mednotes-opencode 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 (430) hide show
  1. package/.opencode/agents/med-chat-triager.md +204 -0
  2. package/.opencode/agents/med-flashcard-maker.md +63 -0
  3. package/.opencode/agents/med-knowledge-architect.md +230 -0
  4. package/.opencode/agents/med-link-graph-curator.md +177 -0
  5. package/.opencode/agents/med-publish-guard.md +62 -0
  6. package/.opencode/commands/flashcards.md +25 -0
  7. package/.opencode/commands/mednotes/create.md +25 -0
  8. package/.opencode/commands/mednotes/enrich.md +27 -0
  9. package/.opencode/commands/mednotes/fix-wiki.md +27 -0
  10. package/.opencode/commands/mednotes/history.md +22 -0
  11. package/.opencode/commands/mednotes/link-body.md +25 -0
  12. package/.opencode/commands/mednotes/link-related.md +27 -0
  13. package/.opencode/commands/mednotes/link.md +27 -0
  14. package/.opencode/commands/mednotes/pdf-library.md +27 -0
  15. package/.opencode/commands/mednotes/process-chats.md +23 -0
  16. package/.opencode/commands/mednotes/setup.md +21 -0
  17. package/.opencode/commands/mednotes/status.md +27 -0
  18. package/.opencode/commands/mednotes/telemetry.md +27 -0
  19. package/.opencode/commands/report.md +26 -0
  20. package/.opencode/mednotes/AGENTS.md +57 -0
  21. package/.opencode/mednotes/agents/med-chat-triager.md +197 -0
  22. package/.opencode/mednotes/agents/med-flashcard-maker.md +56 -0
  23. package/.opencode/mednotes/agents/med-knowledge-architect.md +224 -0
  24. package/.opencode/mednotes/agents/med-link-graph-curator.md +171 -0
  25. package/.opencode/mednotes/agents/med-publish-guard.md +55 -0
  26. package/.opencode/mednotes/contracts/.gitkeep +1 -0
  27. package/.opencode/mednotes/contracts/agents.json +116 -0
  28. package/.opencode/mednotes/contracts/opencode-plugin.json +70 -0
  29. package/.opencode/mednotes/docs/agent-prompt-hardening.md +567 -0
  30. package/.opencode/mednotes/docs/agent-role-contracts.md +94 -0
  31. package/.opencode/mednotes/docs/anki-mcp-twenty-rules.md +214 -0
  32. package/.opencode/mednotes/docs/anki-templates/README.md +39 -0
  33. package/.opencode/mednotes/docs/anki-templates/cloze.back.html +23 -0
  34. package/.opencode/mednotes/docs/anki-templates/cloze.front.html +14 -0
  35. package/.opencode/mednotes/docs/anki-templates/qa.back.html +24 -0
  36. package/.opencode/mednotes/docs/anki-templates/qa.front.html +14 -0
  37. package/.opencode/mednotes/docs/anki-templates/style.css +182 -0
  38. package/.opencode/mednotes/docs/atomicity-splitting-policy.md +113 -0
  39. package/.opencode/mednotes/docs/extension-docs.md +40 -0
  40. package/.opencode/mednotes/docs/flashcard-ingestion.md +278 -0
  41. package/.opencode/mednotes/docs/knowledge-architect.md +208 -0
  42. package/.opencode/mednotes/docs/merge-policy.md +110 -0
  43. package/.opencode/mednotes/docs/public-vocabulary.md +104 -0
  44. package/.opencode/mednotes/docs/semantic-linker.md +141 -0
  45. package/.opencode/mednotes/docs/taxonomy-policy.md +90 -0
  46. package/.opencode/mednotes/docs/triage-policy.md +187 -0
  47. package/.opencode/mednotes/docs/vault-version-control.md +758 -0
  48. package/.opencode/mednotes/docs/vocabulary-db-recovery.md +58 -0
  49. package/.opencode/mednotes/docs/workflow-output-contract.md +779 -0
  50. package/.opencode/mednotes/hooks/hooks.json +79 -0
  51. package/.opencode/mednotes/package-lock.json +6361 -0
  52. package/.opencode/mednotes/package.json +15 -0
  53. package/.opencode/mednotes/pyproject.toml +48 -0
  54. package/.opencode/mednotes/scripts/bootstrap_windows_python_uv.cmd +13 -0
  55. package/.opencode/mednotes/scripts/bootstrap_windows_python_uv.ps1 +172 -0
  56. package/.opencode/mednotes/scripts/enrich_notes.py +23 -0
  57. package/.opencode/mednotes/scripts/full_reset_windows_python_uv.cmd +13 -0
  58. package/.opencode/mednotes/scripts/hooks/antigravity_hook_status.mjs +212 -0
  59. package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/antigravity.mjs +169 -0
  60. package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/harness_payload.mjs +103 -0
  61. package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/opencode_plugin.mjs +341 -0
  62. package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/opencode_user_config_sync.mjs +177 -0
  63. package/.opencode/mednotes/scripts/hooks/mednotes_hook/anki_preflight.mjs +214 -0
  64. package/.opencode/mednotes/scripts/hooks/mednotes_hook/cli.mjs +143 -0
  65. package/.opencode/mednotes/scripts/hooks/mednotes_hook/diagnostics.mjs +11 -0
  66. package/.opencode/mednotes/scripts/hooks/mednotes_hook/domain/agent_directive_core.mjs +160 -0
  67. package/.opencode/mednotes/scripts/hooks/mednotes_hook/fsm_directive.mjs +1470 -0
  68. package/.opencode/mednotes/scripts/hooks/mednotes_hook/hook_errors.mjs +120 -0
  69. package/.opencode/mednotes/scripts/hooks/mednotes_hook/retention.mjs +114 -0
  70. package/.opencode/mednotes/scripts/hooks/mednotes_hook/runtime.mjs +174 -0
  71. package/.opencode/mednotes/scripts/hooks/mednotes_hook/telemetry_capture.mjs +511 -0
  72. package/.opencode/mednotes/scripts/hooks/mednotes_hook/vault_guard.mjs +624 -0
  73. package/.opencode/mednotes/scripts/hooks/mednotes_hook.mjs +5 -0
  74. package/.opencode/mednotes/scripts/mednotes/_runtime_paths.py +24 -0
  75. package/.opencode/mednotes/scripts/mednotes/anki_model_validator.py +18 -0
  76. package/.opencode/mednotes/scripts/mednotes/capture_extension_diff.py +1562 -0
  77. package/.opencode/mednotes/scripts/mednotes/feedback_report.py +16 -0
  78. package/.opencode/mednotes/scripts/mednotes/flashcard_index.py +18 -0
  79. package/.opencode/mednotes/scripts/mednotes/flashcard_pipeline.py +18 -0
  80. package/.opencode/mednotes/scripts/mednotes/flashcard_report.py +18 -0
  81. package/.opencode/mednotes/scripts/mednotes/flashcard_sources.py +18 -0
  82. package/.opencode/mednotes/scripts/mednotes/obsidian/README.md +6 -0
  83. package/.opencode/mednotes/scripts/mednotes/obsidian_note_utils.py +20 -0
  84. package/.opencode/mednotes/scripts/mednotes/pdf_library/cli.py +16 -0
  85. package/.opencode/mednotes/scripts/mednotes/project_fsm.py +229 -0
  86. package/.opencode/mednotes/scripts/mednotes/setup_telemetry_email.py +404 -0
  87. package/.opencode/mednotes/scripts/mednotes/sync_anki_twenty_rules.py +18 -0
  88. package/.opencode/mednotes/scripts/mednotes/sync_opencode_user_config.py +36 -0
  89. package/.opencode/mednotes/scripts/mednotes/wiki/cli.py +20 -0
  90. package/.opencode/mednotes/scripts/mednotes/wiki_graph.py +18 -0
  91. package/.opencode/mednotes/scripts/mednotes/wiki_tree.py +134 -0
  92. package/.opencode/mednotes/scripts/reset_windows_python_uv.ps1 +625 -0
  93. package/.opencode/mednotes/scripts/run_python.mjs +109 -0
  94. package/.opencode/mednotes/scripts/vault/vault_commit.ps1 +19 -0
  95. package/.opencode/mednotes/scripts/vault/vault_commit.sh +18 -0
  96. package/.opencode/mednotes/scripts/vault/vault_git.ps1 +19 -0
  97. package/.opencode/mednotes/scripts/vault/vault_git.py +3107 -0
  98. package/.opencode/mednotes/scripts/vault/vault_git.sh +18 -0
  99. package/.opencode/mednotes/scripts/vault/vault_precommit.ps1 +19 -0
  100. package/.opencode/mednotes/scripts/vault/vault_precommit.sh +18 -0
  101. package/.opencode/mednotes/skills/THIRD_PARTY_NOTICES.md +45 -0
  102. package/.opencode/mednotes/skills/create-medical-flashcards/SKILL.md +113 -0
  103. package/.opencode/mednotes/skills/create-medical-note/SKILL.md +90 -0
  104. package/.opencode/mednotes/skills/enrich-medical-note/SKILL.md +120 -0
  105. package/.opencode/mednotes/skills/fix-medical-wiki/SKILL.md +559 -0
  106. package/.opencode/mednotes/skills/link-medical-wiki/SKILL.md +224 -0
  107. package/.opencode/mednotes/skills/obsidian-cli/SKILL.md +118 -0
  108. package/.opencode/mednotes/skills/obsidian-markdown/SKILL.md +207 -0
  109. package/.opencode/mednotes/skills/obsidian-markdown/references/CALLOUTS.md +58 -0
  110. package/.opencode/mednotes/skills/obsidian-markdown/references/EMBEDS.md +63 -0
  111. package/.opencode/mednotes/skills/obsidian-markdown/references/PROPERTIES.md +61 -0
  112. package/.opencode/mednotes/skills/obsidian-ops/SKILL.md +136 -0
  113. package/.opencode/mednotes/skills/pdf-library/SKILL.md +45 -0
  114. package/.opencode/mednotes/skills/process-medical-chats/SKILL.md +246 -0
  115. package/.opencode/mednotes/skills/workflow-report/SKILL.md +100 -0
  116. package/.opencode/mednotes/src/mednotes/__init__.py +5 -0
  117. package/.opencode/mednotes/src/mednotes/domains/__init__.py +5 -0
  118. package/.opencode/mednotes/src/mednotes/domains/flashcards/README.md +26 -0
  119. package/.opencode/mednotes/src/mednotes/domains/flashcards/__init__.py +2 -0
  120. package/.opencode/mednotes/src/mednotes/domains/flashcards/build_demo_apkg.py +177 -0
  121. package/.opencode/mednotes/src/mednotes/domains/flashcards/contracts.py +385 -0
  122. package/.opencode/mednotes/src/mednotes/domains/flashcards/flashcards_machine.py +522 -0
  123. package/.opencode/mednotes/src/mednotes/domains/flashcards/fsm.py +817 -0
  124. package/.opencode/mednotes/src/mednotes/domains/flashcards/index.py +630 -0
  125. package/.opencode/mednotes/src/mednotes/domains/flashcards/install_models.py +445 -0
  126. package/.opencode/mednotes/src/mednotes/domains/flashcards/model.py +359 -0
  127. package/.opencode/mednotes/src/mednotes/domains/flashcards/obsidian_links.py +135 -0
  128. package/.opencode/mednotes/src/mednotes/domains/flashcards/obsidian_note_utils.py +546 -0
  129. package/.opencode/mednotes/src/mednotes/domains/flashcards/pipeline.py +580 -0
  130. package/.opencode/mednotes/src/mednotes/domains/flashcards/report.py +510 -0
  131. package/.opencode/mednotes/src/mednotes/domains/flashcards/sources.py +682 -0
  132. package/.opencode/mednotes/src/mednotes/domains/flashcards/sync_rules.py +184 -0
  133. package/.opencode/mednotes/src/mednotes/domains/history/__init__.py +1 -0
  134. package/.opencode/mednotes/src/mednotes/domains/history/history_fsm.py +852 -0
  135. package/.opencode/mednotes/src/mednotes/domains/history/history_machine.py +453 -0
  136. package/.opencode/mednotes/src/mednotes/domains/setup/__init__.py +7 -0
  137. package/.opencode/mednotes/src/mednotes/domains/setup/setup_fsm.py +808 -0
  138. package/.opencode/mednotes/src/mednotes/domains/setup/setup_machine.py +973 -0
  139. package/.opencode/mednotes/src/mednotes/domains/wiki/README.md +64 -0
  140. package/.opencode/mednotes/src/mednotes/domains/wiki/__init__.py +1 -0
  141. package/.opencode/mednotes/src/mednotes/domains/wiki/api.py +668 -0
  142. package/.opencode/mednotes/src/mednotes/domains/wiki/batch_state.py +102 -0
  143. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/__init__.py +1 -0
  144. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/atomicity/__init__.py +1 -0
  145. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/atomicity/atomicity.py +877 -0
  146. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/body_link/__init__.py +1 -0
  147. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/body_link/body_linker.py +1562 -0
  148. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/effects/__init__.py +1 -0
  149. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/effects/effect_adapters.py +949 -0
  150. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/effects/fix_wiki_runtime_adapters.py +433 -0
  151. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/__init__.py +1 -0
  152. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/coverage.py +413 -0
  153. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/graph.py +396 -0
  154. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/graph_fixes.py +161 -0
  155. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/hygiene/__init__.py +1 -0
  156. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/hygiene/hygiene.py +483 -0
  157. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/__init__.py +2 -0
  158. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/anchors.py +185 -0
  159. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/__init__.py +0 -0
  160. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/cache.py +223 -0
  161. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/config.py +131 -0
  162. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/download.py +224 -0
  163. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/frontmatter.py +59 -0
  164. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/insert.py +227 -0
  165. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/local_import.py +54 -0
  166. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/__init__.py +42 -0
  167. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/web_profiles.py +99 -0
  168. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/web_search.py +203 -0
  169. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/wikimedia.py +102 -0
  170. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/__init__.py +1 -0
  171. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/markdown_db_adapter.mjs +434 -0
  172. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/markdown_node_runtime.py +274 -0
  173. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/markdown_query.py +227 -0
  174. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/__init__.py +1 -0
  175. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/artifacts.py +605 -0
  176. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/canonical_merge.py +277 -0
  177. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/markdown_zones.py +85 -0
  178. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/meaning_planner.py +307 -0
  179. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_iter.py +67 -0
  180. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_merge.py +278 -0
  181. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_plan.py +409 -0
  182. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_policy.py +22 -0
  183. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/__init__.py +79 -0
  184. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/fixes.py +264 -0
  185. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/frontmatter.py +435 -0
  186. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/models.py +208 -0
  187. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/prompts.py +37 -0
  188. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/tables.py +236 -0
  189. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/validate.py +404 -0
  190. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/provenance.py +478 -0
  191. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/raw_chats.py +273 -0
  192. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/sources_backfill.py +235 -0
  193. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/__init__.py +10 -0
  194. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/anchors.py +16 -0
  195. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/captions.py +47 -0
  196. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/cli.py +179 -0
  197. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/cloud.py +52 -0
  198. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/config.py +196 -0
  199. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/context_packets.py +76 -0
  200. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/db.py +81 -0
  201. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/doctor.py +102 -0
  202. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/figure_ids.py +42 -0
  203. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/ingest.py +326 -0
  204. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/insert.py +316 -0
  205. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/mentions.py +57 -0
  206. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/ocr.py +71 -0
  207. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/paths.py +35 -0
  208. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/pdf_engine.py +77 -0
  209. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/schema.py +155 -0
  210. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/search.py +188 -0
  211. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/__init__.py +1 -0
  212. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/app.py +89 -0
  213. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/image_backend.py +29 -0
  214. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/state.py +65 -0
  215. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/__init__.py +1 -0
  216. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/publish.py +1139 -0
  217. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/publish_receipts.py +365 -0
  218. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/publish_recovery.py +240 -0
  219. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/__init__.py +1 -0
  220. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/agent_behavior_corpus.py +2069 -0
  221. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/agent_report_validation.py +4448 -0
  222. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/agent_run_audit.py +852 -0
  223. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/architect_prompt_eval.py +341 -0
  224. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/body_linker_eval.py +240 -0
  225. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/curator_output_validation.py +175 -0
  226. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/curator_prompt_eval.py +865 -0
  227. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/triager_prompt_eval.py +1295 -0
  228. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/related_notes/__init__.py +1 -0
  229. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/related_notes/related_notes.py +1920 -0
  230. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/related_notes/related_notes_headless.py +1186 -0
  231. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/__init__.py +1 -0
  232. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/plan_attestation.py +148 -0
  233. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/specialist_receipts.py +360 -0
  234. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/specialist_runtime.py +52 -0
  235. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/specialist_task_runner.py +2470 -0
  236. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/style/__init__.py +1 -0
  237. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/style/style.py +1952 -0
  238. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/subagents/__init__.py +1 -0
  239. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/subagents/agents.py +1767 -0
  240. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/__init__.py +1 -0
  241. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/alias_projection.py +331 -0
  242. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/link_terms.py +151 -0
  243. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/llm_disambiguation.py +182 -0
  244. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/__init__.py +116 -0
  245. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/audit.py +201 -0
  246. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/migration.py +314 -0
  247. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/normalize.py +72 -0
  248. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/policy.py +135 -0
  249. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/resolve.py +413 -0
  250. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/schema.py +157 -0
  251. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/status.py +137 -0
  252. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_bootstrap.py +509 -0
  253. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_curator_batch.py +1115 -0
  254. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_ingestion.py +632 -0
  255. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_map.py +930 -0
  256. package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_recovery.py +1388 -0
  257. package/.opencode/mednotes/src/mednotes/domains/wiki/cli.py +6665 -0
  258. package/.opencode/mednotes/src/mednotes/domains/wiki/common.py +69 -0
  259. package/.opencode/mednotes/src/mednotes/domains/wiki/config.py +210 -0
  260. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/__init__.py +74 -0
  261. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/agent_report.py +242 -0
  262. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/agent_run_audit.py +196 -0
  263. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/agents.py +601 -0
  264. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/curator.py +256 -0
  265. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/effect_payloads.py +519 -0
  266. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/happy_path.py +190 -0
  267. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/link_git.py +110 -0
  268. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/link_runtime_artifact.py +52 -0
  269. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/note_plan.py +75 -0
  270. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/paths.py +114 -0
  271. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/public_report.py +53 -0
  272. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/publish.py +111 -0
  273. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/raw_coverage.py +217 -0
  274. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/related_notes.py +136 -0
  275. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/related_notes_headless.py +153 -0
  276. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/related_notes_runtime.py +395 -0
  277. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/schema_registry.py +637 -0
  278. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/specialist.py +432 -0
  279. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/status.py +62 -0
  280. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/style_rewrite.py +568 -0
  281. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/vocabulary_ingestion.py +223 -0
  282. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_blockers.py +510 -0
  283. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_guardrails.py +637 -0
  284. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_outcomes.py +121 -0
  285. package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_receipts.py +100 -0
  286. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/__init__.py +1 -0
  287. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/__init__.py +1 -0
  288. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/__main__.py +4 -0
  289. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/cli.py +275 -0
  290. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/__init__.py +2 -0
  291. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/candidates.py +193 -0
  292. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/cli.py +189 -0
  293. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/gemini.py +220 -0
  294. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/inputs.py +120 -0
  295. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/models.py +34 -0
  296. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/parsing.py +48 -0
  297. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/prompts.py +216 -0
  298. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/quality.py +54 -0
  299. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/reporting.py +24 -0
  300. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/runner.py +433 -0
  301. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/utils.py +39 -0
  302. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/vault_guard_bridge.py +17 -0
  303. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/__init__.py +1 -0
  304. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_context_packets.py +454 -0
  305. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_decision_projection.py +133 -0
  306. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_effects.py +1260 -0
  307. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_fsm.py +2768 -0
  308. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_machine.py +1588 -0
  309. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_plan.py +306 -0
  310. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_primary_objective.py +316 -0
  311. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_problem.py +153 -0
  312. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_receipt_evidence.py +306 -0
  313. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_states.py +290 -0
  314. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_user_report.py +342 -0
  315. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/health.py +6332 -0
  316. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/__init__.py +1 -0
  317. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_fsm.py +1119 -0
  318. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_git.py +638 -0
  319. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_machine.py +1106 -0
  320. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_retry_governance.py +374 -0
  321. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_runtime_result.py +485 -0
  322. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_triggers.py +183 -0
  323. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/linking.py +2758 -0
  324. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/reference_repair.py +718 -0
  325. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/related_notes_fsm.py +1855 -0
  326. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link_related/__init__.py +1 -0
  327. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link_related/link_related_machine.py +834 -0
  328. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/__init__.py +1 -0
  329. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_fsm.py +1592 -0
  330. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_machine.py +3097 -0
  331. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_primary_objective.py +28 -0
  332. package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_runtime_result.py +185 -0
  333. package/.opencode/mednotes/src/mednotes/domains/wiki/performance.py +97 -0
  334. package/.opencode/mednotes/src/mednotes/kernel/__init__.py +6 -0
  335. package/.opencode/mednotes/src/mednotes/kernel/agent_directive.py +336 -0
  336. package/.opencode/mednotes/src/mednotes/kernel/base.py +51 -0
  337. package/.opencode/mednotes/src/mednotes/kernel/blockers.py +39 -0
  338. package/.opencode/mednotes/src/mednotes/kernel/effect_executor.py +55 -0
  339. package/.opencode/mednotes/src/mednotes/kernel/effect_intent.py +69 -0
  340. package/.opencode/mednotes/src/mednotes/kernel/effects.py +160 -0
  341. package/.opencode/mednotes/src/mednotes/kernel/errors.py +38 -0
  342. package/.opencode/mednotes/src/mednotes/kernel/fsm_event.py +35 -0
  343. package/.opencode/mednotes/src/mednotes/kernel/fsm_model.py +55 -0
  344. package/.opencode/mednotes/src/mednotes/kernel/fsm_transition_result.py +75 -0
  345. package/.opencode/mednotes/src/mednotes/kernel/guardrails.py +188 -0
  346. package/.opencode/mednotes/src/mednotes/kernel/progress.py +319 -0
  347. package/.opencode/mednotes/src/mednotes/kernel/public_report.py +346 -0
  348. package/.opencode/mednotes/src/mednotes/kernel/state_machine.py +164 -0
  349. package/.opencode/mednotes/src/mednotes/kernel/workflow.py +619 -0
  350. package/.opencode/mednotes/src/mednotes/platform/__init__.py +5 -0
  351. package/.opencode/mednotes/src/mednotes/platform/backup_policy.py +382 -0
  352. package/.opencode/mednotes/src/mednotes/platform/feedback/__init__.py +62 -0
  353. package/.opencode/mednotes/src/mednotes/platform/feedback/cli.py +275 -0
  354. package/.opencode/mednotes/src/mednotes/platform/feedback/contracts.py +83 -0
  355. package/.opencode/mednotes/src/mednotes/platform/feedback/core.py +4168 -0
  356. package/.opencode/mednotes/src/mednotes/platform/feedback/integrity.py +989 -0
  357. package/.opencode/mednotes/src/mednotes/platform/feedback/operational_contract.py +2293 -0
  358. package/.opencode/mednotes/src/mednotes/platform/feedback/telemetry.py +875 -0
  359. package/.opencode/mednotes/src/mednotes/platform/feedback/telemetry_config.py +65 -0
  360. package/.opencode/mednotes/src/mednotes/platform/opencode_runtime_config.py +182 -0
  361. package/.opencode/mednotes/src/mednotes/platform/paths/__init__.py +1560 -0
  362. package/.opencode/mednotes/src/mednotes/platform/secrets.py +89 -0
  363. package/.opencode/mednotes/src/mednotes/platform/user_config.py +103 -0
  364. package/.opencode/mednotes/src/mednotes/platform/vault_guard.py +214 -0
  365. package/.opencode/mednotes/uv.lock +932 -0
  366. package/.opencode/mednotes.generated.json +395 -0
  367. package/.opencode/opencode.json +31 -0
  368. package/.opencode/plugins/mednotes-fsm.mjs +7 -0
  369. package/.opencode/plugins/mednotes_hook/adapters/antigravity.mjs +169 -0
  370. package/.opencode/plugins/mednotes_hook/adapters/harness_payload.mjs +103 -0
  371. package/.opencode/plugins/mednotes_hook/adapters/opencode_plugin.mjs +341 -0
  372. package/.opencode/plugins/mednotes_hook/adapters/opencode_user_config_sync.mjs +177 -0
  373. package/.opencode/plugins/mednotes_hook/anki_preflight.mjs +214 -0
  374. package/.opencode/plugins/mednotes_hook/cli.mjs +143 -0
  375. package/.opencode/plugins/mednotes_hook/diagnostics.mjs +11 -0
  376. package/.opencode/plugins/mednotes_hook/domain/agent_directive_core.mjs +160 -0
  377. package/.opencode/plugins/mednotes_hook/fsm_directive.mjs +1470 -0
  378. package/.opencode/plugins/mednotes_hook/hook_errors.mjs +120 -0
  379. package/.opencode/plugins/mednotes_hook/retention.mjs +114 -0
  380. package/.opencode/plugins/mednotes_hook/runtime.mjs +174 -0
  381. package/.opencode/plugins/mednotes_hook/telemetry_capture.mjs +511 -0
  382. package/.opencode/plugins/mednotes_hook/vault_guard.mjs +624 -0
  383. package/AGENTS.md +57 -0
  384. package/README.md +194 -0
  385. package/adapters/antigravity/agents.json +80 -0
  386. package/adapters/antigravity/templates/med-chat-triager.md +214 -0
  387. package/adapters/antigravity/templates/med-flashcard-maker.md +72 -0
  388. package/adapters/antigravity/templates/med-knowledge-architect.md +241 -0
  389. package/adapters/antigravity/templates/med-link-graph-curator.md +187 -0
  390. package/adapters/antigravity/templates/med-publish-guard.md +71 -0
  391. package/adapters/gemini-cli/gemini-extension.json +14 -0
  392. package/adapters/gemini-cli/package.json +15 -0
  393. package/adapters/gemini-cli/pyproject.toml +48 -0
  394. package/bin/mednotes-opencode.mjs +155 -0
  395. package/contracts/agents.json +116 -0
  396. package/core/agents/med-chat-triager.md +197 -0
  397. package/core/agents/med-flashcard-maker.md +56 -0
  398. package/core/agents/med-knowledge-architect.md +224 -0
  399. package/core/agents/med-link-graph-curator.md +171 -0
  400. package/core/agents/med-publish-guard.md +55 -0
  401. package/core/commands/flashcards.toml +22 -0
  402. package/core/commands/mednotes/create.toml +22 -0
  403. package/core/commands/mednotes/enrich.toml +24 -0
  404. package/core/commands/mednotes/fix-wiki.toml +24 -0
  405. package/core/commands/mednotes/history.toml +19 -0
  406. package/core/commands/mednotes/link-body.toml +22 -0
  407. package/core/commands/mednotes/link-related.toml +24 -0
  408. package/core/commands/mednotes/link.toml +24 -0
  409. package/core/commands/mednotes/pdf-library.toml +24 -0
  410. package/core/commands/mednotes/process-chats.toml +20 -0
  411. package/core/commands/mednotes/setup.toml +18 -0
  412. package/core/commands/mednotes/status.toml +24 -0
  413. package/core/commands/mednotes/telemetry.toml +24 -0
  414. package/core/commands/report.toml +23 -0
  415. package/core/skills/THIRD_PARTY_NOTICES.md +45 -0
  416. package/core/skills/create-medical-flashcards/SKILL.md +113 -0
  417. package/core/skills/create-medical-note/SKILL.md +90 -0
  418. package/core/skills/enrich-medical-note/SKILL.md +120 -0
  419. package/core/skills/fix-medical-wiki/SKILL.md +559 -0
  420. package/core/skills/link-medical-wiki/SKILL.md +224 -0
  421. package/core/skills/obsidian-cli/SKILL.md +118 -0
  422. package/core/skills/obsidian-markdown/SKILL.md +207 -0
  423. package/core/skills/obsidian-markdown/references/CALLOUTS.md +58 -0
  424. package/core/skills/obsidian-markdown/references/EMBEDS.md +63 -0
  425. package/core/skills/obsidian-markdown/references/PROPERTIES.md +61 -0
  426. package/core/skills/obsidian-ops/SKILL.md +136 -0
  427. package/core/skills/pdf-library/SKILL.md +45 -0
  428. package/core/skills/process-medical-chats/SKILL.md +246 -0
  429. package/core/skills/workflow-report/SKILL.md +100 -0
  430. package/package.json +45 -0
