wicked-garden 12.27.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 (640) hide show
  1. package/.claude-plugin/archetypes.json +166 -0
  2. package/.claude-plugin/components.json +75 -0
  3. package/.claude-plugin/marketplace.json +15 -0
  4. package/.claude-plugin/plugin.json +174 -0
  5. package/.claude-plugin/specialist.json +48 -0
  6. package/.claude-plugin/stack-registry.json +96 -0
  7. package/AGENTS.md +13 -0
  8. package/CHANGELOG.md +712 -0
  9. package/CONTRIBUTING.md +99 -0
  10. package/ETHOS.md +83 -0
  11. package/LICENSE +21 -0
  12. package/README.md +115 -0
  13. package/WICKED_GARDEN_BUS_EVENTS.md +149 -0
  14. package/agents/agentic/architect.md +449 -0
  15. package/agents/agentic/performance-analyst.md +702 -0
  16. package/agents/agentic/safety-reviewer.md +662 -0
  17. package/agents/crew/implementer.md +163 -0
  18. package/agents/crew/researcher.md +94 -0
  19. package/agents/crew/reviewer.md +184 -0
  20. package/agents/data/data-engineer.md +227 -0
  21. package/agents/engineering/api-documentarian.md +440 -0
  22. package/agents/engineering/migration-engineer.md +301 -0
  23. package/agents/engineering/solution-architect.md +208 -0
  24. package/agents/jam/brainstorm-facilitator.md +297 -0
  25. package/agents/jam/council.md +322 -0
  26. package/agents/jam/quick-facilitator.md +85 -0
  27. package/agents/persona/persona-agent.md +121 -0
  28. package/agents/platform/compliance-officer.md +266 -0
  29. package/agents/platform/privacy-expert.md +496 -0
  30. package/agents/platform/security-engineer.md +287 -0
  31. package/agents/product/a11y-expert.md +323 -0
  32. package/agents/product/requirements-analyst.md +238 -0
  33. package/agents/product/ui-reviewer.md +180 -0
  34. package/agents/product/ux-designer.md +199 -0
  35. package/agents/product/value-strategist.md +269 -0
  36. package/agents/qe/semantic-reviewer.md +78 -0
  37. package/commands/agentic/audit.md +24 -0
  38. package/commands/agentic/design.md +24 -0
  39. package/commands/agentic/frameworks.md +25 -0
  40. package/commands/agentic/review.md +27 -0
  41. package/commands/archetype/build.md +12 -0
  42. package/commands/archetype/decide.md +12 -0
  43. package/commands/archetype/explore.md +12 -0
  44. package/commands/archetype/incident.md +12 -0
  45. package/commands/archetype/migrate.md +12 -0
  46. package/commands/archetype/modernize.md +12 -0
  47. package/commands/archetype/review.md +14 -0
  48. package/commands/archetype/ship.md +12 -0
  49. package/commands/archetype/specify.md +12 -0
  50. package/commands/archetype/triage.md +12 -0
  51. package/commands/compile.md +37 -0
  52. package/commands/data/analyze.md +18 -0
  53. package/commands/data/data.md +21 -0
  54. package/commands/data/ml.md +18 -0
  55. package/commands/data/ontology.md +22 -0
  56. package/commands/data/pipeline.md +17 -0
  57. package/commands/deliberate.md +181 -0
  58. package/commands/engineering/add-field.md +77 -0
  59. package/commands/engineering/apply.md +58 -0
  60. package/commands/engineering/arch.md +26 -0
  61. package/commands/engineering/debug.md +27 -0
  62. package/commands/engineering/docs.md +27 -0
  63. package/commands/engineering/new-generator.md +257 -0
  64. package/commands/engineering/patch-plan.md +59 -0
  65. package/commands/engineering/plan.md +29 -0
  66. package/commands/engineering/remove.md +48 -0
  67. package/commands/engineering/rename.md +44 -0
  68. package/commands/engineering/review.md +32 -0
  69. package/commands/help.md +128 -0
  70. package/commands/install.md +118 -0
  71. package/commands/intent.md +54 -0
  72. package/commands/jam/brainstorm.md +37 -0
  73. package/commands/jam/council.md +49 -0
  74. package/commands/jam/quick.md +21 -0
  75. package/commands/jam/revisit.md +79 -0
  76. package/commands/persona/as.md +136 -0
  77. package/commands/persona/define.md +24 -0
  78. package/commands/persona/list.md +118 -0
  79. package/commands/platform/actions.md +20 -0
  80. package/commands/platform/assert.md +18 -0
  81. package/commands/platform/audit.md +23 -0
  82. package/commands/platform/compliance.md +20 -0
  83. package/commands/platform/gh.md +22 -0
  84. package/commands/platform/health.md +22 -0
  85. package/commands/platform/incident.md +23 -0
  86. package/commands/platform/infra.md +24 -0
  87. package/commands/platform/peer-health.md +103 -0
  88. package/commands/platform/plugin-health.md +58 -0
  89. package/commands/platform/security.md +38 -0
  90. package/commands/platform/toolchain.md +96 -0
  91. package/commands/platform/traces.md +20 -0
  92. package/commands/product/a11y.md +19 -0
  93. package/commands/product/acceptance.md +19 -0
  94. package/commands/product/align.md +20 -0
  95. package/commands/product/analyze.md +23 -0
  96. package/commands/product/elicit.md +19 -0
  97. package/commands/product/listen.md +24 -0
  98. package/commands/product/mockup.md +20 -0
  99. package/commands/product/screenshot.md +19 -0
  100. package/commands/product/strategy.md +40 -0
  101. package/commands/product/synthesize.md +23 -0
  102. package/commands/product/ux-review.md +42 -0
  103. package/commands/product/ux.md +20 -0
  104. package/commands/product/visual-direction.md +34 -0
  105. package/commands/prove.md +47 -0
  106. package/commands/report-issue.md +243 -0
  107. package/commands/reset.md +144 -0
  108. package/commands/search/blast-radius.md +58 -0
  109. package/commands/search/hotspots.md +55 -0
  110. package/commands/search/index.md +38 -0
  111. package/commands/search/lineage.md +47 -0
  112. package/commands/search/service-map.md +79 -0
  113. package/commands/setup.md +363 -0
  114. package/commands/smaht/briefing.md +200 -0
  115. package/commands/smaht/events-import.md +95 -0
  116. package/commands/smaht/state.md +19 -0
  117. package/commands/where-am-i.md +58 -0
  118. package/docs/README.md +32 -0
  119. package/docs/adr/0001-code-relationship-graph-engine.md +116 -0
  120. package/docs/adr/0002-major-cleanup-keep-cut.md +91 -0
  121. package/docs/adr/0003-peers-gate-required-layers-optin.md +41 -0
  122. package/docs/adr/0004-code-graph-moves-to-wicked-brain.md +47 -0
  123. package/docs/brain-chunk-format.md +135 -0
  124. package/docs/compiler.md +95 -0
  125. package/docs/daemon-api.md +70 -0
  126. package/docs/domains.md +197 -0
  127. package/docs/getting-started.md +208 -0
  128. package/docs/plans/2026-06-08-wicked-loom-conduct.md +1337 -0
  129. package/docs/plans/2026-06-08-wicked-loom-contract.md +638 -0
  130. package/docs/plans/2026-06-08-wicked-loom-cutover.md +1300 -0
  131. package/docs/plans/2026-06-08-wicked-loom-expand-compose.md +843 -0
  132. package/docs/plans/2026-06-08-wicked-loom-flow-cutover.md +403 -0
  133. package/docs/plans/2026-06-10-codegraph-to-brain-phase1a-graph-core.md +838 -0
  134. package/docs/plans/2026-06-10-codegraph-to-brain-phase1b-injected-edges.md +44 -0
  135. package/docs/required-peers.md +60 -0
  136. package/docs/specs/2026-06-08-wicked-loom-extraction.md +225 -0
  137. package/docs/specs/2026-06-10-codegraph-to-brain-migration.md +168 -0
  138. package/docs/v11/archetypes.md +231 -0
  139. package/hooks/hooks.json +275 -0
  140. package/hooks/scripts/bootstrap.py +1797 -0
  141. package/hooks/scripts/invoke.py +62 -0
  142. package/hooks/scripts/notification.py +166 -0
  143. package/hooks/scripts/permission_request.py +223 -0
  144. package/hooks/scripts/post_tool.py +1374 -0
  145. package/hooks/scripts/pre_compact.py +272 -0
  146. package/hooks/scripts/pre_tool.py +1278 -0
  147. package/hooks/scripts/prompt_submit.py +1109 -0
  148. package/hooks/scripts/session_end.py +95 -0
  149. package/hooks/scripts/stop.py +624 -0
  150. package/hooks/scripts/subagent_lifecycle.py +464 -0
  151. package/hooks/scripts/subscribers/on_gate_decided.py +84 -0
  152. package/hooks/scripts/task_completed.py +322 -0
  153. package/hooks/scripts/worktree_guard.py +148 -0
  154. package/hooks/subscriptions/on_gate_decided.json +9 -0
  155. package/install.mjs +128 -0
  156. package/package.json +41 -0
  157. package/pyproject.toml +59 -0
  158. package/schemas/README.md +32 -0
  159. package/schemas/assert_contracts.json +37 -0
  160. package/schemas/health_probe.json +46 -0
  161. package/schemas/plugin_status.json +37 -0
  162. package/scripts/_adapters/__init__.py +166 -0
  163. package/scripts/_adapters/jira_adapter.py +18 -0
  164. package/scripts/_adapters/linear_adapter.py +18 -0
  165. package/scripts/_adapters/miro_adapter.py +18 -0
  166. package/scripts/_adapters/notion_adapter.py +18 -0
  167. package/scripts/_agents.py +357 -0
  168. package/scripts/_brain_ingest/__init__.py +2 -0
  169. package/scripts/_brain_ingest/session_fact_extractor.py +341 -0
  170. package/scripts/_brain_port.py +163 -0
  171. package/scripts/_bus.py +1081 -0
  172. package/scripts/_bus_catalog_gen.py +93 -0
  173. package/scripts/_bus_consumers.json +46 -0
  174. package/scripts/_bus_emit.py +43 -0
  175. package/scripts/_capability_registry.py +334 -0
  176. package/scripts/_capability_resolver.py +322 -0
  177. package/scripts/_domain_store.py +559 -0
  178. package/scripts/_event_log_reader.py +154 -0
  179. package/scripts/_event_schema.py +305 -0
  180. package/scripts/_event_store.py +397 -0
  181. package/scripts/_heavy_cadence.py +324 -0
  182. package/scripts/_integration_resolver.py +321 -0
  183. package/scripts/_logger.py +151 -0
  184. package/scripts/_loom.py +482 -0
  185. package/scripts/_paths.py +133 -0
  186. package/scripts/_python.sh +22 -0
  187. package/scripts/_run.py +137 -0
  188. package/scripts/_session.py +502 -0
  189. package/scripts/_validate_registry.py +1042 -0
  190. package/scripts/_wicked_testing_probe.py +277 -0
  191. package/scripts/agentic/analyze_agents.py +391 -0
  192. package/scripts/agentic/detect_framework.py +420 -0
  193. package/scripts/agentic/issue_taxonomy.py +357 -0
  194. package/scripts/agentic/pattern_scorer.py +434 -0
  195. package/scripts/classify/persist.py +169 -0
  196. package/scripts/compiler/compile.py +552 -0
  197. package/scripts/compiler/phase0/VERDICT.md +60 -0
  198. package/scripts/compiler/phase0/detect.py +292 -0
  199. package/scripts/compiler/phase0/emit.py +228 -0
  200. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.bindings.json +30 -0
  201. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.lint-output.txt +17 -0
  202. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/failing-tests.txt +4 -0
  203. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/.wg/evidence/honest-tests.txt +2 -0
  204. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-fail.build.md +8 -0
  205. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/fab-missing.build.md +8 -0
  206. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/honest.build.md +8 -0
  207. package/scripts/compiler/phase0/evidence/Enterprise-AISDLC.stage/wg_check_claims.py +174 -0
  208. package/scripts/compiler/phase0/evidence/command_iq.bindings.json +45 -0
  209. package/scripts/compiler/phase0/evidence/command_iq.lint-output.txt +17 -0
  210. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/failing-tests.txt +4 -0
  211. package/scripts/compiler/phase0/evidence/command_iq.stage/.projects/evidence-domain/phase-1-clarify/evidence/honest-tests.txt +3 -0
  212. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-fail.build.md +8 -0
  213. package/scripts/compiler/phase0/evidence/command_iq.stage/fab-missing.build.md +8 -0
  214. package/scripts/compiler/phase0/evidence/command_iq.stage/honest.build.md +8 -0
  215. package/scripts/compiler/phase0/evidence/command_iq.stage/wg_check_claims.py +174 -0
  216. package/scripts/compiler/phase0/evidence/memos.bindings.json +28 -0
  217. package/scripts/compiler/phase0/evidence/memos.lint-output.txt +17 -0
  218. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/failing-tests.txt +4 -0
  219. package/scripts/compiler/phase0/evidence/memos.stage/.wg/evidence/honest-tests.txt +2 -0
  220. package/scripts/compiler/phase0/evidence/memos.stage/fab-fail.build.md +8 -0
  221. package/scripts/compiler/phase0/evidence/memos.stage/fab-missing.build.md +8 -0
  222. package/scripts/compiler/phase0/evidence/memos.stage/honest.build.md +8 -0
  223. package/scripts/compiler/phase0/evidence/memos.stage/wg_check_claims.py +174 -0
  224. package/scripts/compiler/phase0/evidence/verdict.json +104 -0
  225. package/scripts/compiler/phase0/evidence/wicked-bus.bindings.json +29 -0
  226. package/scripts/compiler/phase0/evidence/wicked-bus.lint-output.txt +17 -0
  227. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/failing-tests.txt +4 -0
  228. package/scripts/compiler/phase0/evidence/wicked-bus.stage/coverage/honest-tests.txt +3 -0
  229. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-fail.build.md +8 -0
  230. package/scripts/compiler/phase0/evidence/wicked-bus.stage/fab-missing.build.md +8 -0
  231. package/scripts/compiler/phase0/evidence/wicked-bus.stage/honest.build.md +8 -0
  232. package/scripts/compiler/phase0/evidence/wicked-bus.stage/wg_check_claims.py +174 -0
  233. package/scripts/compiler/phase0/evidence/wire-vault-transcript.txt +60 -0
  234. package/scripts/compiler/phase0/run_probe.py +234 -0
  235. package/scripts/compiler/phase0/wire_vault.py +310 -0
  236. package/scripts/crew/__init__.py +0 -0
  237. package/scripts/crew/_task_audit_writer.py +243 -0
  238. package/scripts/crew/_task_reader.py +389 -0
  239. package/scripts/crew/archetypes_v11.py +348 -0
  240. package/scripts/crew/detectors/__init__.py +12 -0
  241. package/scripts/crew/flow_compiler.py +121 -0
  242. package/scripts/crew/phase_manager.py +703 -0
  243. package/scripts/crew/scope_delta.py +264 -0
  244. package/scripts/crew/specialist_resolver.py +218 -0
  245. package/scripts/crew/stack_registry.py +189 -0
  246. package/scripts/data/data_profiler.py +271 -0
  247. package/scripts/data/ontology_recommender.py +231 -0
  248. package/scripts/data/schema_validator.py +267 -0
  249. package/scripts/delivery/drift.py +739 -0
  250. package/scripts/delivery/telemetry.py +614 -0
  251. package/scripts/engineering/patch/codegraph_db.py +125 -0
  252. package/scripts/engineering/patch/generators/__init__.py +56 -0
  253. package/scripts/engineering/patch/generators/base.py +373 -0
  254. package/scripts/engineering/patch/generators/csharp_generator.py +494 -0
  255. package/scripts/engineering/patch/generators/go_generator.py +430 -0
  256. package/scripts/engineering/patch/generators/java_generator.py +928 -0
  257. package/scripts/engineering/patch/generators/jsp_generator.py +454 -0
  258. package/scripts/engineering/patch/generators/kotlin_generator.py +561 -0
  259. package/scripts/engineering/patch/generators/perl_generator.py +510 -0
  260. package/scripts/engineering/patch/generators/php_generator.py +644 -0
  261. package/scripts/engineering/patch/generators/propagation_engine.py +929 -0
  262. package/scripts/engineering/patch/generators/python_generator.py +487 -0
  263. package/scripts/engineering/patch/generators/ruby_generator.py +463 -0
  264. package/scripts/engineering/patch/generators/rust_generator.py +400 -0
  265. package/scripts/engineering/patch/generators/sql_generator.py +594 -0
  266. package/scripts/engineering/patch/generators/typescript_generator.py +439 -0
  267. package/scripts/engineering/patch/patch.py +800 -0
  268. package/scripts/engineering/patch/safety.py +429 -0
  269. package/scripts/jam/__init__.py +0 -0
  270. package/scripts/jam/_bus_consumers.py +271 -0
  271. package/scripts/jam/agentic_cli_registry.py +703 -0
  272. package/scripts/jam/consensus.py +737 -0
  273. package/scripts/jam/detect_clis.py +409 -0
  274. package/scripts/jam/jam.py +283 -0
  275. package/scripts/jam/save_transcript.py +171 -0
  276. package/scripts/loom/__init__.py +22 -0
  277. package/scripts/loom/cli.py +170 -0
  278. package/scripts/loom/compose.py +180 -0
  279. package/scripts/loom/gate.py +120 -0
  280. package/scripts/loom/manifest.py +140 -0
  281. package/scripts/loom/resolve.py +59 -0
  282. package/scripts/persona/__init__.py +0 -0
  283. package/scripts/persona/registry.py +688 -0
  284. package/scripts/platform/guard_pipeline.py +1214 -0
  285. package/scripts/platform/guard_profiles.py +216 -0
  286. package/scripts/platform/observability/assert_contracts.py +434 -0
  287. package/scripts/platform/observability/health_probe.py +915 -0
  288. package/scripts/platform/observability/ops_log_viewer.py +209 -0
  289. package/scripts/platform/prereq_doctor.py +567 -0
  290. package/scripts/qe/conditions_manifest.py +260 -0
  291. package/scripts/qe/content_sanitizer.py +160 -0
  292. package/scripts/qe/coverage_tracker.py +535 -0
  293. package/scripts/qe/discover_scenarios.py +243 -0
  294. package/scripts/qe/evidence_tracker.py +232 -0
  295. package/scripts/qe/prove.py +196 -0
  296. package/scripts/qe/registry_lookup.py +80 -0
  297. package/scripts/qe/registry_store.py +176 -0
  298. package/scripts/qe/semantic_review.py +1005 -0
  299. package/scripts/qe/vault_gate.py +382 -0
  300. package/scripts/qe/verdict_audit.py +175 -0
  301. package/scripts/qe/verdict_schema.py +335 -0
  302. package/scripts/reset.py +220 -0
  303. package/scripts/resolve_path.py +22 -0
  304. package/scripts/sentinel/invariants.py +402 -0
  305. package/scripts/sentinel/pre_push.py +73 -0
  306. package/scripts/setup/__init__.py +1 -0
  307. package/scripts/setup/detect_state.py +114 -0
  308. package/scripts/setup/migrate_legacy.py +67 -0
  309. package/scripts/setup/migrate_v6_projects.py +232 -0
  310. package/scripts/setup/onboarding.py +114 -0
  311. package/scripts/smaht/_bus_consumers.py +98 -0
  312. package/scripts/smaht/adapters/__init__.py +83 -0
  313. package/scripts/smaht/adapters/brain_adapter.py +254 -0
  314. package/scripts/smaht/adapters/context7_adapter.py +438 -0
  315. package/scripts/smaht/adapters/delegation_adapter.py +104 -0
  316. package/scripts/smaht/adapters/domain_adapter.py +206 -0
  317. package/scripts/smaht/adapters/events_adapter.py +231 -0
  318. package/scripts/smaht/adapters/tools_adapter.py +49 -0
  319. package/scripts/smaht/cheatsheet_store.py +236 -0
  320. package/scripts/smaht/context_package.py +386 -0
  321. package/scripts/smaht/knowledge_graph.py +395 -0
  322. package/scripts/smaht/propose_skills.py +856 -0
  323. package/scripts/smaht/test_cheatsheet_store.py +428 -0
  324. package/scripts/statusline.py +151 -0
  325. package/scripts/where_am_i.py +236 -0
  326. package/skills/agentic/agentic-patterns/SKILL.md +91 -0
  327. package/skills/agentic/agentic-patterns/refs/anti-patterns-design.md +283 -0
  328. package/skills/agentic/agentic-patterns/refs/anti-patterns-operational.md +216 -0
  329. package/skills/agentic/agentic-patterns/refs/pattern-catalog.md +329 -0
  330. package/skills/agentic/context-engineering/SKILL.md +142 -0
  331. package/skills/agentic/context-engineering/refs/caching-and-optimization.md +251 -0
  332. package/skills/agentic/context-engineering/refs/compression-techniques.md +171 -0
  333. package/skills/agentic/context-engineering/refs/cost-calculation-budget.md +250 -0
  334. package/skills/agentic/context-engineering/refs/cost-optimization-reporting.md +300 -0
  335. package/skills/agentic/context-engineering/refs/selective-loading.md +179 -0
  336. package/skills/agentic/frameworks/SKILL.md +191 -0
  337. package/skills/agentic/frameworks/refs/framework-profiles-1.md +209 -0
  338. package/skills/agentic/frameworks/refs/framework-profiles-2.md +214 -0
  339. package/skills/agentic/frameworks/refs/migration-patterns-paths.md +267 -0
  340. package/skills/agentic/frameworks/refs/migration-patterns-testing.md +208 -0
  341. package/skills/agentic/refs/audit.md +134 -0
  342. package/skills/agentic/refs/design.md +137 -0
  343. package/skills/agentic/refs/frameworks.md +102 -0
  344. package/skills/agentic/refs/review.md +160 -0
  345. package/skills/agentic/review-methodology/SKILL.md +186 -0
  346. package/skills/agentic/review-methodology/refs/deliverable-templates.md +246 -0
  347. package/skills/agentic/review-methodology/refs/issue-taxonomy-quality-testing.md +277 -0
  348. package/skills/agentic/review-methodology/refs/issue-taxonomy-reliability-safety.md +253 -0
  349. package/skills/agentic/trust-and-safety/SKILL.md +177 -0
  350. package/skills/agentic/trust-and-safety/refs/guardrails-actions.md +246 -0
  351. package/skills/agentic/trust-and-safety/refs/guardrails-input-output.md +238 -0
  352. package/skills/agentic/trust-and-safety/refs/guardrails-resources.md +209 -0
  353. package/skills/agentic/trust-and-safety/refs/safety-checklist-advanced.md +209 -0
  354. package/skills/agentic/trust-and-safety/refs/safety-checklist-core.md +215 -0
  355. package/skills/archetype/SKILL.md +104 -0
  356. package/skills/archetype/refs/build.md +142 -0
  357. package/skills/archetype/refs/decide.md +117 -0
  358. package/skills/archetype/refs/explore.md +66 -0
  359. package/skills/archetype/refs/incident.md +149 -0
  360. package/skills/archetype/refs/migrate.md +170 -0
  361. package/skills/archetype/refs/modernize.md +187 -0
  362. package/skills/archetype/refs/review.md +145 -0
  363. package/skills/archetype/refs/ship.md +117 -0
  364. package/skills/archetype/refs/specify.md +108 -0
  365. package/skills/archetype/refs/triage.md +62 -0
  366. package/skills/classify/SKILL.md +157 -0
  367. package/skills/data/analysis/SKILL.md +125 -0
  368. package/skills/data/analysis/refs/templates.md +170 -0
  369. package/skills/data/data/SKILL.md +118 -0
  370. package/skills/data/data/refs/examples.md +235 -0
  371. package/skills/data/ml/SKILL.md +125 -0
  372. package/skills/data/ml/refs/templates.md +172 -0
  373. package/skills/data/pipeline/SKILL.md +136 -0
  374. package/skills/data/pipeline/refs/templates.md +175 -0
  375. package/skills/data/refs/analyze.md +123 -0
  376. package/skills/data/refs/data.md +95 -0
  377. package/skills/data/refs/ml.md +118 -0
  378. package/skills/data/refs/pipeline.md +92 -0
  379. package/skills/deliberate/SKILL.md +125 -0
  380. package/skills/deliberate/refs/architecture-lens.md +37 -0
  381. package/skills/deliberate/refs/assumptions-lens.md +43 -0
  382. package/skills/deliberate/refs/code-lens.md +38 -0
  383. package/skills/deliberate/refs/content-lens.md +37 -0
  384. package/skills/deliberate/refs/data-lens.md +43 -0
  385. package/skills/deliberate/refs/design-lens.md +37 -0
  386. package/skills/deliberate/refs/opportunity-patterns.md +107 -0
  387. package/skills/deliberate/refs/ops-lens.md +43 -0
  388. package/skills/deliberate/refs/product-lens.md +46 -0
  389. package/skills/deliberate/refs/rethink-framework.md +77 -0
  390. package/skills/deliberate/refs/security-lens.md +47 -0
  391. package/skills/deliberate/refs/testing-lens.md +45 -0
  392. package/skills/deliberate/refs/timing-lens.md +42 -0
  393. package/skills/engineering/architecture/SKILL.md +177 -0
  394. package/skills/engineering/architecture/refs/adr-template.md +268 -0
  395. package/skills/engineering/architecture/refs/architecture-template-deployment.md +176 -0
  396. package/skills/engineering/architecture/refs/architecture-template-design.md +300 -0
  397. package/skills/engineering/architecture/refs/examples-ecommerce-analytics.md +299 -0
  398. package/skills/engineering/architecture/refs/examples-saas-trading.md +291 -0
  399. package/skills/engineering/architecture/refs/patterns-advanced.md +238 -0
  400. package/skills/engineering/architecture/refs/patterns-structural.md +303 -0
  401. package/skills/engineering/backend/SKILL.md +102 -0
  402. package/skills/engineering/backend/refs/checklists.md +146 -0
  403. package/skills/engineering/backend/refs/patterns.md +181 -0
  404. package/skills/engineering/debugging/SKILL.md +99 -0
  405. package/skills/engineering/debugging/refs/patterns.md +248 -0
  406. package/skills/engineering/debugging/refs/process.md +203 -0
  407. package/skills/engineering/docs/SKILL.md +97 -0
  408. package/skills/engineering/engineering/SKILL.md +88 -0
  409. package/skills/engineering/engineering/refs/checklists.md +91 -0
  410. package/skills/engineering/engineering/refs/templates.md +71 -0
  411. package/skills/engineering/frontend/SKILL.md +92 -0
  412. package/skills/engineering/frontend/refs/checklists.md +96 -0
  413. package/skills/engineering/frontend/refs/patterns.md +167 -0
  414. package/skills/engineering/integration/SKILL.md +183 -0
  415. package/skills/engineering/integration/refs/error-handling-best-practices.md +139 -0
  416. package/skills/engineering/integration/refs/error-handling-error-classes-typescript.md +212 -0
  417. package/skills/engineering/integration/refs/error-handling-error-response-format.md +301 -0
  418. package/skills/engineering/integration/refs/error-handling-retry-strategies.md +190 -0
  419. package/skills/engineering/integration/refs/event-schemas-best-practices.md +225 -0
  420. package/skills/engineering/integration/refs/event-schemas-event-naming-conventions.md +303 -0
  421. package/skills/engineering/integration/refs/event-schemas-event-structure.md +288 -0
  422. package/skills/engineering/integration/refs/graphql-best-practices.md +138 -0
  423. package/skills/engineering/integration/refs/graphql-error-handling.md +198 -0
  424. package/skills/engineering/integration/refs/graphql-graphql-basics.md +197 -0
  425. package/skills/engineering/integration/refs/graphql-query-examples.md +226 -0
  426. package/skills/engineering/integration/refs/graphql-schema-design-patterns.md +280 -0
  427. package/skills/engineering/integration/refs/grpc-grpc-overview.md +246 -0
  428. package/skills/engineering/integration/refs/grpc-implementation-examples.md +269 -0
  429. package/skills/engineering/integration/refs/grpc-metadata-headers.md +304 -0
  430. package/skills/engineering/integration/refs/grpc-testing.md +49 -0
  431. package/skills/engineering/integration/refs/openapi-template.yaml +682 -0
  432. package/skills/engineering/integration/refs/resilience-best-practices.md +109 -0
  433. package/skills/engineering/integration/refs/resilience-circuit-breaker-pattern.md +302 -0
  434. package/skills/engineering/integration/refs/resilience-rate-limiting.md +245 -0
  435. package/skills/engineering/integration/refs/resilience-timeout-pattern.md +212 -0
  436. package/skills/engineering/integration/refs/rest-api-fundamentals.md +299 -0
  437. package/skills/engineering/integration/refs/rest-api-responses-security.md +302 -0
  438. package/skills/engineering/integration/refs/versioning-breaking-changes.md +237 -0
  439. package/skills/engineering/integration/refs/versioning-migration-strategies.md +257 -0
  440. package/skills/engineering/integration/refs/versioning-versioning-strategies.md +296 -0
  441. package/skills/engineering/large-scale-migration/SKILL.md +65 -0
  442. package/skills/engineering/patch/SKILL.md +184 -0
  443. package/skills/engineering/refs/arch.md +126 -0
  444. package/skills/engineering/refs/debug.md +142 -0
  445. package/skills/engineering/refs/docs.md +190 -0
  446. package/skills/engineering/refs/plan.md +109 -0
  447. package/skills/engineering/refs/review.md +138 -0
  448. package/skills/engineering/system-design/SKILL.md +154 -0
  449. package/skills/engineering/system-design/refs/anti-patterns-big-ball-of-mud.md +254 -0
  450. package/skills/engineering/system-design/refs/anti-patterns-circular-dependencies.md +241 -0
  451. package/skills/engineering/system-design/refs/anti-patterns-feature-envy.md +168 -0
  452. package/skills/engineering/system-design/refs/anti-patterns-god-object.md +247 -0
  453. package/skills/engineering/system-design/refs/component-template-lifecycle.md +210 -0
  454. package/skills/engineering/system-design/refs/component-template-maintenance.md +219 -0
  455. package/skills/engineering/system-design/refs/component-template-structure.md +276 -0
  456. package/skills/engineering/system-design/refs/dependencies-best-practices.md +260 -0
  457. package/skills/engineering/system-design/refs/dependencies-dependency-principles.md +295 -0
  458. package/skills/engineering/system-design/refs/dependencies-dependency-tracking.md +261 -0
  459. package/skills/engineering/system-design/refs/interface-template-lifecycle.md +211 -0
  460. package/skills/engineering/system-design/refs/interface-template-maintenance.md +212 -0
  461. package/skills/engineering/system-design/refs/interface-template-structure.md +269 -0
  462. package/skills/engineering/system-design/refs/patterns-dependency-injection.md +151 -0
  463. package/skills/engineering/system-design/refs/patterns-facade-pattern.md +257 -0
  464. package/skills/engineering/system-design/refs/patterns-layered-pattern.md +204 -0
  465. package/skills/engineering/system-design/refs/patterns-plugin-architecture.md +229 -0
  466. package/skills/engineering/unit-test-quality/SKILL.md +194 -0
  467. package/skills/ground/SKILL.md +130 -0
  468. package/skills/integration-discovery/SKILL.md +168 -0
  469. package/skills/integration-discovery/refs/capabilities.md +282 -0
  470. package/skills/integration-discovery/refs/cli-detection.md +295 -0
  471. package/skills/integration-discovery/refs/discovery-sources.md +233 -0
  472. package/skills/integration-discovery/refs/task-patterns.md +206 -0
  473. package/skills/jam/SKILL.md +45 -0
  474. package/skills/jam/refs/facilitation-patterns.md +125 -0
  475. package/skills/jam/refs/quick.md +64 -0
  476. package/skills/jam/refs/synthesis-patterns.md +114 -0
  477. package/skills/multi-model/SKILL.md +168 -0
  478. package/skills/multi-model/refs/aichat.md +119 -0
  479. package/skills/multi-model/refs/aider.md +100 -0
  480. package/skills/multi-model/refs/auditability.md +238 -0
  481. package/skills/multi-model/refs/codex.md +169 -0
  482. package/skills/multi-model/refs/context.md +306 -0
  483. package/skills/multi-model/refs/copilot.md +161 -0
  484. package/skills/multi-model/refs/examples.md +224 -0
  485. package/skills/multi-model/refs/gemini.md +185 -0
  486. package/skills/multi-model/refs/goose.md +112 -0
  487. package/skills/multi-model/refs/llm.md +124 -0
  488. package/skills/multi-model/refs/opencode.md +196 -0
  489. package/skills/multi-model/refs/orchestration.md +188 -0
  490. package/skills/multi-model/refs/pi.md +208 -0
  491. package/skills/persona/SKILL.md +144 -0
  492. package/skills/persona/refs/define.md +133 -0
  493. package/skills/platform/actions/refs/actions.md +114 -0
  494. package/skills/platform/audit/SKILL.md +174 -0
  495. package/skills/platform/audit/refs/audit.md +145 -0
  496. package/skills/platform/audit/refs/checklists-evidence-operations.md +144 -0
  497. package/skills/platform/audit/refs/checklists-gdpr-pci-evidence.md +213 -0
  498. package/skills/platform/audit/refs/checklists-soc2-hipaa.md +120 -0
  499. package/skills/platform/audit/refs/frameworks-gdpr-pci.md +225 -0
  500. package/skills/platform/audit/refs/frameworks-soc2-hipaa.md +228 -0
  501. package/skills/platform/compliance/SKILL.md +169 -0
  502. package/skills/platform/compliance/refs/checklists.md +303 -0
  503. package/skills/platform/compliance/refs/compliance.md +117 -0
  504. package/skills/platform/compliance/refs/frameworks.md +282 -0
  505. package/skills/platform/errors/SKILL.md +183 -0
  506. package/skills/platform/errors/refs/patterns.md +271 -0
  507. package/skills/platform/errors/refs/severity.md +264 -0
  508. package/skills/platform/gate-benchmark-rebaseline/SKILL.md +108 -0
  509. package/skills/platform/gh/refs/gh.md +105 -0
  510. package/skills/platform/gh-cli/SKILL.md +120 -0
  511. package/skills/platform/gh-cli/refs/automation.md +63 -0
  512. package/skills/platform/gh-cli/refs/gh-ops.md +103 -0
  513. package/skills/platform/gh-cli/refs/patterns.md +132 -0
  514. package/skills/platform/gh-cli/scripts/gh_ops.py +454 -0
  515. package/skills/platform/github-actions/SKILL.md +159 -0
  516. package/skills/platform/github-actions/refs/security.md +150 -0
  517. package/skills/platform/github-actions/refs/templates.md +230 -0
  518. package/skills/platform/github-actions/refs/troubleshooting.md +174 -0
  519. package/skills/platform/github-actions/scripts/workflow_gen.py +215 -0
  520. package/skills/platform/gitlab-ci/SKILL.md +140 -0
  521. package/skills/platform/gitlab-ci/refs/templates.md +223 -0
  522. package/skills/platform/gitlab-ci/refs/troubleshooting.md +213 -0
  523. package/skills/platform/glab-cli/SKILL.md +133 -0
  524. package/skills/platform/glab-cli/refs/ci-debugging.md +95 -0
  525. package/skills/platform/glab-cli/refs/glab-ops.md +78 -0
  526. package/skills/platform/glab-cli/refs/patterns.md +131 -0
  527. package/skills/platform/glab-cli/scripts/glab_ops.py +313 -0
  528. package/skills/platform/health/SKILL.md +177 -0
  529. package/skills/platform/health/refs/health.md +72 -0
  530. package/skills/platform/health/refs/sources.md +302 -0
  531. package/skills/platform/incident/refs/incident.md +136 -0
  532. package/skills/platform/infra/refs/infra.md +104 -0
  533. package/skills/platform/observability/SKILL.md +128 -0
  534. package/skills/platform/observability/refs/toolchain-discovery.md +243 -0
  535. package/skills/platform/prereq-doctor/SKILL.md +57 -0
  536. package/skills/platform/prereq-doctor/refs/tool-registry.md +58 -0
  537. package/skills/platform/traces/refs/traces.md +101 -0
  538. package/skills/product/acceptance-criteria/SKILL.md +193 -0
  539. package/skills/product/acceptance-criteria/refs/ac-anti-patterns.md +291 -0
  540. package/skills/product/acceptance-criteria/refs/ac-examples.md +277 -0
  541. package/skills/product/accessibility/SKILL.md +197 -0
  542. package/skills/product/accessibility/refs/aria-patterns-basics.md +250 -0
  543. package/skills/product/accessibility/refs/aria-patterns-dynamic.md +187 -0
  544. package/skills/product/accessibility/refs/aria-patterns-interactive.md +246 -0
  545. package/skills/product/accessibility/refs/audit-report-findings.md +248 -0
  546. package/skills/product/accessibility/refs/audit-report-results.md +276 -0
  547. package/skills/product/accessibility/refs/common-violations-html-css.md +270 -0
  548. package/skills/product/accessibility/refs/common-violations-interactive.md +303 -0
  549. package/skills/product/accessibility/refs/keyboard-testing-basics.md +222 -0
  550. package/skills/product/accessibility/refs/keyboard-testing-patterns.md +173 -0
  551. package/skills/product/accessibility/refs/screen-reader-testing-advanced.md +294 -0
  552. package/skills/product/accessibility/refs/screen-reader-testing-commands.md +255 -0
  553. package/skills/product/accessibility/refs/wcag-checklist.md +262 -0
  554. package/skills/product/analyze/SKILL.md +164 -0
  555. package/skills/product/analyze/refs/algorithms.md +238 -0
  556. package/skills/product/analyze/refs/sentiment-patterns.md +180 -0
  557. package/skills/product/imagery/SKILL.md +97 -0
  558. package/skills/product/imagery/alter/SKILL.md +105 -0
  559. package/skills/product/imagery/alter/refs/editing-reference.md +146 -0
  560. package/skills/product/imagery/create/SKILL.md +109 -0
  561. package/skills/product/imagery/create/refs/prompt-engineering.md +112 -0
  562. package/skills/product/imagery/create/refs/provider-reference.md +219 -0
  563. package/skills/product/imagery/review/SKILL.md +101 -0
  564. package/skills/product/imagery/review/refs/analysis-lenses.md +136 -0
  565. package/skills/product/imagery/review/refs/quality-gates.md +153 -0
  566. package/skills/product/imagery/scripts/analyze.sh +23 -0
  567. package/skills/product/imagery/scripts/edit.sh +14 -0
  568. package/skills/product/imagery/scripts/generate.sh +13 -0
  569. package/skills/product/imagery/scripts/provider.py +787 -0
  570. package/skills/product/listen/SKILL.md +175 -0
  571. package/skills/product/listen/refs/channels.md +220 -0
  572. package/skills/product/mockup/SKILL.md +106 -0
  573. package/skills/product/mockup/refs/templates.md +95 -0
  574. package/skills/product/refs/a11y.md +109 -0
  575. package/skills/product/refs/acceptance.md +79 -0
  576. package/skills/product/refs/align.md +67 -0
  577. package/skills/product/refs/analyze.md +77 -0
  578. package/skills/product/refs/elicit.md +67 -0
  579. package/skills/product/refs/listen.md +58 -0
  580. package/skills/product/refs/mockup.md +77 -0
  581. package/skills/product/refs/screenshot.md +59 -0
  582. package/skills/product/refs/strategy.md +77 -0
  583. package/skills/product/refs/synthesize.md +54 -0
  584. package/skills/product/refs/ux-review.md +68 -0
  585. package/skills/product/refs/ux.md +101 -0
  586. package/skills/product/requirements-analysis/SKILL.md +136 -0
  587. package/skills/product/requirements-analysis/refs/requirements-example-auth.md +264 -0
  588. package/skills/product/requirements-analysis/refs/requirements-example-export-integration.md +88 -0
  589. package/skills/product/requirements-analysis/refs/requirements-output-format-template.md +247 -0
  590. package/skills/product/requirements-analysis/refs/user-story-guide.md +296 -0
  591. package/skills/product/requirements-graph/SKILL.md +155 -0
  592. package/skills/product/requirements-graph/refs/examples.md +223 -0
  593. package/skills/product/requirements-graph/refs/schema.md +162 -0
  594. package/skills/product/requirements-migrate/SKILL.md +90 -0
  595. package/skills/product/requirements-navigate/SKILL.md +141 -0
  596. package/skills/product/requirements-navigate/refs/meta-templates.md +141 -0
  597. package/skills/product/screenshot/SKILL.md +147 -0
  598. package/skills/product/strategy/SKILL.md +198 -0
  599. package/skills/product/strategy/refs/frameworks.md +295 -0
  600. package/skills/product/strategy/refs/templates-competitive-market.md +299 -0
  601. package/skills/product/strategy/refs/templates-roi-value.md +207 -0
  602. package/skills/product/synthesize/SKILL.md +116 -0
  603. package/skills/product/synthesize/refs/journey-mapping.md +212 -0
  604. package/skills/product/synthesize/refs/prioritization.md +193 -0
  605. package/skills/product/ux-review/SKILL.md +164 -0
  606. package/skills/product/visual-direction/SKILL.md +137 -0
  607. package/skills/product/visual-review/SKILL.md +131 -0
  608. package/skills/runtime-exec/SKILL.md +138 -0
  609. package/skills/search/codebase-narrator/SKILL.md +131 -0
  610. package/skills/search/codebase-narrator/refs/output-template.md +100 -0
  611. package/skills/smaht/SKILL.md +72 -0
  612. package/skills/smaht/discovery/SKILL.md +65 -0
  613. package/skills/smaht/intent/SKILL.md +89 -0
  614. package/skills/smaht/propose-skills/SKILL.md +142 -0
  615. package/skills/smaht/refs/state.md +76 -0
  616. package/skills/swarm/SKILL.md +132 -0
  617. package/skills/swarm/refs/fan-out.md +104 -0
  618. package/skills/swarm/refs/independent-verification.md +86 -0
  619. package/skills/swarm/refs/receipts-and-evidence.md +69 -0
  620. package/skills/swarm/refs/recon-synthesis.md +87 -0
  621. package/skills/swarm/refs/ship-discipline.md +90 -0
  622. package/skills/wickedizer/SKILL.md +147 -0
  623. package/skills/wickedizer/refs/artifact-types.md +238 -0
  624. package/skills/wickedizer/refs/complexity.md +278 -0
  625. package/skills/wickedizer/refs/de-ai-pass.md +140 -0
  626. package/skills/wickedizer/refs/failure-modes.md +249 -0
  627. package/skills/wickedizer/refs/patterns.md +282 -0
  628. package/skills/wickedizer/refs/review.md +221 -0
  629. package/skills/wickedizer/refs/structure.md +282 -0
  630. package/skills/wickedizer/refs/voice-profile.md +125 -0
  631. package/skills/workflow/SKILL.md +132 -0
  632. package/skills/workflow/refs/archetype-adjustments.md +205 -0
  633. package/skills/workflow/refs/evidence.md +58 -0
  634. package/skills/workflow/refs/integration.md +130 -0
  635. package/skills/workflow/refs/risk-dimension-signals.md +260 -0
  636. package/skills/workflow/refs/scoring-rubric.md +49 -0
  637. package/skills/workflow/refs/signal-keywords.md +176 -0
  638. package/skills/workflow/refs/specialist-routing-rules.md +159 -0
  639. package/skills/worktrees/SKILL.md +87 -0
  640. package/skills/worktrees/refs/recipes.md +96 -0
