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,243 @@
1
+ #!/usr/bin/env python3
2
+ """scripts/crew/_task_audit_writer.py — cross-session task-chain index.
3
+
4
+ Phase 3 of v10. Designed in jam session 03 (decision memory:
5
+ ``v10-native-task-store-audit-trail-decision``).
6
+
7
+ This module owns the JSONL audit-log schema. **It is the SOLE writer**
8
+ of ``${CLAUDE_CONFIG_DIR}/wicked-garden/task-audit/{session_id}.jsonl``.
9
+ Schema changes require a PR to this module — anyone else writing to the
10
+ file is a layering violation.
11
+
12
+ ## Purpose vs. dispatch-log
13
+
14
+ This is NOT the same as ``phases/{phase}/dispatch-log.jsonl``. The two
15
+ serve different threat models — see brain memory
16
+ ``dispatch-log-precedes-reviewer-do-not-move-to-post-hook``:
17
+
18
+ * dispatch-log: HMAC-signed, written BEFORE reviewer invocation. Threat
19
+ model = rogue reviewer self-authorizing a gate-result. Sequencing is
20
+ the security property.
21
+ * task-audit (this file): plain JSONL, written AFTER native TaskCreate
22
+ by a PostToolUse hook. Threat model = ``verify_chain_emission`` not
23
+ finding tasks created in earlier sessions because the per-session
24
+ task store was never cross-session-indexed.
25
+
26
+ Different threat models, different files. Conflating them was an
27
+ explicit anti-pattern caught by the brainstorm.
28
+
29
+ ## Schema (locked; rev with PR)
30
+
31
+ {
32
+ "ts": ISO 8601 UTC,
33
+ "session_id": sanitised CLAUDE_SESSION_ID,
34
+ "task_id": native task id from tool_input/tool_response,
35
+ "subject": task subject string,
36
+ "chain_id": metadata.chain_id (may be None),
37
+ "event_type": metadata.event_type (may be None),
38
+ "source_agent": metadata.source_agent (may be None),
39
+ "status": "pending" | "in_progress" | "completed",
40
+ "tool": "TaskCreate" | "TaskUpdate"
41
+ }
42
+
43
+ Fail-open: any I/O exception is swallowed. Missing audit entries surface
44
+ as drift in ``verify_chain_emission`` rather than a hook crash.
45
+ """
46
+
47
+ from __future__ import annotations
48
+
49
+ import json
50
+ import os
51
+ import re
52
+ import tempfile
53
+ from datetime import datetime, timezone
54
+ from pathlib import Path
55
+ from typing import Any, Iterable
56
+
57
+ # Stable schema version. Bump on any change to the entry shape.
58
+ AUDIT_SCHEMA_VERSION = 1
59
+
60
+
61
+ def _audit_dir() -> Path:
62
+ """Return the per-host audit directory.
63
+
64
+ Mirrors the Claude Code config dir layout. Falls back to a temp dir
65
+ if CLAUDE_CONFIG_DIR is not set, so the writer never raises.
66
+ """
67
+ base = (
68
+ os.environ.get("CLAUDE_CONFIG_DIR")
69
+ or str(Path.home() / ".claude")
70
+ )
71
+ return Path(base) / "wicked-garden" / "task-audit"
72
+
73
+
74
+ _SAFE_ID_RE = re.compile(r"[^A-Za-z0-9_.\-]")
75
+
76
+
77
+ def _sanitize_session_id(raw: str | None) -> str:
78
+ """Strip path traversal and shell metacharacters from a session id."""
79
+ if not raw:
80
+ return "default"
81
+ cleaned = _SAFE_ID_RE.sub("_", raw)
82
+ return cleaned[:128] or "default"
83
+
84
+
85
+ def _now_iso() -> str:
86
+ return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
87
+
88
+
89
+ def _audit_file_for_session(session_id: str) -> Path:
90
+ return _audit_dir() / f"{_sanitize_session_id(session_id)}.jsonl"
91
+
92
+
93
+ def _safe_get(d: Any, *keys: str, default: Any = None) -> Any:
94
+ """Walk a nested dict; return default on any miss."""
95
+ cur = d
96
+ for k in keys:
97
+ if not isinstance(cur, dict):
98
+ return default
99
+ cur = cur.get(k)
100
+ if cur is None:
101
+ return default
102
+ return cur
103
+
104
+
105
+ def _build_entry(
106
+ *,
107
+ tool_name: str,
108
+ tool_input: dict | None,
109
+ tool_response: Any,
110
+ session_id: str,
111
+ ) -> dict | None:
112
+ """Compose the JSONL entry dict for one tool call.
113
+
114
+ Returns None when the tool call is not a task-management event we
115
+ care about (caller skips writing). The caller is expected to have
116
+ already gated on ``tool_name in {"TaskCreate", "TaskUpdate"}``;
117
+ this function double-checks defensively.
118
+ """
119
+ if tool_name not in ("TaskCreate", "TaskUpdate"):
120
+ return None
121
+
122
+ ti = tool_input or {}
123
+ metadata = ti.get("metadata") if isinstance(ti.get("metadata"), dict) else {}
124
+
125
+ # Native task ids appear in different shapes depending on tool. For
126
+ # TaskCreate, the response carries the new id; for TaskUpdate, the
127
+ # input carries taskId. Tolerate both for either tool.
128
+ task_id = (
129
+ ti.get("taskId")
130
+ or ti.get("task_id")
131
+ or _safe_get(tool_response, "taskId")
132
+ or _safe_get(tool_response, "task_id")
133
+ or _safe_get(tool_response, "id")
134
+ )
135
+
136
+ # Status: TaskCreate defaults to pending. TaskUpdate may carry an
137
+ # explicit status; if absent we still record the update so future
138
+ # consumers can correlate the timestamp with the underlying file.
139
+ if tool_name == "TaskCreate":
140
+ status = ti.get("status") or "pending"
141
+ else:
142
+ status = ti.get("status") or "updated"
143
+
144
+ return {
145
+ "schema_version": AUDIT_SCHEMA_VERSION,
146
+ "ts": _now_iso(),
147
+ "session_id": _sanitize_session_id(session_id),
148
+ "task_id": task_id,
149
+ "subject": ti.get("subject"),
150
+ "chain_id": metadata.get("chain_id"),
151
+ "event_type": metadata.get("event_type"),
152
+ "source_agent": metadata.get("source_agent"),
153
+ "phase": metadata.get("phase"),
154
+ "status": status,
155
+ "tool": tool_name,
156
+ }
157
+
158
+
159
+ def append_task_audit(
160
+ *,
161
+ tool_name: str,
162
+ tool_input: dict | None,
163
+ tool_response: Any,
164
+ session_id: str,
165
+ ) -> bool:
166
+ """Append one task-audit JSONL entry for a TaskCreate/TaskUpdate call.
167
+
168
+ Returns True when an entry was written. Returns False on filtered
169
+ tool names or on any I/O error (fail-open). Never raises.
170
+ """
171
+ try:
172
+ entry = _build_entry(
173
+ tool_name=tool_name,
174
+ tool_input=tool_input,
175
+ tool_response=tool_response,
176
+ session_id=session_id,
177
+ )
178
+ if entry is None:
179
+ return False
180
+
181
+ path = _audit_file_for_session(session_id)
182
+ path.parent.mkdir(parents=True, exist_ok=True)
183
+ line = json.dumps(entry, separators=(",", ":")) + "\n"
184
+ with path.open("a", encoding="utf-8") as fh:
185
+ fh.write(line)
186
+ return True
187
+ except Exception:
188
+ return False
189
+
190
+
191
+ def scan_chain(chain_id: str) -> list[dict]:
192
+ """Scan all session audit files for entries matching ``chain_id``.
193
+
194
+ Returns a list of entry dicts (newest first). Empty list when the
195
+ audit directory does not exist yet — the writer hasn't fired or
196
+ PostToolUse is disabled. ``verify_chain_emission`` uses this as a
197
+ cross-session fallback when the native per-session task scan misses.
198
+
199
+ O(N sessions) directory walk. At ~100 sessions × ~50 entries this
200
+ is a few KB scan and well under 10ms in practice.
201
+ """
202
+ audit_dir = _audit_dir()
203
+ if not audit_dir.is_dir():
204
+ return []
205
+
206
+ entries: list[dict] = []
207
+ for path in sorted(audit_dir.glob("*.jsonl")):
208
+ try:
209
+ with path.open("r", encoding="utf-8") as fh:
210
+ for line in fh:
211
+ line = line.strip()
212
+ if not line:
213
+ continue
214
+ try:
215
+ e = json.loads(line)
216
+ except json.JSONDecodeError:
217
+ continue
218
+ if e.get("chain_id") == chain_id:
219
+ entries.append(e)
220
+ except OSError:
221
+ continue
222
+ # Newest first by timestamp; fall back to insertion order for
223
+ # entries lacking a sortable ts.
224
+ entries.sort(key=lambda e: e.get("ts") or "", reverse=True)
225
+ return entries
226
+
227
+
228
+ def latest_per_task(entries: Iterable[dict]) -> list[dict]:
229
+ """Collapse multiple entries per task_id to the most recent one.
230
+
231
+ Useful for ``verify_chain_emission``: a TaskCreate followed by a
232
+ TaskUpdate for the same id yields two entries; we want one row per
233
+ task with the latest known status.
234
+ """
235
+ out: dict[str, dict] = {}
236
+ for e in entries:
237
+ tid = e.get("task_id")
238
+ if not tid:
239
+ continue
240
+ prev = out.get(tid)
241
+ if prev is None or (e.get("ts") or "") > (prev.get("ts") or ""):
242
+ out[tid] = e
243
+ return list(out.values())
@@ -0,0 +1,389 @@
1
+ """Task-store reader abstraction — #596 v8-PR-2.
2
+
3
+ Centralises the WG_DAEMON_ENABLED routing logic for all native task-store
4
+ readers. Callers that previously read
5
+ ``${CLAUDE_CONFIG_DIR:-~/.claude}/tasks/{session_id}/*.json`` directly now
6
+ call helpers from this module and the routing is handled transparently.
7
+
8
+ WG_DAEMON_ENABLED modes:
9
+ false (default) — direct file read; behaviour identical to v7.2.x
10
+ true — try daemon HTTP first; fall back to direct file read on error
11
+ always — daemon HTTP only; error surfaces to caller on unreachable
12
+
13
+ The module-level ``_DAEMON_MODE`` constant is resolved once at import time
14
+ so every process makes exactly one env-var decision (no per-call overhead).
15
+
16
+ Performance:
17
+ - Direct-file path: unchanged vs pre-PR-2
18
+ - Daemon path (WG_DAEMON_ENABLED=true): single HTTP GET with a 45ms timeout
19
+ (under the 50ms p99 hard requirement on the hot subagent_lifecycle path)
20
+ - Daemon path (WG_DAEMON_ENABLED=always): same timeout; error on unreachable
21
+
22
+ Cold-start behavior:
23
+ The first call after daemon startup (or after daemon restart) will hit the
24
+ 45ms HTTP timeout and fall back to the direct file read. This is intentional
25
+ and correct — the daemon needs one request to warm its connection pool and
26
+ prime the projection cursor. Subsequent warm-path calls are ~9ms p99.
27
+
28
+ Operators running WG_DAEMON_ENABLED=always should know: a daemon crash or
29
+ restart will surface a 45ms-latency blip on the next SubagentStart before
30
+ the next request warms the path. WG_DAEMON_ENABLED=true (default) falls
31
+ back to file read silently, so is blip-free at the cost of one extra
32
+ file-scan per restart cycle.
33
+
34
+ R3: all constants named.
35
+ R5: explicit timeout on every HTTP call; bounded iterdir scan preserved.
36
+ """
37
+
38
+ from __future__ import annotations
39
+
40
+ import json
41
+ import os
42
+ import urllib.error
43
+ import urllib.request
44
+ from pathlib import Path
45
+ from typing import Any
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # Constants
49
+ # ---------------------------------------------------------------------------
50
+
51
+ _ENV_DAEMON_ENABLED = "WG_DAEMON_ENABLED"
52
+ _ENV_DAEMON_PORT = "WG_DAEMON_PORT"
53
+ _ENV_DAEMON_HOST = "WG_DAEMON_HOST"
54
+ _ENV_CONFIG_DIR = "CLAUDE_CONFIG_DIR"
55
+
56
+ # Default port matches daemon/server.py DEFAULT_PORT.
57
+ _DEFAULT_DAEMON_PORT: int = 4244
58
+ _DEFAULT_DAEMON_HOST: str = "127.0.0.1"
59
+
60
+ # Sub-50ms hard requirement per #596 spec. We use 45ms to leave headroom.
61
+ # This is a per-call ceiling; network is loopback-only so the budget is realistic.
62
+ _DAEMON_HTTP_TIMEOUT_S: float = 0.045
63
+
64
+ # How many in-progress tasks to surface in WIP-context reads (preserves
65
+ # existing limits in prompt_submit.py and pre_compact.py).
66
+ _DEFAULT_WIP_LIMIT: int = 10
67
+
68
+
69
+ # ---------------------------------------------------------------------------
70
+ # Module-level mode resolution (R3, one decision per process)
71
+ # ---------------------------------------------------------------------------
72
+
73
+ def _resolve_daemon_mode() -> str:
74
+ """Return the normalised WG_DAEMON_ENABLED value: 'false' | 'true' | 'always'."""
75
+ raw = (os.environ.get(_ENV_DAEMON_ENABLED) or "false").strip().lower()
76
+ return raw if raw in ("true", "always") else "false"
77
+
78
+
79
+ _DAEMON_MODE: str = _resolve_daemon_mode()
80
+
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # Direct-file helpers (unchanged from pre-PR-2 behaviour)
84
+ # ---------------------------------------------------------------------------
85
+
86
+ def _tasks_dir_for_session(session_id: str) -> Path | None:
87
+ """Resolve ``${CLAUDE_CONFIG_DIR:-~/.claude}/tasks/{session_id}/``."""
88
+ config_dir = os.environ.get(_ENV_CONFIG_DIR)
89
+ base = Path(config_dir) if config_dir else Path.home() / ".claude"
90
+ tasks_dir = base / "tasks" / session_id
91
+ return tasks_dir if tasks_dir.is_dir() else None
92
+
93
+
94
+ def _read_task_file(session_id: str, task_id: str) -> dict | None:
95
+ """Read a single task JSON file. Returns None on any error."""
96
+ if not session_id or not task_id:
97
+ return None
98
+ try:
99
+ config_dir = os.environ.get(_ENV_CONFIG_DIR)
100
+ base = Path(config_dir) if config_dir else Path.home() / ".claude"
101
+ task_file = base / "tasks" / session_id / f"{task_id}.json"
102
+ if not task_file.is_file():
103
+ return None
104
+ data = json.loads(task_file.read_text(encoding="utf-8"))
105
+ return data if isinstance(data, dict) else None
106
+ except Exception:
107
+ return None
108
+
109
+
110
+ def _scan_tasks_dir(
111
+ session_id: str,
112
+ *,
113
+ status_filter: str | None = None,
114
+ limit: int = _DEFAULT_WIP_LIMIT,
115
+ ) -> list[dict]:
116
+ """Scan the tasks dir and return task dicts matching optional status_filter.
117
+
118
+ Returns at most ``limit`` entries; skips hidden files and non-JSON entries.
119
+ Never raises — returns [] on any error.
120
+ """
121
+ if not session_id:
122
+ return []
123
+ out: list[dict] = []
124
+ try:
125
+ tasks_dir = _tasks_dir_for_session(session_id)
126
+ if tasks_dir is None:
127
+ return out
128
+ for entry in tasks_dir.iterdir():
129
+ if entry.name.startswith(".") or entry.suffix != ".json":
130
+ continue
131
+ try:
132
+ data = json.loads(entry.read_text(encoding="utf-8"))
133
+ except Exception:
134
+ continue
135
+ if not isinstance(data, dict):
136
+ continue
137
+ if status_filter is not None and data.get("status") != status_filter:
138
+ continue
139
+ out.append(data)
140
+ if len(out) >= limit:
141
+ break
142
+ except Exception:
143
+ pass # fail open — tasks dir absent or unreadable; return whatever we collected
144
+ return out
145
+
146
+
147
+ # ---------------------------------------------------------------------------
148
+ # Daemon HTTP helpers
149
+ # ---------------------------------------------------------------------------
150
+
151
+ def _daemon_base_url() -> str:
152
+ host = os.environ.get(_ENV_DAEMON_HOST, _DEFAULT_DAEMON_HOST)
153
+ port_raw = os.environ.get(_ENV_DAEMON_PORT, str(_DEFAULT_DAEMON_PORT))
154
+ try:
155
+ port = int(port_raw)
156
+ except (ValueError, TypeError):
157
+ port = _DEFAULT_DAEMON_PORT
158
+ return f"http://{host}:{port}"
159
+
160
+
161
+ def _daemon_get(path: str) -> Any | None:
162
+ """Issue a GET request to the daemon at ``path``.
163
+
164
+ Returns the parsed JSON body on 200, raises ``urllib.error.URLError``
165
+ or ``urllib.error.HTTPError`` on failure. Callers catch accordingly.
166
+ """
167
+ url = _daemon_base_url() + path
168
+ req = urllib.request.Request(url, method="GET")
169
+ with urllib.request.urlopen(req, timeout=_DAEMON_HTTP_TIMEOUT_S) as resp:
170
+ return json.loads(resp.read().decode("utf-8"))
171
+
172
+
173
+ # ---------------------------------------------------------------------------
174
+ # Public API — routed readers
175
+ # ---------------------------------------------------------------------------
176
+
177
+ def get_task_metadata(session_id: str, task_id: str) -> dict | None:
178
+ """Return the ``metadata`` dict from a single task.
179
+
180
+ Routes via WG_DAEMON_ENABLED:
181
+ false → direct file read
182
+ true → daemon HTTP; fallback to direct file on error
183
+ always → daemon HTTP; returns None on unreachable
184
+ """
185
+ if _DAEMON_MODE == "false":
186
+ data = _read_task_file(session_id, task_id)
187
+ if data is None:
188
+ return None
189
+ meta = data.get("metadata")
190
+ return meta if isinstance(meta, dict) else None
191
+
192
+ # Daemon path.
193
+ try:
194
+ row = _daemon_get(f"/tasks/{task_id}")
195
+ if row and isinstance(row, dict):
196
+ meta = row.get("metadata")
197
+ return meta if isinstance(meta, dict) else None
198
+ return None
199
+ except Exception:
200
+ if _DAEMON_MODE == "always":
201
+ return None
202
+ # fallback
203
+ data = _read_task_file(session_id, task_id)
204
+ if data is None:
205
+ return None
206
+ meta = data.get("metadata")
207
+ return meta if isinstance(meta, dict) else None
208
+
209
+
210
+ def get_active_task_event_type(session_id: str) -> str | None:
211
+ """Return event_type of the most-recently-modified in_progress task.
212
+
213
+ This is the hot path — called on every SubagentStart. Sub-50ms p99 is
214
+ required for the daemon path.
215
+
216
+ Routes via WG_DAEMON_ENABLED:
217
+ false → direct file scan (existing behaviour, bit-identical)
218
+ true → daemon GET /tasks?session=<id>&status=in_progress; fallback to direct
219
+ always → daemon only; None on unreachable
220
+ """
221
+ if not session_id:
222
+ return None
223
+
224
+ if _DAEMON_MODE == "false":
225
+ return _get_active_task_event_type_direct(session_id)
226
+
227
+ # Daemon path.
228
+ try:
229
+ rows = _daemon_get(f"/tasks?session={session_id}&status=in_progress&limit=10")
230
+ if not rows or not isinstance(rows, list):
231
+ return None
232
+ # Pick the task with the highest updated_at (proxy for most-recent).
233
+ best = max(rows, key=lambda r: r.get("updated_at", 0), default=None)
234
+ if best is None:
235
+ return None
236
+ return best.get("event_type")
237
+ except Exception:
238
+ if _DAEMON_MODE == "always":
239
+ return None
240
+ return _get_active_task_event_type_direct(session_id)
241
+
242
+
243
+ def _get_active_task_event_type_direct(session_id: str) -> str | None:
244
+ """Direct-file fallback for get_active_task_event_type (pre-PR-2 behaviour)."""
245
+ try:
246
+ tasks_dir = _tasks_dir_for_session(session_id)
247
+ if tasks_dir is None:
248
+ return None
249
+ best_mtime = -1.0
250
+ best_event_type: str | None = None
251
+ for entry in tasks_dir.iterdir():
252
+ if entry.name.startswith(".") or entry.suffix != ".json":
253
+ continue
254
+ try:
255
+ data = json.loads(entry.read_text(encoding="utf-8"))
256
+ except Exception:
257
+ continue
258
+ if not isinstance(data, dict) or data.get("status") != "in_progress":
259
+ continue
260
+ mtime = entry.stat().st_mtime
261
+ if mtime > best_mtime:
262
+ best_mtime = mtime
263
+ metadata = data.get("metadata") or {}
264
+ if isinstance(metadata, dict):
265
+ best_event_type = metadata.get("event_type")
266
+ return best_event_type
267
+ except Exception:
268
+ return None
269
+
270
+
271
+ def list_in_progress_tasks(
272
+ session_id: str,
273
+ limit: int = _DEFAULT_WIP_LIMIT,
274
+ ) -> list[str]:
275
+ """Return subject strings of in-progress tasks (for WIP context injection).
276
+
277
+ Used by prompt_submit.py and pre_compact.py for context display — subjects
278
+ only, not full task dicts.
279
+ """
280
+ if _DAEMON_MODE == "false":
281
+ tasks = _scan_tasks_dir(session_id, status_filter="in_progress", limit=limit)
282
+ return [t.get("subject") or "untitled" for t in tasks]
283
+
284
+ try:
285
+ rows = _daemon_get(
286
+ f"/tasks?session={session_id}&status=in_progress&limit={limit}"
287
+ )
288
+ if not rows or not isinstance(rows, list):
289
+ return []
290
+ return [r.get("subject") or "untitled" for r in rows]
291
+ except Exception:
292
+ if _DAEMON_MODE == "always":
293
+ return []
294
+ tasks = _scan_tasks_dir(session_id, status_filter="in_progress", limit=limit)
295
+ return [t.get("subject") or "untitled" for t in tasks]
296
+
297
+
298
+ def collect_tasks_for_chain(chain_id: str) -> list[dict]:
299
+ """Return task dicts whose metadata.chain_id matches ``chain_id``.
300
+
301
+ Used by current_chain.py and verify_chain_emission.py.
302
+
303
+ Routes via WG_DAEMON_ENABLED:
304
+ false → direct file scan across all sessions (existing behaviour)
305
+ true → daemon GET /tasks?chain_id=<chain_id>; fallback to direct
306
+ always → daemon only; [] on unreachable
307
+ """
308
+ if _DAEMON_MODE == "false":
309
+ return _collect_tasks_for_chain_direct(chain_id)
310
+
311
+ try:
312
+ rows = _daemon_get(f"/tasks?chain_id={chain_id}&limit=500")
313
+ if not rows or not isinstance(rows, list):
314
+ return []
315
+ # Re-shape to match the dict shape callers expect (id, subject, status, metadata).
316
+ result = []
317
+ for row in rows:
318
+ meta = row.get("metadata") or {}
319
+ if not isinstance(meta, dict):
320
+ meta = {}
321
+ result.append({
322
+ "id": row.get("id", ""),
323
+ "subject": row.get("subject", ""),
324
+ "status": row.get("status", "unknown"),
325
+ "metadata": meta,
326
+ "blockedBy": [],
327
+ })
328
+ return result
329
+ except Exception:
330
+ if _DAEMON_MODE == "always":
331
+ return []
332
+ return _collect_tasks_for_chain_direct(chain_id)
333
+
334
+
335
+ def _collect_tasks_for_chain_direct(chain_id: str) -> list[dict]:
336
+ """Direct-file fallback: scan all sessions for chain_id match."""
337
+ config_dir = os.environ.get(_ENV_CONFIG_DIR) or str(Path.home() / ".claude")
338
+ root = Path(config_dir) / "tasks"
339
+ if not root.exists():
340
+ return []
341
+ out = []
342
+ for task_file in root.rglob("*.json"):
343
+ try:
344
+ data = json.loads(task_file.read_text(encoding="utf-8"))
345
+ except (OSError, json.JSONDecodeError):
346
+ continue
347
+ meta = data.get("metadata") or {}
348
+ if meta.get("chain_id") != chain_id:
349
+ continue
350
+ out.append({
351
+ "id": data.get("id") or task_file.stem,
352
+ "subject": data.get("subject") or data.get("title") or "<untitled>",
353
+ "status": data.get("status") or "unknown",
354
+ "metadata": meta,
355
+ "blockedBy": data.get("blockedBy") or [],
356
+ })
357
+ return out
358
+
359
+
360
+ def read_session_tasks(session_id: str, limit: int = 200) -> list[dict]:
361
+ """Return all task dicts for a session (any status).
362
+
363
+ Used by session_fact_extractor.py and telemetry.py.
364
+
365
+ Routes via WG_DAEMON_ENABLED:
366
+ false → direct file scan
367
+ true → daemon GET /tasks?session=<id>; fallback to direct
368
+ always → daemon only; [] on unreachable
369
+ """
370
+ if _DAEMON_MODE == "false":
371
+ return _scan_tasks_dir(session_id, limit=limit)
372
+
373
+ try:
374
+ rows = _daemon_get(f"/tasks?session={session_id}&limit={limit}")
375
+ if not rows or not isinstance(rows, list):
376
+ return []
377
+ return [
378
+ {
379
+ "id": r.get("id", ""),
380
+ "subject": r.get("subject", ""),
381
+ "status": r.get("status", "unknown"),
382
+ "metadata": r.get("metadata") or {},
383
+ }
384
+ for r in rows
385
+ ]
386
+ except Exception:
387
+ if _DAEMON_MODE == "always":
388
+ return []
389
+ return _scan_tasks_dir(session_id, limit=limit)