@@ -0,0 +1,69 @@
1
+ """Shared primitives for deterministic Wiki workflow operations."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import shlex
6
+ from datetime import UTC, datetime
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ # Generic exit codes + the MedOpsError hierarchy live in the framework; the
11
+ # linker-specific code is domain-owned so the shared kernel stays product-free.
12
+ from mednotes.kernel.errors import ( # noqa: F401
13
+ EXIT_IO,
14
+ EXIT_MISSING,
15
+ EXIT_OK,
16
+ EXIT_USAGE,
17
+ EXIT_VALIDATION,
18
+ CollisionError,
19
+ FileWriteError,
20
+ MedOpsError,
21
+ MissingPathError,
22
+ ValidationError,
23
+ )
24
+
25
+ EXIT_LINKER = 6
26
+
27
+ MIGRATION_PLAN_SCHEMA = "medical-notes-workbench.taxonomy-migration-plan.v1"
28
+ MIGRATION_RECEIPT_SCHEMA = "medical-notes-workbench.taxonomy-migration-receipt.v1"
29
+ SUBAGENT_PLAN_SCHEMA = "medical-notes-workbench.subagent-plan.v1"
30
+ WIKI_HEALTH_FIX_SCHEMA = "medical-notes-workbench.wiki-health-fix.v1"
31
+ BLOCKER_RESOLUTION_SCHEMA = "medical-notes-workbench.blocker-resolution.v1"
32
+ NOTE_MERGE_PLAN_SCHEMA = "medical-notes-workbench.note-merge-plan.v1"
33
+ NOTE_MERGE_APPLY_SCHEMA = "medical-notes-workbench.note-merge-apply.v1"
34
+
35
+
36
+ # Exit codes and the MedOpsError hierarchy now live in mednotes.kernel.errors
37
+ # (framework); re-exported above for the many domain callers of wiki.common.
38
+
39
+
40
+ def _now_iso() -> str:
41
+ return datetime.now(UTC).replace(microsecond=0).isoformat()
42
+
43
+
44
+ def _json(data: Any) -> None:
45
+ print(json.dumps(data, ensure_ascii=False, indent=2))
46
+
47
+
48
+ def wiki_cli_base_command() -> str:
49
+ """Return an executable command for the current Wiki CLI entrypoint."""
50
+ shim = Path(__file__).resolve().parents[4] / "scripts" / "mednotes" / "wiki" / "cli.py"
51
+ return "uv run python " + shlex.quote(str(shim))
52
+
53
+
54
+ def wiki_cli_command(*args: object) -> str:
55
+ return " ".join([wiki_cli_base_command(), *(shlex.quote(str(arg)) for arg in args)])
56
+
57
+
58
+ # Forma RELATIVA-ao-checkout dos caminhos canônicos, para instruções voltadas ao
59
+ # agent que mostram um caminho relativo (vs. o absoluto do wiki_cli_base_command
60
+ # acima). Fonte única: ao reorganizar a árvore, atualize SÓ aqui.
61
+ # Ver ADR-0001 regra 10 (layout macio).
62
+ WIKI_CLI_RELPATH = "bundle/scripts/mednotes/wiki/cli.py"
63
+ DOCS_RELPATH = "bundle/docs"
64
+ SKILLS_RELPATH = "bundle/skills"
65
+
66
+
67
+ def wiki_cli_relative_command(command: str = "") -> str:
68
+ """`uv run python <cli> <command>` relativo ao checkout, para instruções ao agent."""
69
+ return f"uv run python {WIKI_CLI_RELPATH} {command}".rstrip()
@@ -0,0 +1,210 @@
1
+ """Configuration and resolved path helpers for Wiki workflows."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import os
6
+ import tomllib
7
+ from dataclasses import dataclass, field
8
+ from pathlib import Path
9
+
10
+ from pydantic import ValidationError as PydanticValidationError
11
+
12
+ import mednotes.platform.paths as mednotes_paths_module
13
+ from mednotes.domains.wiki.common import ValidationError
14
+ from mednotes.domains.wiki.contracts.paths import PathResolutionResult, blocker_from_wiki_resolution
15
+ from mednotes.kernel.base import JsonObject, JsonObjectAdapter
16
+ from mednotes.platform.paths import (
17
+ WikiPathResolution,
18
+ config_encoding_warnings,
19
+ environment_preflight,
20
+ expand_path,
21
+ find_config,
22
+ read_toml,
23
+ resolve_raw_dir,
24
+ resolve_wiki_dir,
25
+ user_state_dir,
26
+ )
27
+ from mednotes.platform.user_config import MedNotesUserConfig, load_user_config
28
+
29
+ DEFAULT_CATALOG_PATH = mednotes_paths_module.DEFAULT_CATALOG_PATH
30
+ DEFAULT_RAW_DIR = mednotes_paths_module.DEFAULT_RAW_DIR
31
+ DEFAULT_WIKI_DIR = ""
32
+ DEFAULT_VOCABULARY_DB_PATH = "~/.mednotes/vocabulary.sqlite"
33
+
34
+
35
+ @dataclass(frozen=True)
36
+ class MedConfig:
37
+ raw_dir: Path
38
+ wiki_dir: Path
39
+ catalog_path: Path
40
+ vocabulary_db_path: Path | None = None
41
+ artifact_dir: Path | None = None
42
+ state_dir: Path | None = None
43
+ wiki_source: str = ""
44
+ wiki_compat_warnings: tuple[str, ...] = ()
45
+ wiki_memory_path: Path | None = None
46
+ config_path: Path | None = None
47
+ user_config: MedNotesUserConfig = field(default_factory=MedNotesUserConfig)
48
+
49
+
50
+ def _path(value: str | os.PathLike[str]) -> Path:
51
+ return expand_path(value)
52
+
53
+
54
+ class WikiPathResolutionError(ValidationError):
55
+ """Raised when wiki_dir cannot be resolved safely before a workflow."""
56
+
57
+ def __init__(self, resolution: WikiPathResolution):
58
+ self.resolution = resolution
59
+ super().__init__(resolution.next_action or resolution.blocked_reason)
60
+
61
+ def payload(self, *, phase: str = "resolve_wiki_dir") -> dict[str, object]:
62
+ resolution_payload = self.resolution.as_payload(phase=phase)
63
+ blocker = blocker_from_wiki_resolution(resolution_payload)
64
+ result = PathResolutionResult(status="blocked", blocker=blocker)
65
+ return {
66
+ **resolution_payload,
67
+ **result.model_dump(mode="json")["blocker"],
68
+ "status": "blocked",
69
+ }
70
+
71
+
72
+ def _user_state_dir() -> Path:
73
+ return user_state_dir()
74
+
75
+
76
+ def _default_catalog_path() -> Path:
77
+ return user_state_dir() / "CATALOGO_WIKI.json"
78
+
79
+
80
+ def _json_field(payload: JsonObject, key: str) -> object:
81
+ if key not in payload:
82
+ return None
83
+ return payload[key]
84
+
85
+
86
+ def _json_str_field(payload: JsonObject, key: str) -> str:
87
+ value = _json_field(payload, key)
88
+ return value if isinstance(value, str) else ""
89
+
90
+
91
+ def _json_list_field(payload: JsonObject, key: str) -> list[object]:
92
+ value = _json_field(payload, key)
93
+ return value if isinstance(value, list) else []
94
+
95
+
96
+ def _json_object_field(payload: JsonObject, key: str) -> JsonObject:
97
+ value = _json_field(payload, key)
98
+ return JsonObjectAdapter.validate_python(value) if isinstance(value, dict) else {}
99
+
100
+
101
+ def _read_toml(path: Path | None) -> JsonObject:
102
+ try:
103
+ return JsonObjectAdapter.validate_python(read_toml(path))
104
+ except RuntimeError as exc:
105
+ raise ValidationError(str(exc)) from exc
106
+
107
+
108
+ def _load_user_config(path: Path | None) -> MedNotesUserConfig:
109
+ try:
110
+ return load_user_config(path)
111
+ except (OSError, tomllib.TOMLDecodeError, PydanticValidationError) as exc:
112
+ raise ValidationError(f"invalid MedNotes config: {exc}") from exc
113
+
114
+
115
+ def _find_config(explicit: str | None) -> Path | None:
116
+ return find_config(explicit, start=Path.cwd())
117
+
118
+
119
+ def resolve_config(args: argparse.Namespace) -> MedConfig:
120
+ explicit_config = getattr(args, "config", None)
121
+ config_path = _find_config(explicit_config)
122
+ user_config = _load_user_config(config_path)
123
+ cfg = _read_toml(config_path)
124
+ section = _json_object_field(cfg, "chat_processor")
125
+
126
+ def pick(name: str, env: str, default: str | os.PathLike[str]) -> Path:
127
+ cli_value = getattr(args, name, None)
128
+ value = cli_value or os.getenv(env) or _json_field(section, name) or default
129
+ return _path(str(value))
130
+
131
+ def pick_optional(name: str, env: str) -> Path | None:
132
+ cli_value = getattr(args, name, None)
133
+ value = cli_value or os.getenv(env) or _json_field(section, name)
134
+ return _path(str(value)) if value else None
135
+
136
+ vocabulary_value = (
137
+ getattr(args, "vocabulary_db", None)
138
+ or os.getenv("MEDNOTES_VOCABULARY_DB")
139
+ or _json_field(section, "vocabulary_db_path")
140
+ or _json_field(section, "vocabulary_db")
141
+ )
142
+ vocabulary_db_path = _path(str(vocabulary_value)) if vocabulary_value else user_state_dir() / "vocabulary.sqlite"
143
+
144
+ wiki_resolution = resolve_wiki_dir(
145
+ explicit=getattr(args, "wiki_dir", None),
146
+ config=explicit_config,
147
+ start=Path.cwd(),
148
+ enable_gemini_probe=False,
149
+ )
150
+ if not wiki_resolution.ok:
151
+ raise WikiPathResolutionError(wiki_resolution)
152
+ wiki_dir = wiki_resolution.path
153
+ if wiki_dir is None:
154
+ raise WikiPathResolutionError(wiki_resolution)
155
+
156
+ return MedConfig(
157
+ raw_dir=resolve_raw_dir(
158
+ explicit=getattr(args, "raw_dir", None),
159
+ config=explicit_config,
160
+ start=Path.cwd(),
161
+ ),
162
+ wiki_dir=wiki_dir,
163
+ catalog_path=pick("catalog_path", "MED_CATALOG_PATH", _default_catalog_path()),
164
+ vocabulary_db_path=vocabulary_db_path,
165
+ artifact_dir=pick_optional("artifact_dir", "MED_ARTIFACT_DIR"),
166
+ state_dir=user_state_dir(),
167
+ wiki_source=wiki_resolution.source,
168
+ wiki_compat_warnings=wiki_resolution.compat_warnings,
169
+ wiki_memory_path=wiki_resolution.memory_path,
170
+ config_path=config_path,
171
+ user_config=user_config,
172
+ )
173
+
174
+
175
+ def validate_config(config: MedConfig) -> JsonObject:
176
+ preflight = environment_preflight(
177
+ extension_root=Path(__file__).resolve().parents[4],
178
+ state_dir=config.state_dir or user_state_dir(),
179
+ sample_paths=[
180
+ config.raw_dir,
181
+ config.wiki_dir,
182
+ config.catalog_path,
183
+ *( [config.vocabulary_db_path] if config.vocabulary_db_path else [] ),
184
+ ],
185
+ )
186
+ preflight_payload = JsonObjectAdapter.validate_python(preflight)
187
+ return {
188
+ "phase": "validate_environment",
189
+ "status": _json_str_field(preflight_payload, "status") or "completed",
190
+ "blocked_reason": _json_str_field(preflight_payload, "blocked_reason"),
191
+ "next_action": _json_str_field(preflight_payload, "next_action"),
192
+ "required_inputs": _json_list_field(preflight_payload, "required_inputs"),
193
+ "human_decision_required": False,
194
+ "raw_dir": str(config.raw_dir),
195
+ "raw_dir_exists": config.raw_dir.exists(),
196
+ "wiki_dir": str(config.wiki_dir),
197
+ "wiki_dir_exists": config.wiki_dir.exists(),
198
+ "wiki_source": config.wiki_source,
199
+ "wiki_memory_path": str(config.wiki_memory_path) if config.wiki_memory_path else "",
200
+ "config_path": str(config.config_path) if config.config_path else "",
201
+ "config_encoding_warnings": config_encoding_warnings(config.config_path),
202
+ "wiki_compat_warnings": list(config.wiki_compat_warnings),
203
+ "catalog_path": str(config.catalog_path),
204
+ "catalog_path_exists": config.catalog_path.exists(),
205
+ "vocabulary_db_path": str(config.vocabulary_db_path) if config.vocabulary_db_path else "",
206
+ "vocabulary_db_exists": bool(config.vocabulary_db_path and config.vocabulary_db_path.exists()),
207
+ "artifact_dir": str(config.artifact_dir) if config.artifact_dir else "",
208
+ "artifact_dir_exists": bool(config.artifact_dir and config.artifact_dir.exists()),
209
+ "environment_preflight": preflight,
210
+ }
@@ -0,0 +1,74 @@
1
+ """Executable contract models for Medical Notes Workbench workflows."""
2
+
3
+ from mednotes.kernel.base import ContractModel, contract_error
4
+ from mednotes.kernel.blockers import BlockerEntryModel
5
+ from mednotes.kernel.progress import (
6
+ ProgressMode,
7
+ WorkflowProgressCounts,
8
+ WorkflowProgressEvent,
9
+ WorkflowProgressEventType,
10
+ WorkflowProgressState,
11
+ WorkflowProgressStatus,
12
+ WorkflowProgressViewModel,
13
+ build_progress_view_model,
14
+ fold_progress_events,
15
+ )
16
+ from mednotes.kernel.state_machine import (
17
+ WorkflowStateCategory,
18
+ WorkflowStateMachineSnapshot,
19
+ WorkflowTransition,
20
+ )
21
+ from mednotes.kernel.workflow import (
22
+ AutomationKind,
23
+ DecisionEvidence,
24
+ DecisionKind,
25
+ HumanDecisionOption,
26
+ HumanDecisionPacket,
27
+ ReceiptStatus,
28
+ RejectedAutomation,
29
+ VersionControlSafety,
30
+ WorkflowArtifact,
31
+ WorkflowAutomationKind,
32
+ WorkflowDecision,
33
+ WorkflowDecisionKind,
34
+ WorkflowOutcomeError,
35
+ WorkflowPhaseOutcome,
36
+ WorkflowPhaseReceipt,
37
+ WorkflowReceiptPayload,
38
+ WorkflowRollback,
39
+ )
40
+
41
+ __all__ = [
42
+ "AutomationKind",
43
+ "BlockerEntryModel",
44
+ "ContractModel",
45
+ "DecisionEvidence",
46
+ "DecisionKind",
47
+ "HumanDecisionOption",
48
+ "HumanDecisionPacket",
49
+ "ProgressMode",
50
+ "ReceiptStatus",
51
+ "RejectedAutomation",
52
+ "VersionControlSafety",
53
+ "WorkflowAutomationKind",
54
+ "WorkflowArtifact",
55
+ "WorkflowDecision",
56
+ "WorkflowDecisionKind",
57
+ "WorkflowOutcomeError",
58
+ "WorkflowPhaseOutcome",
59
+ "WorkflowPhaseReceipt",
60
+ "WorkflowProgressCounts",
61
+ "WorkflowProgressEvent",
62
+ "WorkflowProgressEventType",
63
+ "WorkflowProgressState",
64
+ "WorkflowProgressStatus",
65
+ "WorkflowProgressViewModel",
66
+ "WorkflowReceiptPayload",
67
+ "WorkflowRollback",
68
+ "WorkflowStateCategory",
69
+ "WorkflowStateMachineSnapshot",
70
+ "WorkflowTransition",
71
+ "build_progress_view_model",
72
+ "contract_error",
73
+ "fold_progress_events",
74
+ ]
@@ -0,0 +1,242 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import StrEnum
4
+ from typing import Literal
5
+
6
+ from pydantic import Field, field_validator, model_validator
7
+ from pydantic_core.core_schema import ValidationInfo
8
+
9
+ from mednotes.domains.wiki.contracts.agent_run_audit import WorkflowTranscriptAuditResult
10
+ from mednotes.domains.wiki.contracts.happy_path import HappyPathRunMetrics
11
+ from mednotes.domains.wiki.contracts.public_report import WorkflowPublicReportViewModel
12
+ from mednotes.kernel.base import ContractModel, JsonObject
13
+ from mednotes.kernel.public_report import WorkflowPrimaryObjectiveSummary
14
+
15
+
16
+ class AgentRunReportFindingCode(StrEnum):
17
+ RECEIPT_STATUS_MISMATCH = "agent.final_report_receipt_status_mismatch"
18
+ PROGRESS_STATUS_MISMATCH = "agent.final_report_progress_status_mismatch"
19
+ WORKFLOW_STATUS_OMITTED = "agent.final_report_workflow_status_omitted"
20
+ OMITTED_TOOL_ERROR = "agent.final_report_omitted_tool_error"
21
+ REPORTED_ARTIFACT_PATH_INVALID = "agent.final_report_artifact_path_invalid"
22
+ FINAL_REPORT_LOCAL_PATH_LEAK = "agent.final_report_local_path_leak"
23
+ SUCCESS_CLAIM_MISMATCH = "agent.final_report_success_claim_mismatch"
24
+ PUBLIC_OUTPUT_INTERNAL_TERM_LEAK = "agent.public_output_internal_term_leak"
25
+ STALE_NEXT_ACTION = "agent.workflow_stale_next_action"
26
+ PRIMARY_OBJECTIVE_OMITTED = "agent.final_report_primary_objective_omitted"
27
+ TOOL_DEVIATION_OMITTED = "agent.final_report_tool_deviation_omitted"
28
+ WORKFLOW_CONTRACT_CONTRADICTION = "agent.workflow_contract_contradiction"
29
+ AGENT_EVENT_OMITTED = "agent.final_report_agent_event_omitted"
30
+ VERSION_CONTROL_SAFETY_OMITTED = "agent.final_report_version_control_safety_omitted"
31
+ API_ACCOUNTING_MISMATCH = "agent.final_report_api_accounting_mismatch"
32
+ OPERATIONAL_WARNING_OMITTED = "agent.final_report_operational_warning_omitted"
33
+ WAITING_AGENT_CONTINUATION_OMITTED = "agent.final_report_waiting_agent_continuation_omitted"
34
+ FINAL_REPORT_NOT_ALLOWED = "agent.final_report_not_allowed"
35
+ WORKFLOW_AGENT_DIRECTIVE_INVALID = "agent.workflow_agent_directive_invalid"
36
+ MISSING_ERROR_CONTEXT_ROOT_CAUSE = "agent.final_report_missing_error_context_root_cause"
37
+ CONTENT_QUALITY_AUDIT_OMITTED = "agent.final_report_content_quality_audit_omitted"
38
+ RUNTIME_ERROR_OMITTED = "agent.final_report_runtime_error_omitted"
39
+ RUNTIME_PERFORMANCE_BUG = "agent.runtime_performance_bug"
40
+ RUNTIME_ROUTE_PROBE_OBSERVED = "agent.runtime_route_probe_observed"
41
+ SPECIALIST_MODEL_POLICY_VIOLATION = "agent.specialist_model_policy_violation"
42
+ BLOCKED_TOOL_RESULT_OMITTED = "agent.final_report_blocked_tool_result_omitted"
43
+ RUN_FINISH_OMITTED = "agent.final_report_run_finish_omitted"
44
+ FINAL_REPORT_INCOMPLETE = "agent.final_report_incomplete"
45
+ WAITING_EXTERNAL_CONTINUATION_ATTEMPTED = "agent.waiting_external_continuation_attempted"
46
+ BATCH_PROGRESS_REPORT_OMITTED = "agent.batch_progress_report_omitted"
47
+ SPECIALIST_APPLY_STEP_OMITTED = "agent.specialist_apply_step_omitted"
48
+ SPECIALIST_REWRITE_COUNT_MISMATCH = "agent.final_report_specialist_rewrite_count_mismatch"
49
+ READY_CONTINUATION_STOPPED = "agent.ready_continuation_stopped"
50
+ PROCESS_CHATS_PRIMARY_OBJECTIVE_UNRESOLVED = "agent.process_chats_primary_objective_unresolved"
51
+ PROCESS_CHATS_VAULT_DELETION_WITHOUT_RECEIPT = "agent.process_chats_vault_deletion_without_receipt"
52
+ TRANSCRIPT_UNREADABLE = "agent.transcript_unreadable"
53
+ SUBAGENT_RAW_CONTENT_CONTRACT_VIOLATION = "agent.subagent_raw_content_contract_violation"
54
+ PARENT_CANONICAL_ARTIFACT_WRITE_BEFORE_SUBAGENT = "agent.parent_canonical_artifact_write_before_subagent"
55
+ PARENT_CANONICAL_ARTIFACT_WRITE_AFTER_SUBAGENT = "agent.parent_canonical_artifact_write_after_subagent"
56
+ PARALLEL_HUMAN_DECISION_BACKLOG = "agent.parallel_human_decision_backlog"
57
+ AGY_MATERIALIZED_SKILL_MISCLASSIFIED_AS_STALE = "agent.agy_materialized_skill_misclassified_as_stale"
58
+ RECOVERABLE_TOOL_ERROR_OBSERVED = "agent.recoverable_tool_error_observed"
59
+ EFFECT_PAYLOAD_CONTRACT_INVALID = "effect_payload_contract_invalid"
60
+
61
+
62
+ AgentRunReportSeverity = Literal["low", "medium", "high", "critical"]
63
+ AgentRunReportValidationStatus = Literal["completed", "blocked"]
64
+ FixWikiObjectiveStatus = Literal["yes", "partial", "no", "waiting_agent", "waiting_external", "failed", "unknown"]
65
+ FixWikiGraphStatus = Literal["improved", "clean", "blocked", "unchanged", "worse", "unknown"]
66
+ FixWikiRelatedNotesStatus = Literal["updated", "pending", "blocked", "skipped", "unknown"]
67
+ ProcessChatsObjectiveStatus = Literal[
68
+ "no_pending",
69
+ "preview_ready",
70
+ "ready_to_publish",
71
+ "published",
72
+ "completed_with_link_blockers",
73
+ "completed",
74
+ "blocked",
75
+ "failed",
76
+ "unknown",
77
+ ]
78
+ ProcessChatsNotesStatus = Literal["ready_to_publish", "published", "not_written", "blocked", "unknown"]
79
+ ProcessChatsRawStatus = Literal["covered", "processed", "partial", "not_processed", "unknown"]
80
+ ProcessChatsCoverageStatus = Literal["valid", "missing", "invalid", "not_applicable", "unknown"]
81
+ ProcessChatsLinkerStatus = Literal["applied", "blocked", "skipped", "not_run", "not_applicable", "unknown"]
82
+ StyleRewriteApplyStatus = Literal["applied", "completed", "blocked", "failed", "waiting_external"]
83
+
84
+
85
+ class StyleRewriteAtomicApplyItem(ContractModel):
86
+ """Typed item evidence emitted by style-rewrite apply tools."""
87
+
88
+ work_id: str = ""
89
+ written: bool
90
+
91
+
92
+ class StyleRewriteAtomicApplyResult(ContractModel):
93
+ """Tool-output contract consumed by final report validation."""
94
+
95
+ schema_: Literal[
96
+ "medical-notes-workbench.style-rewrite-atomic-apply-agent-stdout.v1",
97
+ "medical-notes-workbench.style-rewrite-atomic-apply-result.v1",
98
+ ] = Field(alias="schema")
99
+ status: StyleRewriteApplyStatus
100
+ work_id: str = ""
101
+ written_count: int = Field(default=0, ge=0)
102
+ items: tuple[StyleRewriteAtomicApplyItem, ...] = ()
103
+
104
+
105
+ class FixWikiPrimaryObjectiveSummary(ContractModel):
106
+ schema_: Literal["medical-notes-workbench.fix-wiki-primary-objective-summary.v1"] = Field(
107
+ "medical-notes-workbench.fix-wiki-primary-objective-summary.v1",
108
+ alias="schema",
109
+ )
110
+ wiki_fixed: FixWikiObjectiveStatus
111
+ wiki_summary: str
112
+ mutation_count: int = Field(ge=0)
113
+ written_count: int = Field(ge=0)
114
+ mutation_summary: str
115
+ graph_status: FixWikiGraphStatus
116
+ graph_summary: str
117
+ related_notes_status: FixWikiRelatedNotesStatus
118
+ related_notes_summary: str
119
+ required_report_items: list[str] = Field(
120
+ default_factory=lambda: [
121
+ "wiki_fixed",
122
+ "mutation_summary",
123
+ "graph_summary",
124
+ "related_notes_summary",
125
+ ]
126
+ )
127
+
128
+ @field_validator("wiki_summary", "mutation_summary", "graph_summary", "related_notes_summary")
129
+ @classmethod
130
+ def _required_summary_text(cls, value: str, info: ValidationInfo) -> str:
131
+ cleaned = value.strip()
132
+ if not cleaned:
133
+ raise ValueError(f"{info.field_name} must be non-empty")
134
+ return cleaned
135
+
136
+
137
+ class ProcessChatsPrimaryObjectiveSummary(ContractModel):
138
+ schema_: Literal["medical-notes-workbench.process-chats-primary-objective-summary.v1"] = Field(
139
+ "medical-notes-workbench.process-chats-primary-objective-summary.v1",
140
+ alias="schema",
141
+ )
142
+ process_status: ProcessChatsObjectiveStatus
143
+ process_summary: str
144
+ notes_status: ProcessChatsNotesStatus
145
+ note_count: int = Field(ge=0, strict=True)
146
+ wiki_write_summary: str
147
+ raw_status: ProcessChatsRawStatus
148
+ raw_count: int = Field(ge=0, strict=True)
149
+ raw_summary: str
150
+ coverage_status: ProcessChatsCoverageStatus
151
+ coverage_summary: str
152
+ linker_status: ProcessChatsLinkerStatus
153
+ linker_summary: str
154
+ required_report_items: list[str] = Field(
155
+ default_factory=lambda: [
156
+ "process_status",
157
+ "raw_summary",
158
+ "wiki_write_summary",
159
+ "coverage_summary",
160
+ "linker_summary",
161
+ ]
162
+ )
163
+
164
+ @field_validator(
165
+ "process_summary",
166
+ "wiki_write_summary",
167
+ "raw_summary",
168
+ "coverage_summary",
169
+ "linker_summary",
170
+ )
171
+ @classmethod
172
+ def _required_summary_text(cls, value: str, info: ValidationInfo) -> str:
173
+ cleaned = value.strip()
174
+ if not cleaned:
175
+ raise ValueError(f"{info.field_name} must be non-empty")
176
+ return cleaned
177
+
178
+
179
+ class AgentRunReportFinding(ContractModel):
180
+ schema_: Literal["medical-notes-workbench.agent-run-report-finding.v1"] = Field(
181
+ "medical-notes-workbench.agent-run-report-finding.v1",
182
+ alias="schema",
183
+ )
184
+ code: AgentRunReportFindingCode
185
+ severity: AgentRunReportSeverity
186
+ source: str
187
+ message: str
188
+ next_action: str
189
+ source_field: str = ""
190
+ expected: str = ""
191
+ actual: str = ""
192
+ path: str = ""
193
+ artifact_name: str = ""
194
+ tool_error_type: str = ""
195
+ evidence: JsonObject = Field(default_factory=dict)
196
+
197
+ @field_validator("source", "message", "next_action")
198
+ @classmethod
199
+ def _required_text(cls, value: str, info: ValidationInfo) -> str:
200
+ cleaned = value.strip()
201
+ if not cleaned:
202
+ raise ValueError(f"{info.field_name} must be non-empty")
203
+ return cleaned
204
+
205
+
206
+ class AgentRunReportValidation(ContractModel):
207
+ schema_: Literal["medical-notes-workbench.agent-run-report-validation.v1"] = Field(
208
+ "medical-notes-workbench.agent-run-report-validation.v1",
209
+ alias="schema",
210
+ )
211
+ phase: Literal["validate_agent_run_report"] = "validate_agent_run_report"
212
+ status: AgentRunReportValidationStatus
213
+ workflow: str = ""
214
+ run_id: str = ""
215
+ workflow_status: str = ""
216
+ workflow_phase: str = ""
217
+ receipt_status: str = ""
218
+ blocked_reason: str = ""
219
+ next_action: str = ""
220
+ final_report_present: bool = False
221
+ transcript_present: bool = False
222
+ workflow_payload_path: str = ""
223
+ transcript_path: str = ""
224
+ final_report_path: str = ""
225
+ primary_objective: (
226
+ FixWikiPrimaryObjectiveSummary | ProcessChatsPrimaryObjectiveSummary | WorkflowPrimaryObjectiveSummary | None
227
+ ) = None
228
+ happy_path_metrics: HappyPathRunMetrics | None = None
229
+ public_report_view_model: WorkflowPublicReportViewModel | None = None
230
+ transcript_audit: WorkflowTranscriptAuditResult | None = None
231
+ finding_count: int = Field(ge=0)
232
+ findings: list[AgentRunReportFinding] = Field(default_factory=list)
233
+
234
+ @model_validator(mode="after")
235
+ def _validate_report_contract(self) -> AgentRunReportValidation:
236
+ if self.finding_count != len(self.findings):
237
+ raise ValueError("finding_count must match findings length")
238
+ if self.findings and self.status != "blocked":
239
+ raise ValueError("findings require blocked status")
240
+ if self.status == "blocked" and not self.next_action.strip():
241
+ raise ValueError("blocked validation requires next_action")
242
+ return self