@@ -0,0 +1,800 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ wicked-patch CLI - Language-agnostic code generation and change propagation.
4
+
5
+ Generates patches for code changes and propagates them across all affected files.
6
+ Symbol resolution uses wicked-brain's symbols/dependents API. Patch generation
7
+ (add-field, rename, remove) additionally requires --db for symbol-level graph traversal.
8
+
9
+ Usage:
10
+ # Plan what would be affected (brain-backed, no --db needed)
11
+ patch plan SYMBOL_ID --change add_field
12
+
13
+ # Plan with full symbol graph (requires local DB)
14
+ patch plan SYMBOL_ID --change add_field --db symbols.db
15
+
16
+ # Add a field to an entity/class
17
+ patch add-field SYMBOL_ID --name email --type String --column EMAIL --db symbols.db
18
+
19
+ # Rename a field across all usages
20
+ patch rename SYMBOL_ID --old status --new providerStatus --db symbols.db
21
+
22
+ # Remove a field everywhere
23
+ patch remove SYMBOL_ID --field deprecated_field --db symbols.db
24
+
25
+ # Apply generated patches
26
+ patch apply patches.json
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import argparse
32
+ import json
33
+ import sys
34
+ from pathlib import Path
35
+ from typing import Optional, List
36
+ from datetime import datetime
37
+
38
+ # Add patch dir for local imports (generators, safety) and scripts root for shared modules (_brain_port)
39
+ sys.path.insert(0, str(Path(__file__).resolve().parents[2])) # scripts/ — for _brain_port
40
+ sys.path.insert(0, str(Path(__file__).parent)) # scripts/engineering/patch/
41
+
42
+ from generators import (
43
+ ChangeSpec,
44
+ ChangeType,
45
+ FieldSpec,
46
+ PatchSet,
47
+ GeneratorRegistry,
48
+ )
49
+ from generators.propagation_engine import PropagationEngine, PropagationPlan
50
+ from safety import (
51
+ run_safety_checks,
52
+ TransactionalApplicator,
53
+ SafetyError,
54
+ GitSafetyChecker,
55
+ FreshnessChecker,
56
+ )
57
+
58
+
59
+ def _parse_version(v: str) -> tuple:
60
+ """Parse semver string to comparable tuple."""
61
+ import re
62
+ match = re.match(r"(\d+)\.(\d+)\.(\d+)", v)
63
+ if match:
64
+ return tuple(int(x) for x in match.groups())
65
+ return (0, 0, 0)
66
+
67
+
68
+ def _brain_api(action: str, params: dict, port: Optional[int] = None) -> dict:
69
+ """Call wicked-brain API. Returns empty dict on failure.
70
+
71
+ Port is auto-discovered from project brain configs unless overridden.
72
+ """
73
+ import urllib.request
74
+ if port is None:
75
+ try:
76
+ from _brain_port import resolve_port
77
+ port = resolve_port()
78
+ except ImportError:
79
+ print("warning: _brain_port not found, falling back to port 4242", file=sys.stderr)
80
+ port = 4242
81
+ try:
82
+ payload = json.dumps({"action": action, "params": params}).encode()
83
+ req = urllib.request.Request(
84
+ f"http://localhost:{port}/api",
85
+ data=payload,
86
+ headers={"Content-Type": "application/json"},
87
+ method="POST",
88
+ )
89
+ with urllib.request.urlopen(req, timeout=3) as resp:
90
+ return json.loads(resp.read().decode())
91
+ except Exception:
92
+ return {}
93
+
94
+
95
+ def _resolve_symbol_id(symbol_id: str, db_path: Optional[Path]) -> str:
96
+ """Resolve a partial symbol name to a full ID.
97
+
98
+ Tries brain's symbols API first (returns file_path::Name when LSP data
99
+ is available), then falls back to local SQLite if db_path is provided.
100
+ """
101
+ if not symbol_id or symbol_id.startswith("/") or "::" in symbol_id:
102
+ return symbol_id
103
+
104
+ # Try brain symbols API — fetch up to 10 to find one with a real file_path
105
+ # (FTS results often have file_path=null for chunk-indexed entries; LSP-indexed
106
+ # entries have the actual path and appear later in the result list)
107
+ result = _brain_api("symbols", {"name": symbol_id, "limit": 10})
108
+ for r in result.get("results", []):
109
+ if r.get("file_path"):
110
+ return r["id"] # format: "file_path::SymbolName"
111
+
112
+ # SQLite fallback
113
+ if db_path:
114
+ try:
115
+ import sqlite3
116
+ conn = sqlite3.connect(str(db_path))
117
+ conn.row_factory = sqlite3.Row
118
+ cursor = conn.cursor()
119
+ cursor.execute(
120
+ "SELECT id FROM symbols WHERE id LIKE ? LIMIT 1",
121
+ (f"%/{symbol_id}",),
122
+ )
123
+ row = cursor.fetchone()
124
+ conn.close()
125
+ if row:
126
+ return row["id"]
127
+ except Exception:
128
+ pass # fail open
129
+
130
+ return symbol_id
131
+
132
+
133
+ def _require_db(args_db: Optional[str]) -> Optional[Path]:
134
+ """Resolve db_path from --db flag or return None with an informative error."""
135
+ if args_db:
136
+ p = Path(args_db)
137
+ if not p.exists():
138
+ print(f"Error: Database not found at {p}", file=sys.stderr)
139
+ return None
140
+ return p
141
+
142
+ print(
143
+ "Error: patch generation requires a local symbol database.\n"
144
+ " Pass --db <path-to-symbol.db> to use a local SQLite symbol graph.\n"
145
+ " The 'plan' command works without --db using wicked-brain's symbol API.",
146
+ file=sys.stderr,
147
+ )
148
+ return None
149
+
150
+
151
+ def _assess_risk(plan: PropagationPlan, change_type: str = "") -> dict:
152
+ """Assess risk level, confidence, and breaking change potential."""
153
+ total = len(plan.all_affected)
154
+ files = len(plan.files_affected)
155
+ upstream = len(plan.upstream_impacts)
156
+
157
+ # Determine risk level
158
+ risk_reason = None
159
+ if change_type == "remove_field":
160
+ # Field removal is always a breaking change — even if no internal
161
+ # references are found, external consumers (APIs, serialization,
162
+ # database tools) may depend on the field.
163
+ risk_level = "HIGH"
164
+ if upstream == 0 and total <= 1:
165
+ risk_reason = "no_internal_refs"
166
+ elif change_type == "rename_field":
167
+ if upstream > 10 or files > 6:
168
+ risk_level = "HIGH"
169
+ elif upstream > 0 or files > 1:
170
+ risk_level = "MEDIUM"
171
+ else:
172
+ risk_level = "LOW"
173
+ # Orphaned field rename is as risky as removal — external consumers
174
+ # may depend on the old name via APIs, serialization, or DB schemas.
175
+ if upstream == 0 and total <= 1:
176
+ risk_level = "HIGH"
177
+ risk_reason = "no_internal_refs"
178
+ elif change_type == "add_field":
179
+ risk_level = "LOW"
180
+ else:
181
+ if total > 10 or files > 4:
182
+ risk_level = "HIGH"
183
+ elif total > 5 or files > 2:
184
+ risk_level = "MEDIUM"
185
+ else:
186
+ risk_level = "LOW"
187
+
188
+ # Determine confidence
189
+ if total > 0 and files > 0:
190
+ confidence = "HIGH"
191
+ elif total > 0:
192
+ confidence = "MEDIUM"
193
+ else:
194
+ confidence = "LOW"
195
+
196
+ # Detect breaking changes — removal is always breaking regardless of
197
+ # internal references; renames break when upstream consumers exist.
198
+ if change_type == "remove_field":
199
+ breaking = True
200
+ else:
201
+ breaking = change_type == "rename_field" and upstream > 0
202
+
203
+ # Check for test files in impacts
204
+ test_refs = sum(
205
+ 1 for s in plan.all_affected
206
+ if s.file_path and ("test" in s.file_path.lower() or "spec" in s.file_path.lower())
207
+ )
208
+
209
+ return {
210
+ "risk_level": risk_level,
211
+ "confidence": confidence,
212
+ "breaking": breaking,
213
+ "test_coverage": "GOOD" if test_refs > 0 else "NONE",
214
+ "test_refs": test_refs,
215
+ "risk_reason": risk_reason,
216
+ }
217
+
218
+
219
+ def format_plan(plan: PropagationPlan, change_type: str = "") -> str:
220
+ """Format a propagation plan for display."""
221
+ risk = _assess_risk(plan, change_type)
222
+
223
+ lines = [
224
+ "=" * 60,
225
+ "PROPAGATION PLAN",
226
+ "=" * 60,
227
+ "",
228
+ f"Source: {plan.source_symbol.name}",
229
+ f" Type: {plan.source_symbol.type}",
230
+ f" File: {plan.source_symbol.file_path}",
231
+ f" Line: {plan.source_symbol.line_start}",
232
+ "",
233
+ ]
234
+
235
+ if plan.direct_impacts:
236
+ lines.append(f"Direct Impacts ({len(plan.direct_impacts)}):")
237
+ for s in plan.direct_impacts[:10]:
238
+ lines.append(f" - {s.name} ({s.type}) @ {Path(s.file_path).name if s.file_path else 'N/A'}")
239
+ if len(plan.direct_impacts) > 10:
240
+ lines.append(f" ... and {len(plan.direct_impacts) - 10} more")
241
+ lines.append("")
242
+
243
+ if plan.upstream_impacts:
244
+ lines.append(f"Upstream Impacts ({len(plan.upstream_impacts)}):")
245
+ for s in plan.upstream_impacts[:10]:
246
+ lines.append(f" - {s.name} ({s.type}) @ {Path(s.file_path).name if s.file_path else 'N/A'}")
247
+ if len(plan.upstream_impacts) > 10:
248
+ lines.append(f" ... and {len(plan.upstream_impacts) - 10} more")
249
+ lines.append("")
250
+
251
+ if plan.downstream_impacts:
252
+ lines.append(f"Downstream Impacts ({len(plan.downstream_impacts)}):")
253
+ for s in plan.downstream_impacts[:10]:
254
+ lines.append(f" - {s.name} ({s.type}) @ {Path(s.file_path).name if s.file_path else 'N/A'}")
255
+ if len(plan.downstream_impacts) > 10:
256
+ lines.append(f" ... and {len(plan.downstream_impacts) - 10} more")
257
+ lines.append("")
258
+
259
+ # Risk assessment section
260
+ lines.append("-" * 60)
261
+ lines.append("Risk Assessment:")
262
+ lines.append(f" Risk level: {risk['risk_level']}")
263
+ lines.append(f" Confidence: {risk['confidence']}")
264
+ if risk["breaking"]:
265
+ lines.append(f" Breaking change: YES (affects {len(plan.upstream_impacts)} upstream dependencies)")
266
+ else:
267
+ lines.append(f" Breaking change: NO")
268
+ lines.append(f" Test coverage: {risk['test_coverage']} ({risk['test_refs']} test references found)")
269
+ if risk.get("risk_reason") == "no_internal_refs":
270
+ lines.append(" WARNING: Field has no internal references — may be used by external API clients or database tools")
271
+ lines.append(" Audit API contracts and external integrations before proceeding")
272
+ lines.append("")
273
+
274
+ lines.extend([
275
+ "-" * 60,
276
+ f"Total: {len(plan.all_affected)} symbols in {len(plan.files_affected)} files",
277
+ "=" * 60,
278
+ ])
279
+
280
+ return "\n".join(lines)
281
+
282
+
283
+ def format_patches(patch_set: PatchSet, verbose: bool = False) -> str:
284
+ """Format a patch set for display."""
285
+ lines = [
286
+ "=" * 60,
287
+ "GENERATED PATCHES",
288
+ "=" * 60,
289
+ "",
290
+ patch_set.summary(),
291
+ "",
292
+ ]
293
+
294
+ if patch_set.errors:
295
+ lines.append("ERRORS:")
296
+ for err in patch_set.errors:
297
+ lines.append(f" ✗ {err}")
298
+ lines.append("")
299
+
300
+ if patch_set.warnings:
301
+ lines.append("WARNINGS:")
302
+ for warn in patch_set.warnings:
303
+ lines.append(f" ⚠ {warn}")
304
+ lines.append("")
305
+
306
+ lines.append("PATCHES:")
307
+ for file_path, patches in patch_set.patches_by_file().items():
308
+ lines.append(f"\n {file_path}")
309
+ for patch in patches:
310
+ lines.append(f" [{patch.line_start}-{patch.line_end}] {patch.description}")
311
+ if verbose:
312
+ if patch.old_content:
313
+ for old_line in patch.old_content.split("\n")[:3]:
314
+ lines.append(f" - {old_line}")
315
+ if patch.new_content:
316
+ for new_line in patch.new_content.split("\n")[:5]:
317
+ lines.append(f" + {new_line}")
318
+
319
+ lines.append("")
320
+ lines.append("=" * 60)
321
+
322
+ return "\n".join(lines)
323
+
324
+
325
+ def _cmd_plan_brain(args) -> int:
326
+ """Show a brain-backed propagation plan (file-level, no local DB needed)."""
327
+ # Strip path prefix if user passed a full symbol ID
328
+ symbol_name = args.symbol_id.split("::")[-1] if "::" in args.symbol_id else args.symbol_id
329
+
330
+ sym_result = _brain_api("symbols", {"name": symbol_name, "limit": 5})
331
+ symbols = sym_result.get("results", [])
332
+
333
+ dep_result = _brain_api("dependents", {"name": symbol_name})
334
+ dep_files = dep_result.get("files", [])
335
+
336
+ if not symbols and not dep_files:
337
+ print(f"Error: '{symbol_name}' not found in brain index.", file=sys.stderr)
338
+ print("Index the codebase first, or pass --db <symbol.db> for local SQLite planning.", file=sys.stderr)
339
+ return 1
340
+
341
+ source = symbols[0] if symbols else {"name": symbol_name, "type": "unknown", "file_path": None}
342
+ change_type = args.change if args.change else "modify_field"
343
+
344
+ print("=" * 60)
345
+ print("PROPAGATION PLAN [brain-backed, file-level]")
346
+ print("=" * 60)
347
+ print()
348
+ print(f"Source: {source.get('name', symbol_name)}")
349
+ print(f" Type: {source.get('type', 'unknown')}")
350
+ file_path = source.get("file_path")
351
+ print(f" File: {file_path or '(chunk-indexed — run ingest with LSP for exact location)'}")
352
+ print()
353
+
354
+ if dep_files:
355
+ print(f"Dependent Files ({len(dep_files)}):")
356
+ for f in dep_files[:15]:
357
+ print(f" - {f}")
358
+ if len(dep_files) > 15:
359
+ print(f" ... and {len(dep_files) - 15} more")
360
+ else:
361
+ print("No dependent files found in brain index.")
362
+ print()
363
+ print("Note: Pass --db <symbol.db> for symbol-level graph traversal and patch generation.")
364
+ print("=" * 60)
365
+
366
+ if args.json:
367
+ print("\n" + json.dumps({
368
+ "source": {
369
+ "name": source.get("name", symbol_name),
370
+ "type": source.get("type", "unknown"),
371
+ "file": file_path,
372
+ },
373
+ "change_type": change_type,
374
+ "files_affected": dep_files,
375
+ "planning_source": "brain",
376
+ }, indent=2))
377
+
378
+ return 0
379
+
380
+
381
+ def cmd_plan(args):
382
+ """Show propagation plan without generating patches."""
383
+ if not args.db:
384
+ return _cmd_plan_brain(args)
385
+
386
+ db_path = Path(args.db)
387
+ if not db_path.exists():
388
+ print(f"Error: Database not found at {db_path}", file=sys.stderr)
389
+ return 1
390
+
391
+ resolved_id = _resolve_symbol_id(args.symbol_id, db_path)
392
+
393
+ engine = PropagationEngine(db_path)
394
+ try:
395
+ change_type = ChangeType(args.change) if args.change else ChangeType.MODIFY_FIELD
396
+ change_spec = ChangeSpec(
397
+ change_type=change_type,
398
+ target_symbol_id=resolved_id,
399
+ )
400
+
401
+ plan = engine.plan_propagation(change_spec, max_depth=args.depth)
402
+ print(format_plan(plan, change_type=change_type.value))
403
+
404
+ if args.json:
405
+ risk = _assess_risk(plan, change_type.value)
406
+ plan_dict = {
407
+ "source": {
408
+ "id": plan.source_symbol.id,
409
+ "name": plan.source_symbol.name,
410
+ "type": plan.source_symbol.type,
411
+ "file": plan.source_symbol.file_path,
412
+ },
413
+ "impacts": {
414
+ "direct": len(plan.direct_impacts),
415
+ "upstream": len(plan.upstream_impacts),
416
+ "downstream": len(plan.downstream_impacts),
417
+ },
418
+ "files_affected": list(plan.files_affected),
419
+ "risk_assessment": risk,
420
+ }
421
+ print("\n" + json.dumps(plan_dict, indent=2))
422
+
423
+ return 0
424
+
425
+ finally:
426
+ engine.close()
427
+
428
+
429
+ def cmd_add_field(args):
430
+ """Add a field and propagate to all affected files."""
431
+ db_path = _require_db(args.db)
432
+ if db_path is None:
433
+ return 1
434
+
435
+ resolved_id = _resolve_symbol_id(args.symbol_id, db_path)
436
+
437
+ engine = PropagationEngine(db_path)
438
+ try:
439
+ field_spec = FieldSpec(
440
+ name=args.name,
441
+ type=args.type,
442
+ nullable=not args.required,
443
+ column_name=args.column,
444
+ label=args.label,
445
+ validation={"required": True} if args.required else {},
446
+ )
447
+
448
+ change_spec = ChangeSpec(
449
+ change_type=ChangeType.ADD_FIELD,
450
+ target_symbol_id=resolved_id,
451
+ field_spec=field_spec,
452
+ )
453
+
454
+ patch_set = engine.generate_patches(change_spec, max_depth=args.depth)
455
+ print(format_patches(patch_set, verbose=args.verbose))
456
+
457
+ if patch_set.has_errors:
458
+ return 1
459
+
460
+ # Save patches to file
461
+ if args.output:
462
+ save_patches(patch_set, args.output)
463
+ print(f"\nPatches saved to {args.output}")
464
+
465
+ # Apply if requested
466
+ if args.apply:
467
+ return apply_patches_interactive(
468
+ patch_set, db_path,
469
+ force=getattr(args, 'force', False),
470
+ skip_git=getattr(args, 'skip_git', False),
471
+ )
472
+
473
+ return 0
474
+
475
+ finally:
476
+ engine.close()
477
+
478
+
479
+ def cmd_rename(args):
480
+ """Rename a field across all usages."""
481
+ db_path = _require_db(args.db)
482
+ if db_path is None:
483
+ return 1
484
+
485
+ resolved_id = _resolve_symbol_id(args.symbol_id, db_path)
486
+
487
+ engine = PropagationEngine(db_path)
488
+ try:
489
+ change_spec = ChangeSpec(
490
+ change_type=ChangeType.RENAME_FIELD,
491
+ target_symbol_id=resolved_id,
492
+ old_name=args.old,
493
+ new_name=args.new,
494
+ )
495
+
496
+ patch_set = engine.generate_patches(change_spec, max_depth=args.depth)
497
+ print(format_patches(patch_set, verbose=args.verbose))
498
+
499
+ if args.output:
500
+ save_patches(patch_set, args.output)
501
+ print(f"\nPatches saved to {args.output}")
502
+
503
+ if args.apply and not patch_set.has_errors:
504
+ return apply_patches_interactive(
505
+ patch_set, db_path,
506
+ force=getattr(args, 'force', False),
507
+ skip_git=getattr(args, 'skip_git', False),
508
+ )
509
+
510
+ return 0 if not patch_set.has_errors else 1
511
+
512
+ finally:
513
+ engine.close()
514
+
515
+
516
+ def cmd_remove(args):
517
+ """Remove a field and all its usages."""
518
+ db_path = _require_db(args.db)
519
+ if db_path is None:
520
+ return 1
521
+
522
+ resolved_id = _resolve_symbol_id(args.symbol_id, db_path)
523
+
524
+ engine = PropagationEngine(db_path)
525
+ try:
526
+ change_spec = ChangeSpec(
527
+ change_type=ChangeType.REMOVE_FIELD,
528
+ target_symbol_id=resolved_id,
529
+ old_name=args.field,
530
+ )
531
+
532
+ patch_set = engine.generate_patches(change_spec, max_depth=args.depth)
533
+ print(format_patches(patch_set, verbose=args.verbose))
534
+
535
+ if args.output:
536
+ save_patches(patch_set, args.output)
537
+
538
+ if args.apply and not patch_set.has_errors:
539
+ print("\n⚠️ WARNING: This will DELETE code!")
540
+ return apply_patches_interactive(
541
+ patch_set, db_path,
542
+ force=getattr(args, 'force', False),
543
+ skip_git=getattr(args, 'skip_git', False),
544
+ )
545
+
546
+ return 0 if not patch_set.has_errors else 1
547
+
548
+ finally:
549
+ engine.close()
550
+
551
+
552
+ def cmd_apply(args):
553
+ """Apply patches from a saved file."""
554
+ patches_file = Path(args.patches_file)
555
+ if not patches_file.exists():
556
+ print(f"Error: Patches file not found: {patches_file}", file=sys.stderr)
557
+ return 1
558
+
559
+ with open(patches_file) as f:
560
+ data = json.load(f)
561
+
562
+ print(f"Loaded {len(data.get('patches', []))} patches from {patches_file}")
563
+ print(f"Files affected: {len(data.get('files_affected', []))}")
564
+
565
+ if args.dry_run:
566
+ print("\nDry run - no changes made")
567
+ return 0
568
+
569
+ # Reconstruct patches
570
+ from generators import Patch, PatchSet, ChangeSpec, ChangeType
571
+ patches = [
572
+ Patch(
573
+ file_path=p['file'],
574
+ line_start=p['line_start'],
575
+ line_end=p['line_end'],
576
+ old_content=p['old'],
577
+ new_content=p['new'],
578
+ description=p['description'],
579
+ confidence=p.get('confidence', 'high'),
580
+ )
581
+ for p in data.get('patches', [])
582
+ ]
583
+
584
+ patch_set = PatchSet(
585
+ change_spec=ChangeSpec(
586
+ change_type=ChangeType(data.get('change_type', 'modify_field')),
587
+ target_symbol_id=data.get('target', ''),
588
+ ),
589
+ patches=patches,
590
+ )
591
+
592
+ db_path = Path(args.db) if args.db else None
593
+
594
+ return apply_patches_interactive(
595
+ patch_set, db_path,
596
+ force=getattr(args, 'force', False),
597
+ skip_git=getattr(args, 'skip_git', False),
598
+ )
599
+
600
+
601
+ def cmd_generators(args):
602
+ """List available generators."""
603
+ print("Available Generators:\n")
604
+ print(f"{'Extension':<12} {'Generator':<12} {'Symbol Types'}")
605
+ print("-" * 60)
606
+ for ext in sorted(GeneratorRegistry.supported_extensions()):
607
+ gen = GeneratorRegistry.list_generators().get(ext)
608
+ if gen:
609
+ types = ", ".join(sorted(gen.symbol_types))
610
+ print(f"{ext:<12} {gen.name:<12} {types}")
611
+
612
+
613
+ def save_patches(patch_set: PatchSet, output_path: str):
614
+ """Save patches to a JSON file, with a companion manifest.json."""
615
+ data = patch_set.to_dict()
616
+ data['generated_at'] = datetime.now().isoformat()
617
+ with open(output_path, 'w') as f:
618
+ json.dump(data, f, indent=2)
619
+
620
+ # Generate manifest.json alongside patches file
621
+ output_dir = Path(output_path).parent
622
+ manifest_path = output_dir / "manifest.json"
623
+ manifest = {
624
+ "patches_file": Path(output_path).name,
625
+ "generated_at": data['generated_at'],
626
+ "change_type": data.get('change_type', ''),
627
+ "target": data.get('target', ''),
628
+ "files_affected": data.get('files_affected', []),
629
+ "patch_count": len(data.get('patches', [])),
630
+ "has_errors": patch_set.has_errors,
631
+ "warnings": patch_set.warnings or [],
632
+ }
633
+ with open(manifest_path, 'w') as f:
634
+ json.dump(manifest, f, indent=2)
635
+
636
+
637
+ def apply_patches_interactive(
638
+ patch_set: PatchSet,
639
+ db_path: Optional[Path],
640
+ force: bool = False,
641
+ skip_git: bool = False,
642
+ ) -> int:
643
+ """
644
+ Interactively apply patches with safety checks.
645
+
646
+ Args:
647
+ patch_set: Patches to apply
648
+ db_path: Path to symbol database for freshness check, or None to skip it
649
+ force: Skip freshness check
650
+ skip_git: Skip git clean check
651
+ """
652
+ if not patch_set.patches:
653
+ print("\nNo patches to apply.")
654
+ return 0
655
+
656
+ files = list(patch_set.files_affected)
657
+
658
+ # Run safety checks
659
+ print("\nRunning safety checks...")
660
+ passed, results = run_safety_checks(
661
+ files=files,
662
+ db_path=db_path,
663
+ force=force,
664
+ skip_git=skip_git,
665
+ )
666
+
667
+ for result in results:
668
+ if result.passed:
669
+ print(f" ✓ {result.message}")
670
+ else:
671
+ print(f" ✗ {result.message}")
672
+
673
+ if not passed:
674
+ print("\nSafety checks failed. Use --force to bypass freshness check.")
675
+ return 1
676
+
677
+ # Confirm
678
+ confirm = input(f"\nApply {len(patch_set.patches)} patches to {len(files)} files? [y/N] ")
679
+ if confirm.lower() != 'y':
680
+ print("\nAborted.")
681
+ return 0
682
+
683
+ # Apply with transactional safety
684
+ print("\nApplying patches...")
685
+ applicator = TransactionalApplicator(patch_set.patches)
686
+ result = applicator.apply()
687
+
688
+ if result.success:
689
+ print(f"\n✓ Applied {len(result.files_modified)} files successfully")
690
+ return 0
691
+ else:
692
+ print(f"\n✗ Failed: {result.error}")
693
+ if result.rolled_back:
694
+ print(" All changes have been rolled back.")
695
+ return 1
696
+
697
+
698
+ def main():
699
+ parser = argparse.ArgumentParser(
700
+ description="wicked-patch: Language-agnostic code generation and change propagation",
701
+ formatter_class=argparse.RawDescriptionHelpFormatter,
702
+ epilog="""
703
+ Examples:
704
+ # Show what would be affected
705
+ patch plan "path/Entity.java::EntityName" --change add_field
706
+
707
+ # Add a new field
708
+ patch add-field "path/Entity.java::EntityName" --name email --type String
709
+
710
+ # Rename a field everywhere
711
+ patch rename "path/Entity.java::EntityName" --old status --new state
712
+
713
+ # Save patches for review
714
+ patch add-field SYMBOL --name foo --type String --output patches.json
715
+
716
+ # Apply saved patches
717
+ patch apply patches.json
718
+ """,
719
+ )
720
+
721
+ parser.add_argument("--db", help="Path to symbol database (required until wicked-brain#23 lands)")
722
+ parser.add_argument("--version", action="version", version="wicked-patch 1.0.0")
723
+
724
+ subparsers = parser.add_subparsers(dest="command", help="Command")
725
+
726
+ # plan
727
+ plan_p = subparsers.add_parser("plan", help="Show propagation plan")
728
+ plan_p.add_argument("symbol_id", help="Symbol ID to analyze")
729
+ plan_p.add_argument("--change", help="Change type (add_field, rename_field, etc.)")
730
+ plan_p.add_argument("--depth", type=int, default=5, help="Max traversal depth")
731
+ plan_p.add_argument("--json", action="store_true", help="Output JSON")
732
+
733
+ # add-field
734
+ add_p = subparsers.add_parser("add-field", help="Add a field")
735
+ add_p.add_argument("symbol_id", help="Target symbol ID")
736
+ add_p.add_argument("--name", required=True, help="Field name")
737
+ add_p.add_argument("--type", required=True, help="Field type")
738
+ add_p.add_argument("--column", help="Database column name")
739
+ add_p.add_argument("--label", help="UI label")
740
+ add_p.add_argument("--required", action="store_true", help="Field is required")
741
+ add_p.add_argument("--depth", type=int, default=5, help="Propagation depth")
742
+ add_p.add_argument("--output", "-o", help="Save patches to file")
743
+ add_p.add_argument("--apply", action="store_true", help="Apply patches")
744
+ add_p.add_argument("--force", action="store_true", help="Skip freshness check")
745
+ add_p.add_argument("--skip-git", action="store_true", help="Skip git clean check")
746
+ add_p.add_argument("--verbose", "-v", action="store_true", help="Show diffs")
747
+
748
+ # rename
749
+ rename_p = subparsers.add_parser("rename", help="Rename a field")
750
+ rename_p.add_argument("symbol_id", help="Target symbol ID")
751
+ rename_p.add_argument("--old", required=True, help="Current name")
752
+ rename_p.add_argument("--new", required=True, help="New name")
753
+ rename_p.add_argument("--depth", type=int, default=5)
754
+ rename_p.add_argument("--output", "-o", help="Save patches to file")
755
+ rename_p.add_argument("--apply", action="store_true")
756
+ rename_p.add_argument("--force", action="store_true", help="Skip freshness check")
757
+ rename_p.add_argument("--skip-git", action="store_true", help="Skip git clean check")
758
+ rename_p.add_argument("--verbose", "-v", action="store_true")
759
+
760
+ # remove
761
+ remove_p = subparsers.add_parser("remove", help="Remove a field")
762
+ remove_p.add_argument("symbol_id", help="Target symbol ID")
763
+ remove_p.add_argument("--field", required=True, help="Field name to remove")
764
+ remove_p.add_argument("--depth", type=int, default=5)
765
+ remove_p.add_argument("--output", "-o", help="Save patches to file")
766
+ remove_p.add_argument("--apply", action="store_true")
767
+ remove_p.add_argument("--force", action="store_true", help="Skip freshness check")
768
+ remove_p.add_argument("--skip-git", action="store_true", help="Skip git clean check")
769
+ remove_p.add_argument("--verbose", "-v", action="store_true")
770
+
771
+ # apply
772
+ apply_p = subparsers.add_parser("apply", help="Apply patches from file")
773
+ apply_p.add_argument("patches_file", help="Patches JSON file")
774
+ apply_p.add_argument("--dry-run", action="store_true", help="Show what would be done")
775
+ apply_p.add_argument("--force", action="store_true", help="Skip freshness check")
776
+ apply_p.add_argument("--skip-git", action="store_true", help="Skip git clean check")
777
+
778
+ # generators
779
+ gen_p = subparsers.add_parser("generators", help="List available generators")
780
+
781
+ args = parser.parse_args()
782
+
783
+ if not args.command:
784
+ parser.print_help()
785
+ return 1
786
+
787
+ commands = {
788
+ "plan": cmd_plan,
789
+ "add-field": cmd_add_field,
790
+ "rename": cmd_rename,
791
+ "remove": cmd_remove,
792
+ "apply": cmd_apply,
793
+ "generators": cmd_generators,
794
+ }
795
+
796
+ return commands[args.command](args)
797
+
798
+
799
+ if __name__ == "__main__":
800
+ sys.exit(main())