@rkarim08/sia 1.0.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 (355) hide show
  1. package/.claude-plugin/marketplace.json +35 -0
  2. package/.claude-plugin/plugin.json +27 -0
  3. package/.mcp.json +13 -0
  4. package/CLAUDE.md +226 -0
  5. package/LICENSE +202 -0
  6. package/PLUGIN_README.md +253 -0
  7. package/README.md +1013 -0
  8. package/agents/sia-changelog-writer.md +89 -0
  9. package/agents/sia-code-reviewer.md +86 -0
  10. package/agents/sia-conflict-resolver.md +100 -0
  11. package/agents/sia-convention-enforcer.md +69 -0
  12. package/agents/sia-debug.md +106 -0
  13. package/agents/sia-decision-reviewer.md +101 -0
  14. package/agents/sia-dependency-tracker.md +80 -0
  15. package/agents/sia-explain.md +126 -0
  16. package/agents/sia-feature.md +116 -0
  17. package/agents/sia-knowledge-capture.md +117 -0
  18. package/agents/sia-lead-architecture-advisor.md +93 -0
  19. package/agents/sia-lead-team-health.md +107 -0
  20. package/agents/sia-migration.md +100 -0
  21. package/agents/sia-onboarding.md +115 -0
  22. package/agents/sia-orientation.md +99 -0
  23. package/agents/sia-pm-briefing.md +106 -0
  24. package/agents/sia-pm-risk-advisor.md +82 -0
  25. package/agents/sia-qa-analyst.md +116 -0
  26. package/agents/sia-qa-regression-map.md +94 -0
  27. package/agents/sia-refactor.md +115 -0
  28. package/agents/sia-regression.md +112 -0
  29. package/agents/sia-security-audit.md +125 -0
  30. package/agents/sia-test-advisor.md +91 -0
  31. package/hooks/hooks.json +98 -0
  32. package/migrations/bridge/001_initial.sql +34 -0
  33. package/migrations/episodic/001_initial.sql +35 -0
  34. package/migrations/meta/001_initial.sql +68 -0
  35. package/migrations/semantic/001_initial.sql +292 -0
  36. package/migrations/semantic/002_ontology.sql +89 -0
  37. package/migrations/semantic/003_freshness.sql +63 -0
  38. package/migrations/semantic/004_v5_unified_schema.sql +194 -0
  39. package/migrations/semantic/005_backfill_event_kinds.sql +8 -0
  40. package/migrations/semantic/006_tree_sitter.sql +6 -0
  41. package/migrations/semantic/007_branch_snapshots.sql +22 -0
  42. package/package.json +110 -0
  43. package/scripts/branch-switch.sh +13 -0
  44. package/scripts/build-wasm-grammars.sh +81 -0
  45. package/scripts/post-compact.sh +8 -0
  46. package/scripts/post-tool-use.sh +10 -0
  47. package/scripts/pre-compact.sh +8 -0
  48. package/scripts/session-end.sh +8 -0
  49. package/scripts/session-start.sh +8 -0
  50. package/scripts/start-mcp.ts +45 -0
  51. package/scripts/stop-hook.sh +8 -0
  52. package/scripts/user-prompt-submit.sh +8 -0
  53. package/scripts/viz-server.ts +152 -0
  54. package/skills/sia-brainstorm/SKILL.md +156 -0
  55. package/skills/sia-brainstorm/scripts/frame-template.html +214 -0
  56. package/skills/sia-brainstorm/scripts/helper.js +95 -0
  57. package/skills/sia-brainstorm/scripts/server.cjs +338 -0
  58. package/skills/sia-brainstorm/scripts/start-server.sh +153 -0
  59. package/skills/sia-brainstorm/scripts/stop-server.sh +55 -0
  60. package/skills/sia-brainstorm/spec-document-reviewer-prompt.md +49 -0
  61. package/skills/sia-brainstorm/visual-companion.md +286 -0
  62. package/skills/sia-capture/SKILL.md +64 -0
  63. package/skills/sia-compare/SKILL.md +33 -0
  64. package/skills/sia-conflicts/SKILL.md +38 -0
  65. package/skills/sia-debug-workflow/SKILL.md +120 -0
  66. package/skills/sia-debug-workflow/root-cause-tracing.md +70 -0
  67. package/skills/sia-debug-workflow/scripts/find-polluter.sh +64 -0
  68. package/skills/sia-debug-workflow/temporal-investigation.md +72 -0
  69. package/skills/sia-digest/SKILL.md +23 -0
  70. package/skills/sia-dispatch/SKILL.md +69 -0
  71. package/skills/sia-dispatch/agent-task-template.md +99 -0
  72. package/skills/sia-doctor/SKILL.md +39 -0
  73. package/skills/sia-execute/SKILL.md +70 -0
  74. package/skills/sia-execute-plan/SKILL.md +85 -0
  75. package/skills/sia-export-import/SKILL.md +49 -0
  76. package/skills/sia-export-knowledge/SKILL.md +46 -0
  77. package/skills/sia-finish/SKILL.md +100 -0
  78. package/skills/sia-finish/pr-summary-template.md +54 -0
  79. package/skills/sia-freshness/SKILL.md +38 -0
  80. package/skills/sia-history/SKILL.md +42 -0
  81. package/skills/sia-impact/SKILL.md +70 -0
  82. package/skills/sia-index/SKILL.md +54 -0
  83. package/skills/sia-install/SKILL.md +39 -0
  84. package/skills/sia-lead-compliance/SKILL.md +16 -0
  85. package/skills/sia-lead-drift-report/SKILL.md +16 -0
  86. package/skills/sia-lead-knowledge-map/SKILL.md +16 -0
  87. package/skills/sia-learn/SKILL.md +58 -0
  88. package/skills/sia-plan/SKILL.md +68 -0
  89. package/skills/sia-plan/plan-reviewer-prompt.md +63 -0
  90. package/skills/sia-playbooks/SKILL.md +29 -0
  91. package/skills/sia-playbooks/reference-feature.md +100 -0
  92. package/skills/sia-playbooks/reference-flagging.md +50 -0
  93. package/skills/sia-playbooks/reference-orientation.md +92 -0
  94. package/skills/sia-playbooks/reference-regression.md +115 -0
  95. package/skills/sia-playbooks/reference-review.md +64 -0
  96. package/skills/sia-playbooks/reference-tools.md +239 -0
  97. package/skills/sia-pm-decision-log/SKILL.md +28 -0
  98. package/skills/sia-pm-risk-dashboard/SKILL.md +24 -0
  99. package/skills/sia-pm-sprint-summary/SKILL.md +27 -0
  100. package/skills/sia-prune/SKILL.md +45 -0
  101. package/skills/sia-qa-coverage/SKILL.md +28 -0
  102. package/skills/sia-qa-flaky/SKILL.md +20 -0
  103. package/skills/sia-qa-report/SKILL.md +26 -0
  104. package/skills/sia-reindex/SKILL.md +30 -0
  105. package/skills/sia-review-respond/SKILL.md +88 -0
  106. package/skills/sia-review-respond/pushback-patterns.md +90 -0
  107. package/skills/sia-search/SKILL.md +47 -0
  108. package/skills/sia-setup/SKILL.md +82 -0
  109. package/skills/sia-setup/setup-checklist.md +97 -0
  110. package/skills/sia-stats/SKILL.md +36 -0
  111. package/skills/sia-status/SKILL.md +44 -0
  112. package/skills/sia-sync/SKILL.md +46 -0
  113. package/skills/sia-team/SKILL.md +64 -0
  114. package/skills/sia-test/SKILL.md +92 -0
  115. package/skills/sia-test/testing-anti-patterns.md +104 -0
  116. package/skills/sia-tour/SKILL.md +29 -0
  117. package/skills/sia-upgrade/SKILL.md +43 -0
  118. package/skills/sia-verify/SKILL.md +81 -0
  119. package/skills/sia-visualize/SKILL.md +28 -0
  120. package/skills/sia-visualize-live/SKILL.md +55 -0
  121. package/skills/sia-visualize-live/scripts/graph-template.html +389 -0
  122. package/skills/sia-visualize-live/scripts/start-visualizer.sh +161 -0
  123. package/skills/sia-visualize-live/scripts/stop-visualizer.sh +55 -0
  124. package/skills/sia-visualize-live/scripts/visualizer-server.cjs +264 -0
  125. package/skills/sia-workspace/SKILL.md +57 -0
  126. package/src/agent/claude-md-template-flagging.md +219 -0
  127. package/src/agent/claude-md-template.md +213 -0
  128. package/src/agent/modules/sia-feature.md +100 -0
  129. package/src/agent/modules/sia-flagging.md +50 -0
  130. package/src/agent/modules/sia-orientation.md +92 -0
  131. package/src/agent/modules/sia-regression.md +115 -0
  132. package/src/agent/modules/sia-review.md +64 -0
  133. package/src/agent/modules/sia-tools.md +239 -0
  134. package/src/ast/extractors/c-include.ts +189 -0
  135. package/src/ast/extractors/csharp-project.ts +260 -0
  136. package/src/ast/extractors/prisma-schema.ts +44 -0
  137. package/src/ast/extractors/project-manifest.ts +111 -0
  138. package/src/ast/extractors/sql-schema.ts +67 -0
  139. package/src/ast/extractors/tier-a.ts +423 -0
  140. package/src/ast/extractors/tier-b.ts +289 -0
  141. package/src/ast/extractors/tier-dispatch.ts +247 -0
  142. package/src/ast/index-worker.ts +108 -0
  143. package/src/ast/indexer.ts +484 -0
  144. package/src/ast/languages.ts +408 -0
  145. package/src/ast/pagerank-builder.ts +125 -0
  146. package/src/ast/path-utils.ts +137 -0
  147. package/src/ast/tree-sitter/backends/native.ts +57 -0
  148. package/src/ast/tree-sitter/backends/wasm.ts +39 -0
  149. package/src/ast/tree-sitter/call-walker.ts +44 -0
  150. package/src/ast/tree-sitter/edit-computer.ts +55 -0
  151. package/src/ast/tree-sitter/query-runner.ts +46 -0
  152. package/src/ast/tree-sitter/service.ts +174 -0
  153. package/src/ast/tree-sitter/tree-cache.ts +39 -0
  154. package/src/ast/tree-sitter/types.ts +79 -0
  155. package/src/ast/watcher.ts +322 -0
  156. package/src/capture/chunker.ts +169 -0
  157. package/src/capture/consolidate.ts +127 -0
  158. package/src/capture/edge-inferrer.ts +161 -0
  159. package/src/capture/embedder.ts +166 -0
  160. package/src/capture/embedding-cache.ts +73 -0
  161. package/src/capture/flag-processor.ts +64 -0
  162. package/src/capture/hook.ts +67 -0
  163. package/src/capture/pipeline.ts +450 -0
  164. package/src/capture/prompts/consolidate.ts +25 -0
  165. package/src/capture/prompts/edge-infer.ts +29 -0
  166. package/src/capture/prompts/extract-flagged.ts +36 -0
  167. package/src/capture/prompts/extract.ts +42 -0
  168. package/src/capture/tokenizer.ts +147 -0
  169. package/src/capture/track-a-ast.ts +93 -0
  170. package/src/capture/track-b-llm.ts +149 -0
  171. package/src/capture/types.ts +64 -0
  172. package/src/cli/commands/community.ts +137 -0
  173. package/src/cli/commands/compare.ts +123 -0
  174. package/src/cli/commands/conflicts.ts +41 -0
  175. package/src/cli/commands/digest.ts +197 -0
  176. package/src/cli/commands/disable-flagging.ts +34 -0
  177. package/src/cli/commands/doctor.ts +240 -0
  178. package/src/cli/commands/download-model.ts +161 -0
  179. package/src/cli/commands/enable-flagging.ts +34 -0
  180. package/src/cli/commands/export-knowledge.ts +208 -0
  181. package/src/cli/commands/export.ts +85 -0
  182. package/src/cli/commands/freshness.ts +164 -0
  183. package/src/cli/commands/graph.ts +51 -0
  184. package/src/cli/commands/history.ts +139 -0
  185. package/src/cli/commands/import.ts +335 -0
  186. package/src/cli/commands/install.ts +156 -0
  187. package/src/cli/commands/lead-report.ts +241 -0
  188. package/src/cli/commands/learn.ts +321 -0
  189. package/src/cli/commands/pm-report.ts +413 -0
  190. package/src/cli/commands/prune.ts +75 -0
  191. package/src/cli/commands/qa-report.ts +278 -0
  192. package/src/cli/commands/reindex.ts +104 -0
  193. package/src/cli/commands/rollback.ts +70 -0
  194. package/src/cli/commands/search.ts +103 -0
  195. package/src/cli/commands/server.ts +91 -0
  196. package/src/cli/commands/share.ts +33 -0
  197. package/src/cli/commands/stats.ts +79 -0
  198. package/src/cli/commands/status.ts +176 -0
  199. package/src/cli/commands/sync.ts +96 -0
  200. package/src/cli/commands/team.ts +118 -0
  201. package/src/cli/commands/tour.ts +157 -0
  202. package/src/cli/commands/visualize-live.ts +162 -0
  203. package/src/cli/commands/workspace.ts +117 -0
  204. package/src/cli/index.ts +424 -0
  205. package/src/cli/learn-progress.ts +87 -0
  206. package/src/community/detection-bridge.ts +344 -0
  207. package/src/community/leiden.ts +462 -0
  208. package/src/community/raptor.ts +210 -0
  209. package/src/community/scheduler.ts +74 -0
  210. package/src/community/summarize.ts +115 -0
  211. package/src/decay/archiver.ts +73 -0
  212. package/src/decay/bridge-orphan-cleanup.ts +212 -0
  213. package/src/decay/consolidation-sweep.ts +112 -0
  214. package/src/decay/decay.ts +116 -0
  215. package/src/decay/deep-validator.ts +62 -0
  216. package/src/decay/episodic-promoter.ts +132 -0
  217. package/src/decay/maintenance-scheduler.ts +326 -0
  218. package/src/decay/scheduler.ts +6 -0
  219. package/src/decay/session-sweeper.ts +79 -0
  220. package/src/decay/types.ts +17 -0
  221. package/src/freshness/confidence-decay.ts +122 -0
  222. package/src/freshness/cuckoo-filter.ts +176 -0
  223. package/src/freshness/deep-validation.ts +345 -0
  224. package/src/freshness/dirty-tracker.ts +237 -0
  225. package/src/freshness/file-watcher-layer.ts +119 -0
  226. package/src/freshness/firewall.ts +64 -0
  227. package/src/freshness/git-reconcile-layer.ts +161 -0
  228. package/src/freshness/inverted-index.ts +158 -0
  229. package/src/freshness/stale-read-layer.ts +222 -0
  230. package/src/graph/audit.ts +69 -0
  231. package/src/graph/bridge-db.ts +141 -0
  232. package/src/graph/communities.ts +195 -0
  233. package/src/graph/db-interface.ts +259 -0
  234. package/src/graph/edges.ts +163 -0
  235. package/src/graph/entities.ts +327 -0
  236. package/src/graph/episodic-db.ts +113 -0
  237. package/src/graph/flags.ts +31 -0
  238. package/src/graph/meta-db.ts +200 -0
  239. package/src/graph/semantic-db.ts +101 -0
  240. package/src/graph/session-resume.ts +56 -0
  241. package/src/graph/snapshots.ts +342 -0
  242. package/src/graph/staging.ts +151 -0
  243. package/src/graph/types.ts +128 -0
  244. package/src/hooks/adapters/claude-code.ts +21 -0
  245. package/src/hooks/adapters/cline.ts +43 -0
  246. package/src/hooks/adapters/cursor.ts +65 -0
  247. package/src/hooks/adapters/generic.ts +12 -0
  248. package/src/hooks/agent-detect.ts +34 -0
  249. package/src/hooks/claude-md-directives.ts +32 -0
  250. package/src/hooks/event-router.ts +182 -0
  251. package/src/hooks/extractors/pattern-detector.ts +111 -0
  252. package/src/hooks/handlers/post-compact.ts +30 -0
  253. package/src/hooks/handlers/post-tool-use.ts +403 -0
  254. package/src/hooks/handlers/pre-compact.ts +100 -0
  255. package/src/hooks/handlers/session-end.ts +47 -0
  256. package/src/hooks/handlers/session-start.ts +154 -0
  257. package/src/hooks/handlers/stop.ts +128 -0
  258. package/src/hooks/handlers/user-prompt-submit.ts +68 -0
  259. package/src/hooks/plugin-branch-switch.ts +68 -0
  260. package/src/hooks/plugin-common.ts +47 -0
  261. package/src/hooks/plugin-post-compact.ts +28 -0
  262. package/src/hooks/plugin-post-tool-use.ts +38 -0
  263. package/src/hooks/plugin-pre-compact.ts +37 -0
  264. package/src/hooks/plugin-session-end.ts +37 -0
  265. package/src/hooks/plugin-session-start.ts +75 -0
  266. package/src/hooks/plugin-stop.ts +61 -0
  267. package/src/hooks/plugin-user-prompt-submit.ts +47 -0
  268. package/src/hooks/types.ts +43 -0
  269. package/src/knowledge/discovery.ts +238 -0
  270. package/src/knowledge/external-refs.ts +98 -0
  271. package/src/knowledge/freshness.ts +221 -0
  272. package/src/knowledge/ingest.ts +330 -0
  273. package/src/knowledge/markdown-export.ts +229 -0
  274. package/src/knowledge/markdown-import.ts +359 -0
  275. package/src/knowledge/patterns.ts +74 -0
  276. package/src/knowledge/templates.ts +307 -0
  277. package/src/llm/ai-sdk-adapter.ts +46 -0
  278. package/src/llm/config.ts +88 -0
  279. package/src/llm/cost-tracker.ts +110 -0
  280. package/src/llm/prompts/extraction.ts +55 -0
  281. package/src/llm/prompts/summarization.ts +36 -0
  282. package/src/llm/prompts/validation.ts +37 -0
  283. package/src/llm/provider-registry.ts +68 -0
  284. package/src/llm/reliability.ts +179 -0
  285. package/src/llm/schemas.ts +52 -0
  286. package/src/mcp/freshness-annotator.ts +69 -0
  287. package/src/mcp/server.ts +949 -0
  288. package/src/mcp/tools/sia-ast-query.ts +225 -0
  289. package/src/mcp/tools/sia-at-time.ts +151 -0
  290. package/src/mcp/tools/sia-backlinks.ts +87 -0
  291. package/src/mcp/tools/sia-batch-execute.ts +169 -0
  292. package/src/mcp/tools/sia-by-file.ts +89 -0
  293. package/src/mcp/tools/sia-community.ts +113 -0
  294. package/src/mcp/tools/sia-doctor.ts +73 -0
  295. package/src/mcp/tools/sia-execute-file.ts +122 -0
  296. package/src/mcp/tools/sia-execute.ts +104 -0
  297. package/src/mcp/tools/sia-expand.ts +158 -0
  298. package/src/mcp/tools/sia-fetch-and-index.ts +241 -0
  299. package/src/mcp/tools/sia-flag.ts +65 -0
  300. package/src/mcp/tools/sia-index.ts +111 -0
  301. package/src/mcp/tools/sia-note.ts +134 -0
  302. package/src/mcp/tools/sia-search.ts +105 -0
  303. package/src/mcp/tools/sia-stats.ts +63 -0
  304. package/src/mcp/tools/sia-sync-status.ts +44 -0
  305. package/src/mcp/tools/sia-upgrade.ts +247 -0
  306. package/src/mcp/truncate.ts +231 -0
  307. package/src/native/bridge.ts +167 -0
  308. package/src/native/fallback-ast-diff.ts +144 -0
  309. package/src/native/fallback-graph.ts +325 -0
  310. package/src/ontology/constraints.ts +56 -0
  311. package/src/ontology/errors.ts +8 -0
  312. package/src/ontology/middleware.ts +266 -0
  313. package/src/retrieval/bm25-search.ts +151 -0
  314. package/src/retrieval/context-assembly.ts +76 -0
  315. package/src/retrieval/graph-traversal.ts +168 -0
  316. package/src/retrieval/pagerank.ts +40 -0
  317. package/src/retrieval/query-classifier.ts +106 -0
  318. package/src/retrieval/reranker.ts +156 -0
  319. package/src/retrieval/search.ts +236 -0
  320. package/src/retrieval/throttle.ts +102 -0
  321. package/src/retrieval/vector-search.ts +203 -0
  322. package/src/retrieval/workspace-search.ts +130 -0
  323. package/src/sandbox/context-mode.ts +285 -0
  324. package/src/sandbox/credential-pass.ts +55 -0
  325. package/src/sandbox/executor.ts +235 -0
  326. package/src/security/pattern-detector.ts +127 -0
  327. package/src/security/rule-of-two.ts +50 -0
  328. package/src/security/sanitize.ts +46 -0
  329. package/src/security/semantic-consistency.ts +93 -0
  330. package/src/security/staging-promoter.ts +154 -0
  331. package/src/shared/config.ts +302 -0
  332. package/src/shared/diagnostics.ts +210 -0
  333. package/src/shared/errors.ts +48 -0
  334. package/src/shared/git-utils.ts +143 -0
  335. package/src/shared/llm-client.ts +120 -0
  336. package/src/shared/logger.ts +99 -0
  337. package/src/shared/types.ts +79 -0
  338. package/src/sync/client.ts +43 -0
  339. package/src/sync/conflict.ts +106 -0
  340. package/src/sync/dedup.ts +183 -0
  341. package/src/sync/hlc.ts +117 -0
  342. package/src/sync/keychain.ts +144 -0
  343. package/src/sync/pull.ts +232 -0
  344. package/src/sync/push.ts +131 -0
  345. package/src/types/chokidar.d.ts +23 -0
  346. package/src/visualization/graph-renderer.ts +312 -0
  347. package/src/visualization/subgraph-extract.ts +208 -0
  348. package/src/visualization/views/community-clusters.ts +246 -0
  349. package/src/visualization/views/dependency-map.ts +189 -0
  350. package/src/visualization/views/graph-explorer.ts +364 -0
  351. package/src/visualization/views/timeline.ts +247 -0
  352. package/src/workspace/api-contracts.ts +226 -0
  353. package/src/workspace/cross-repo.ts +61 -0
  354. package/src/workspace/detector.ts +190 -0
  355. package/src/workspace/manifest.ts +141 -0
@@ -0,0 +1,41 @@
1
+ // Module: conflicts — conflict listing and resolution
2
+
3
+ import type { SiaDb } from "@/graph/db-interface";
4
+ import { invalidateEntity } from "@/graph/entities";
5
+
6
+ export async function listConflicts(db: SiaDb): Promise<Record<string, string[]>> {
7
+ const rows = await db.execute(
8
+ "SELECT conflict_group_id, id FROM graph_nodes WHERE conflict_group_id IS NOT NULL AND archived_at IS NULL AND t_valid_until IS NULL",
9
+ );
10
+ const groups: Record<string, string[]> = {};
11
+ for (const row of rows.rows as Array<{ conflict_group_id: string; id: string }>) {
12
+ if (!groups[row.conflict_group_id]) groups[row.conflict_group_id] = [];
13
+ groups[row.conflict_group_id].push(row.id);
14
+ }
15
+ return groups;
16
+ }
17
+
18
+ export async function resolveConflict(
19
+ db: SiaDb,
20
+ groupId: string,
21
+ keepEntityId: string,
22
+ ): Promise<void> {
23
+ const keepRow = await db.execute(
24
+ "SELECT id FROM graph_nodes WHERE id = ? AND conflict_group_id = ?",
25
+ [keepEntityId, groupId],
26
+ );
27
+ if (keepRow.rows.length === 0) {
28
+ throw new Error(`Entity '${keepEntityId}' not found in conflict group '${groupId}'`);
29
+ }
30
+
31
+ const rows = await db.execute("SELECT id FROM graph_nodes WHERE conflict_group_id = ?", [
32
+ groupId,
33
+ ]);
34
+ for (const row of rows.rows as Array<{ id: string }>) {
35
+ if (row.id === keepEntityId) continue;
36
+ await invalidateEntity(db, row.id);
37
+ }
38
+ await db.execute("UPDATE graph_nodes SET conflict_group_id = NULL WHERE conflict_group_id = ?", [
39
+ groupId,
40
+ ]);
41
+ }
@@ -0,0 +1,197 @@
1
+ // Module: digest — Knowledge digest generator for graph activity summaries
2
+
3
+ import type { SiaDb } from "@/graph/db-interface";
4
+
5
+ export type DigestPeriod = "daily" | "weekly" | "monthly" | "custom";
6
+
7
+ export interface DigestOpts {
8
+ period?: DigestPeriod;
9
+ startDate?: number; // Unix ms
10
+ endDate?: number; // Unix ms
11
+ }
12
+
13
+ export interface DigestSection {
14
+ title: string;
15
+ items: DigestItem[];
16
+ }
17
+
18
+ export interface DigestItem {
19
+ id: string;
20
+ name: string;
21
+ type: string;
22
+ summary: string;
23
+ created_at: number;
24
+ }
25
+
26
+ export interface DigestResult {
27
+ period: DigestPeriod;
28
+ startDate: number;
29
+ endDate: number;
30
+ sections: DigestSection[];
31
+ totalEntities: number;
32
+ }
33
+
34
+ /** Map entity type to human-readable section title. */
35
+ const TYPE_TITLES: Record<string, string> = {
36
+ Decision: "Decisions Captured",
37
+ Convention: "Conventions Established",
38
+ Bug: "Bugs Identified",
39
+ Solution: "Solutions Found",
40
+ Concept: "Concepts Added",
41
+ FileNode: "Files Indexed",
42
+ ContentChunk: "Documentation Chunks",
43
+ };
44
+
45
+ /** Ordered list of types so sections appear in a stable order. */
46
+ const TYPE_ORDER: string[] = [
47
+ "Decision",
48
+ "Convention",
49
+ "Bug",
50
+ "Solution",
51
+ "Concept",
52
+ "FileNode",
53
+ "ContentChunk",
54
+ ];
55
+
56
+ const MS_PER_DAY = 86_400_000;
57
+
58
+ /**
59
+ * Compute the start/end timestamps for a named period.
60
+ * "custom" requires explicit startDate/endDate in opts.
61
+ */
62
+ function resolveTimeRange(opts?: DigestOpts): {
63
+ period: DigestPeriod;
64
+ startDate: number;
65
+ endDate: number;
66
+ } {
67
+ const now = Date.now();
68
+ const period = opts?.period ?? "weekly";
69
+ const endDate = opts?.endDate ?? now;
70
+
71
+ if (period === "custom") {
72
+ if (opts?.startDate == null || opts?.endDate == null) {
73
+ throw new Error("Custom period requires both startDate and endDate");
74
+ }
75
+ return { period, startDate: opts.startDate, endDate: opts.endDate };
76
+ }
77
+
78
+ let startDate: number;
79
+ switch (period) {
80
+ case "daily":
81
+ startDate = endDate - MS_PER_DAY;
82
+ break;
83
+ case "monthly":
84
+ startDate = endDate - 30 * MS_PER_DAY;
85
+ break;
86
+ default:
87
+ startDate = endDate - 7 * MS_PER_DAY;
88
+ break;
89
+ }
90
+
91
+ return { period, startDate, endDate };
92
+ }
93
+
94
+ /**
95
+ * Generate a knowledge digest for the specified time period.
96
+ * Queries the graph for entities created within the period, grouped by type.
97
+ */
98
+ export async function generateDigest(db: SiaDb, opts?: DigestOpts): Promise<DigestResult> {
99
+ const { period, startDate, endDate } = resolveTimeRange(opts);
100
+
101
+ const { rows } = await db.execute(
102
+ `SELECT id, type, name, summary, created_at FROM graph_nodes
103
+ WHERE created_at >= ? AND created_at <= ?
104
+ AND t_valid_until IS NULL AND archived_at IS NULL
105
+ ORDER BY type, importance DESC`,
106
+ [startDate, endDate],
107
+ );
108
+
109
+ // Group rows by type
110
+ const grouped = new Map<string, DigestItem[]>();
111
+ for (const row of rows) {
112
+ const type = row.type as string;
113
+ const item: DigestItem = {
114
+ id: row.id as string,
115
+ name: row.name as string,
116
+ type,
117
+ summary: row.summary as string,
118
+ created_at: row.created_at as number,
119
+ };
120
+ const list = grouped.get(type);
121
+ if (list) {
122
+ list.push(item);
123
+ } else {
124
+ grouped.set(type, [item]);
125
+ }
126
+ }
127
+
128
+ // Build sections in stable order, only including non-empty ones
129
+ const sections: DigestSection[] = [];
130
+ for (const type of TYPE_ORDER) {
131
+ const items = grouped.get(type);
132
+ if (items && items.length > 0) {
133
+ sections.push({
134
+ title: TYPE_TITLES[type] ?? type,
135
+ items,
136
+ });
137
+ }
138
+ }
139
+
140
+ // Include any types not in TYPE_ORDER (future entity types)
141
+ for (const [type, items] of grouped) {
142
+ if (!TYPE_ORDER.includes(type) && items.length > 0) {
143
+ sections.push({
144
+ title: TYPE_TITLES[type] ?? type,
145
+ items,
146
+ });
147
+ }
148
+ }
149
+
150
+ const totalEntities = rows.length;
151
+
152
+ return {
153
+ period,
154
+ startDate,
155
+ endDate,
156
+ sections,
157
+ totalEntities,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Format a Unix-ms timestamp as an ISO date string (date portion only).
163
+ */
164
+ function formatDate(ms: number): string {
165
+ return new Date(ms).toISOString().slice(0, 10);
166
+ }
167
+
168
+ /**
169
+ * Render a digest as markdown text.
170
+ */
171
+ export function renderDigestMarkdown(digest: DigestResult): string {
172
+ const lines: string[] = [];
173
+
174
+ lines.push(`# Knowledge Digest — ${digest.period}`);
175
+ lines.push("");
176
+ lines.push(`**Period:** ${formatDate(digest.startDate)} to ${formatDate(digest.endDate)}`);
177
+ lines.push("");
178
+ lines.push(`**Total new entities:** ${digest.totalEntities}`);
179
+
180
+ for (const section of digest.sections) {
181
+ const items = section.items.slice(0, 10);
182
+ lines.push("");
183
+ lines.push(`## ${section.title} (${section.items.length})`);
184
+ lines.push("");
185
+ lines.push("| Name | Summary |");
186
+ lines.push("|------|---------|");
187
+ for (const item of items) {
188
+ // Escape pipes in name/summary to avoid breaking the table
189
+ const name = item.name.replace(/\|/g, "\\|");
190
+ const summary = item.summary.replace(/\|/g, "\\|");
191
+ lines.push(`| ${name} | ${summary} |`);
192
+ }
193
+ }
194
+
195
+ lines.push("");
196
+ return lines.join("\n");
197
+ }
@@ -0,0 +1,34 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { getConfig, writeConfig } from "@/shared/config";
4
+
5
+ /**
6
+ * Disable the sia_flag capture pathway.
7
+ *
8
+ * 1. Persists `enableFlagging: false` in config.
9
+ * 2. Swaps the installed CLAUDE.md back to the base template
10
+ * (Step 4 reverts to the conditional check).
11
+ *
12
+ * Idempotent — running twice is a no-op.
13
+ */
14
+ export async function disableFlagging(opts?: { siaHome?: string; cwd?: string }): Promise<void> {
15
+ const config = getConfig(opts?.siaHome);
16
+
17
+ if (config.enableFlagging === false) {
18
+ return;
19
+ }
20
+
21
+ writeConfig({ enableFlagging: false }, opts?.siaHome);
22
+
23
+ // Resolve the base template relative to *this* file's directory.
24
+ const templatePath = resolve(import.meta.dirname, "../../agent/claude-md-template.md");
25
+ const template = readFileSync(templatePath, "utf-8");
26
+
27
+ const cwd = opts?.cwd ?? process.cwd();
28
+ const claudeDir = join(cwd, ".claude");
29
+ mkdirSync(claudeDir, { recursive: true });
30
+
31
+ writeFileSync(join(claudeDir, "CLAUDE.md"), template, "utf-8");
32
+
33
+ console.log("Flagging disabled. CLAUDE.md restored to base template.");
34
+ }
@@ -0,0 +1,240 @@
1
+ // Module: doctor — System health check with hook + provider diagnostics
2
+ //
3
+ // `npx sia doctor` reports overall system health.
4
+ // `npx sia doctor --providers` adds LLM provider connectivity checks.
5
+ //
6
+ // Checks: runtimes, hooks, capture mode, FTS5, ONNX model, native module,
7
+ // community detection backend, graph integrity, inverted dependency index,
8
+ // and (optionally) LLM provider health.
9
+
10
+ import { existsSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import type { SiaDb } from "@/graph/db-interface";
13
+ import { detectAgent, getRecommendedCaptureMode } from "@/hooks/agent-detect";
14
+ import { getHookConfig } from "@/hooks/event-router";
15
+ import { getDefaultLlmConfig } from "@/llm/config";
16
+ import type { OperationRole } from "@/llm/provider-registry";
17
+ import { isNativeAvailable } from "@/native/bridge";
18
+
19
+ export interface DoctorCheck {
20
+ name: string;
21
+ status: "ok" | "warn" | "error";
22
+ message: string;
23
+ }
24
+
25
+ export interface DoctorReport {
26
+ checks: DoctorCheck[];
27
+ captureMode: string;
28
+ agent: string;
29
+ nativeModule: string;
30
+ communityBackend: string;
31
+ hookHealth: Array<{ event: string; type: string; status: string }>;
32
+ providerHealth: Array<{
33
+ role: string;
34
+ provider: string;
35
+ model: string;
36
+ status: string;
37
+ }>;
38
+ }
39
+
40
+ /**
41
+ * Run the full doctor diagnostic suite.
42
+ */
43
+ export async function runDoctor(
44
+ db: SiaDb | null,
45
+ cwd: string,
46
+ options?: { providers?: boolean },
47
+ ): Promise<DoctorReport> {
48
+ const checks: DoctorCheck[] = [];
49
+
50
+ // 1. Detect agent
51
+ const agent = detectAgent(cwd);
52
+ const captureMode = getRecommendedCaptureMode(agent);
53
+ checks.push({
54
+ name: "Agent detection",
55
+ status: "ok",
56
+ message: `Detected: ${agent} (capture mode: ${captureMode})`,
57
+ });
58
+
59
+ // 2. Native module
60
+ const nativeStatus = isNativeAvailable();
61
+ checks.push({
62
+ name: "Native module",
63
+ status: nativeStatus === "typescript" ? "warn" : "ok",
64
+ message:
65
+ nativeStatus === "typescript"
66
+ ? "Using TypeScript fallbacks (install @sia/native for 5-20x faster AST diffing)"
67
+ : `Loaded: ${nativeStatus}`,
68
+ });
69
+
70
+ // 3. Community detection backend
71
+ const communityBackend =
72
+ nativeStatus !== "typescript" ? "Rust Leiden via graphrs" : "JavaScript Louvain (in-process)";
73
+ checks.push({
74
+ name: "Community detection",
75
+ status: "ok",
76
+ message: communityBackend,
77
+ });
78
+
79
+ // 4. ONNX model
80
+ const modelPath = join(
81
+ process.env.SIA_HOME ?? join(process.env.HOME ?? "~", ".sia"),
82
+ "models",
83
+ "all-MiniLM-L6-v2.onnx",
84
+ );
85
+ const modelExists = existsSync(modelPath);
86
+ checks.push({
87
+ name: "ONNX embedding model",
88
+ status: modelExists ? "ok" : "warn",
89
+ message: modelExists
90
+ ? `Found at ${modelPath}`
91
+ : `Not found at ${modelPath} — run npx sia download-model`,
92
+ });
93
+
94
+ // 5. Graph integrity (if DB available)
95
+ if (db) {
96
+ try {
97
+ const { rows: entityCount } = await db.execute("SELECT COUNT(*) as cnt FROM graph_nodes", []);
98
+ const { rows: edgeCount } = await db.execute("SELECT COUNT(*) as cnt FROM graph_edges", []);
99
+ const entities = (entityCount[0] as { cnt: number }).cnt;
100
+ const edges = (edgeCount[0] as { cnt: number }).cnt;
101
+ checks.push({
102
+ name: "Graph integrity",
103
+ status: "ok",
104
+ message: `${entities} entities, ${edges} edges`,
105
+ });
106
+
107
+ // Check for orphan edges
108
+ const { rows: orphans } = await db.execute(
109
+ `SELECT COUNT(*) as cnt FROM graph_edges e
110
+ WHERE NOT EXISTS (SELECT 1 FROM graph_nodes WHERE id = e.from_id)
111
+ OR NOT EXISTS (SELECT 1 FROM graph_nodes WHERE id = e.to_id)`,
112
+ [],
113
+ );
114
+ const orphanCount = (orphans[0] as { cnt: number }).cnt;
115
+ if (orphanCount > 0) {
116
+ checks.push({
117
+ name: "Orphan edges",
118
+ status: "warn",
119
+ message: `${orphanCount} edges reference non-existent entities`,
120
+ });
121
+ }
122
+
123
+ // Check FTS5
124
+ try {
125
+ await db.execute("SELECT COUNT(*) FROM graph_nodes_fts", []);
126
+ checks.push({ name: "FTS5 index", status: "ok", message: "Operational" });
127
+ } catch {
128
+ checks.push({ name: "FTS5 index", status: "error", message: "Not available" });
129
+ }
130
+
131
+ // Check source_deps (inverted index)
132
+ try {
133
+ const { rows: depCount } = await db.execute("SELECT COUNT(*) as cnt FROM source_deps", []);
134
+ const deps = (depCount[0] as { cnt: number }).cnt;
135
+ checks.push({
136
+ name: "Inverted dependency index",
137
+ status: deps > 0 ? "ok" : "warn",
138
+ message: `${deps} source-to-node mappings`,
139
+ });
140
+ } catch {
141
+ checks.push({
142
+ name: "Inverted dependency index",
143
+ status: "warn",
144
+ message: "source_deps table not found — run npx sia reindex",
145
+ });
146
+ }
147
+ } catch (err) {
148
+ checks.push({
149
+ name: "Graph integrity",
150
+ status: "error",
151
+ message: `Failed to query graph: ${err instanceof Error ? err.message : String(err)}`,
152
+ });
153
+ }
154
+ }
155
+
156
+ // 6. Hook health
157
+ const hookConfig = getHookConfig();
158
+ const hookHealth = Object.entries(hookConfig).map(([event, configs]) => {
159
+ const config = configs[0] as Record<string, unknown>;
160
+ const type = config.type as string;
161
+ // We can't actually test HTTP connectivity here without the server running,
162
+ // so we report the configuration status
163
+ return {
164
+ event,
165
+ type,
166
+ status:
167
+ type === "command"
168
+ ? "configured (command)"
169
+ : `configured (${config.async ? "async" : "sync"})`,
170
+ };
171
+ });
172
+
173
+ // 7. Provider health (only if --providers flag)
174
+ const providerHealth: DoctorReport["providerHealth"] = [];
175
+ if (options?.providers) {
176
+ const config = getDefaultLlmConfig();
177
+ const roles: OperationRole[] = ["summarize", "validate", "extract", "consolidate"];
178
+
179
+ for (const role of roles) {
180
+ const providerConfig = config.providers[role];
181
+ const isStandby = captureMode === "hooks" && (role === "extract" || role === "consolidate");
182
+
183
+ providerHealth.push({
184
+ role,
185
+ provider: providerConfig?.provider ?? "not configured",
186
+ model: providerConfig?.model ?? "not configured",
187
+ status: isStandby ? "standby (hooks active)" : "configured",
188
+ });
189
+ }
190
+ }
191
+
192
+ return {
193
+ checks,
194
+ captureMode,
195
+ agent,
196
+ nativeModule: nativeStatus,
197
+ communityBackend,
198
+ hookHealth,
199
+ providerHealth,
200
+ };
201
+ }
202
+
203
+ /**
204
+ * Format the doctor report as human-readable output.
205
+ */
206
+ export function formatDoctorReport(report: DoctorReport): string {
207
+ const lines: string[] = [];
208
+
209
+ lines.push("Sia Doctor Report");
210
+ lines.push("═".repeat(50));
211
+ lines.push(`Capture Mode: ${report.captureMode} (${report.agent} detected)`);
212
+ lines.push("");
213
+
214
+ // Checks
215
+ for (const check of report.checks) {
216
+ const icon = check.status === "ok" ? "✓" : check.status === "warn" ? "⚠" : "✗";
217
+ lines.push(` ${icon} ${check.name}: ${check.message}`);
218
+ }
219
+
220
+ // Hook configuration
221
+ lines.push("");
222
+ lines.push("Hook Configuration:");
223
+ for (const hook of report.hookHealth) {
224
+ lines.push(` ✓ ${hook.event}: ${hook.status}`);
225
+ }
226
+
227
+ // Provider health (if checked)
228
+ if (report.providerHealth.length > 0) {
229
+ lines.push("");
230
+ lines.push("LLM Providers:");
231
+ for (const provider of report.providerHealth) {
232
+ const icon = provider.status.includes("standby") ? "⚡" : "✓";
233
+ lines.push(
234
+ ` ${icon} ${provider.role}: ${provider.provider} / ${provider.model} — ${provider.status}`,
235
+ );
236
+ }
237
+ }
238
+
239
+ return lines.join("\n");
240
+ }
@@ -0,0 +1,161 @@
1
+ // Module: download-model — downloads the all-MiniLM-L6-v2 ONNX model and tokenizer
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ existsSync,
5
+ mkdirSync,
6
+ readFileSync,
7
+ renameSync,
8
+ statSync,
9
+ unlinkSync,
10
+ writeFileSync,
11
+ } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { SIA_HOME } from "@/shared/config";
14
+
15
+ const MODEL_URL =
16
+ "https://huggingface.co/Xenova/all-MiniLM-L6-v2/resolve/main/onnx/model_quantized.onnx";
17
+ const TOKENIZER_URL = "https://huggingface.co/Xenova/all-MiniLM-L6-v2/resolve/main/tokenizer.json";
18
+
19
+ const MODEL_FILENAME = "all-MiniLM-L6-v2.onnx";
20
+ const TOKENIZER_FILENAME = "tokenizer.json";
21
+
22
+ /**
23
+ * Download a single file from `url` to `destPath`.
24
+ * Writes to a temporary file first, then renames to the final destination.
25
+ */
26
+ async function downloadFile(url: string, destPath: string): Promise<void> {
27
+ const response = await fetch(url);
28
+ if (!response.ok) {
29
+ throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
30
+ }
31
+
32
+ const contentLength = Number(response.headers.get("content-length") ?? 0);
33
+ const reader = response.body?.getReader();
34
+ if (!reader) {
35
+ throw new Error(`No response body for ${url}`);
36
+ }
37
+
38
+ const chunks: Uint8Array[] = [];
39
+ let received = 0;
40
+ let lastPercent = -1;
41
+
42
+ while (true) {
43
+ const { done, value } = await reader.read();
44
+ if (done) break;
45
+ chunks.push(value);
46
+ received += value.length;
47
+
48
+ if (contentLength > 0) {
49
+ const percent = Math.floor((received / contentLength) * 100);
50
+ if (percent !== lastPercent && percent % 10 === 0) {
51
+ console.log(`Downloading ${destPath}... ${percent}%`);
52
+ lastPercent = percent;
53
+ }
54
+ }
55
+ }
56
+
57
+ // Concatenate chunks into a single buffer
58
+ const buffer = new Uint8Array(received);
59
+ let offset = 0;
60
+ for (const chunk of chunks) {
61
+ buffer.set(chunk, offset);
62
+ offset += chunk.length;
63
+ }
64
+
65
+ // Write to temp file first, then rename for atomicity
66
+ const tempPath = `${destPath}.tmp`;
67
+ writeFileSync(tempPath, buffer);
68
+ renameSync(tempPath, destPath);
69
+
70
+ console.log(`Downloaded ${destPath} (${received} bytes)`);
71
+ }
72
+
73
+ /**
74
+ * Verify the SHA-256 checksum of a file against an expected hash.
75
+ *
76
+ * If the hashes match, returns without error.
77
+ * If the hashes do not match, deletes the file and throws an error.
78
+ *
79
+ * @param filePath Path to the file to verify.
80
+ * @param expectedHash Hex-encoded SHA-256 digest to compare against.
81
+ */
82
+ export function verifyModelChecksum(filePath: string, expectedHash: string): void {
83
+ const fileBuffer = readFileSync(filePath);
84
+ const actualHash = createHash("sha256").update(fileBuffer).digest("hex");
85
+ if (actualHash !== expectedHash) {
86
+ unlinkSync(filePath);
87
+ throw new Error(
88
+ `Checksum mismatch for ${filePath}: expected ${expectedHash}, got ${actualHash}`,
89
+ );
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Check whether a file exists and has size > 0.
95
+ */
96
+ function fileExistsWithContent(filePath: string): boolean {
97
+ if (!existsSync(filePath)) return false;
98
+ const stats = statSync(filePath);
99
+ return stats.size > 0;
100
+ }
101
+
102
+ /**
103
+ * Download the all-MiniLM-L6-v2 ONNX model and its tokenizer.
104
+ *
105
+ * Files are saved to `{siaHome}/models/`.
106
+ * If both files already exist with size > 0, the download is skipped.
107
+ *
108
+ * @returns The path to the downloaded model file.
109
+ */
110
+ export async function downloadModel(siaHome: string = SIA_HOME): Promise<string> {
111
+ const modelsDir = join(siaHome, "models");
112
+ const modelPath = join(modelsDir, MODEL_FILENAME);
113
+ const tokenizerPath = join(modelsDir, TOKENIZER_FILENAME);
114
+
115
+ // Ensure models directory exists
116
+ if (!existsSync(modelsDir)) {
117
+ mkdirSync(modelsDir, { recursive: true });
118
+ }
119
+
120
+ // Check if model already exists
121
+ if (fileExistsWithContent(modelPath) && fileExistsWithContent(tokenizerPath)) {
122
+ console.log("Model already downloaded");
123
+ return modelPath;
124
+ }
125
+
126
+ // Download model if needed
127
+ if (!fileExistsWithContent(modelPath)) {
128
+ console.log("Downloading ONNX model...");
129
+ await downloadFile(MODEL_URL, modelPath);
130
+ // TODO: Replace placeholder with the real SHA-256 hash from the HuggingFace model card:
131
+ // https://huggingface.co/Xenova/all-MiniLM-L6-v2/blob/main/onnx/model_quantized.onnx
132
+ const MODEL_EXPECTED_HASH = "CHECKSUM_NOT_YET_KNOWN";
133
+ if (MODEL_EXPECTED_HASH !== "CHECKSUM_NOT_YET_KNOWN") {
134
+ verifyModelChecksum(modelPath, MODEL_EXPECTED_HASH);
135
+ } else {
136
+ console.warn(
137
+ "[warn] Model checksum not configured — skipping integrity verification. " +
138
+ "Set the real SHA-256 hash in download-model.ts to enable verification.",
139
+ );
140
+ }
141
+ }
142
+
143
+ // Download tokenizer if needed
144
+ if (!fileExistsWithContent(tokenizerPath)) {
145
+ console.log("Downloading tokenizer...");
146
+ await downloadFile(TOKENIZER_URL, tokenizerPath);
147
+ // TODO: Replace placeholder with the real SHA-256 hash from the HuggingFace model card:
148
+ // https://huggingface.co/Xenova/all-MiniLM-L6-v2/blob/main/tokenizer.json
149
+ const TOKENIZER_EXPECTED_HASH = "CHECKSUM_NOT_YET_KNOWN";
150
+ if (TOKENIZER_EXPECTED_HASH !== "CHECKSUM_NOT_YET_KNOWN") {
151
+ verifyModelChecksum(tokenizerPath, TOKENIZER_EXPECTED_HASH);
152
+ } else {
153
+ console.warn(
154
+ "[warn] Tokenizer checksum not configured — skipping integrity verification. " +
155
+ "Set the real SHA-256 hash in download-model.ts to enable verification.",
156
+ );
157
+ }
158
+ }
159
+
160
+ return modelPath;
161
+ }
@@ -0,0 +1,34 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { getConfig, writeConfig } from "@/shared/config";
4
+
5
+ /**
6
+ * Enable the sia_flag capture pathway.
7
+ *
8
+ * 1. Persists `enableFlagging: true` in config.
9
+ * 2. Swaps the installed CLAUDE.md to the flagging-enabled template
10
+ * (contains the expanded sia_flag section in Step 4).
11
+ *
12
+ * Idempotent — running twice is a no-op.
13
+ */
14
+ export async function enableFlagging(opts?: { siaHome?: string; cwd?: string }): Promise<void> {
15
+ const config = getConfig(opts?.siaHome);
16
+
17
+ if (config.enableFlagging === true) {
18
+ return;
19
+ }
20
+
21
+ writeConfig({ enableFlagging: true }, opts?.siaHome);
22
+
23
+ // Resolve the flagging template relative to *this* file's directory.
24
+ const templatePath = resolve(import.meta.dirname, "../../agent/claude-md-template-flagging.md");
25
+ const template = readFileSync(templatePath, "utf-8");
26
+
27
+ const cwd = opts?.cwd ?? process.cwd();
28
+ const claudeDir = join(cwd, ".claude");
29
+ mkdirSync(claudeDir, { recursive: true });
30
+
31
+ writeFileSync(join(claudeDir, "CLAUDE.md"), template, "utf-8");
32
+
33
+ console.log("Flagging enabled. CLAUDE.md updated with sia_flag section.");
34
+ }