@scemoon/cdh 1.0.8 → 1.0.9-beta.2

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 (786) hide show
  1. package/ai-dlc-skill/SKILL.md +106 -0
  2. package/ai-dlc-skill/architecture/project-structure.md +78 -0
  3. package/ai-dlc-skill/brownfield/README.md +36 -0
  4. package/ai-dlc-skill/brownfield/entry.md +45 -0
  5. package/ai-dlc-skill/brownfield/generate-context.sh +64 -0
  6. package/ai-dlc-skill/brownfield/scripts/deps.sh +27 -0
  7. package/ai-dlc-skill/brownfield/scripts/discover.sh +34 -0
  8. package/ai-dlc-skill/brownfield/scripts/extract-api.sh +45 -0
  9. package/ai-dlc-skill/components/backend.md +47 -0
  10. package/ai-dlc-skill/components/desktop.md +63 -0
  11. package/ai-dlc-skill/components/mya.md +219 -0
  12. package/ai-dlc-skill/components/native.md +73 -0
  13. package/ai-dlc-skill/components/tta.md +235 -0
  14. package/ai-dlc-skill/components/web.md +77 -0
  15. package/ai-dlc-skill/components/wxa.md +219 -0
  16. package/ai-dlc-skill/contracts/README.md +25 -0
  17. package/ai-dlc-skill/core/adaptive-flow.md +107 -0
  18. package/ai-dlc-skill/core/security.md +29 -0
  19. package/ai-dlc-skill/core/task-registry.md +153 -0
  20. package/ai-dlc-skill/cross-tool/README.md +20 -0
  21. package/ai-dlc-skill/cross-tool/cline/export.sh +38 -0
  22. package/ai-dlc-skill/cross-tool/copilot/export.sh +41 -0
  23. package/ai-dlc-skill/cross-tool/cursor/export.sh +53 -0
  24. package/ai-dlc-skill/cross-tool/onecode/export.sh +27 -0
  25. package/ai-dlc-skill/cross-tool/opencode/export.sh +38 -0
  26. package/ai-dlc-skill/phases/debug/entry.md +48 -0
  27. package/ai-dlc-skill/phases/debug/lifecycle.md +284 -0
  28. package/ai-dlc-skill/phases/deliver/entry.md +35 -0
  29. package/ai-dlc-skill/phases/deliver/lifecycle.md +185 -0
  30. package/ai-dlc-skill/phases/deliver/prompt.md +54 -0
  31. package/ai-dlc-skill/phases/deliver/rules.md +61 -0
  32. package/ai-dlc-skill/phases/plan/design_system/accessibility.md +268 -0
  33. package/ai-dlc-skill/phases/plan/design_system/atomic_design.md +341 -0
  34. package/ai-dlc-skill/phases/plan/design_system/component_spec.md +398 -0
  35. package/ai-dlc-skill/phases/plan/design_system/design_tokens.md +190 -0
  36. package/ai-dlc-skill/phases/plan/design_system/iconography.md +299 -0
  37. package/ai-dlc-skill/phases/plan/design_system/platform_ui/desktop.md +318 -0
  38. package/ai-dlc-skill/phases/plan/design_system/platform_ui/mya.md +354 -0
  39. package/ai-dlc-skill/phases/plan/design_system/platform_ui/native.md +328 -0
  40. package/ai-dlc-skill/phases/plan/design_system/platform_ui/tta.md +394 -0
  41. package/ai-dlc-skill/phases/plan/design_system/platform_ui/web.md +287 -0
  42. package/ai-dlc-skill/phases/plan/design_system/platform_ui/wxa.md +374 -0
  43. package/ai-dlc-skill/phases/plan/design_system/theme_system.md +318 -0
  44. package/ai-dlc-skill/phases/plan/entry.md +33 -0
  45. package/ai-dlc-skill/phases/plan/lifecycle.md +260 -0
  46. package/ai-dlc-skill/phases/plan/prompt.md +75 -0
  47. package/ai-dlc-skill/phases/plan/rules.md +60 -0
  48. package/ai-dlc-skill/phases/understand/entry.md +36 -0
  49. package/ai-dlc-skill/phases/understand/lifecycle.md +184 -0
  50. package/ai-dlc-skill/phases/understand/prompt.md +58 -0
  51. package/ai-dlc-skill/phases/understand/rules.md +49 -0
  52. package/ai-dlc-skill/phases/verify/config/base_url.md +65 -0
  53. package/ai-dlc-skill/phases/verify/entry.md +59 -0
  54. package/ai-dlc-skill/phases/verify/gates/browser_e2e.md +96 -0
  55. package/ai-dlc-skill/phases/verify/lifecycle.md +217 -0
  56. package/ai-dlc-skill/phases/verify/prompt.md +73 -0
  57. package/ai-dlc-skill/phases/verify/rules.md +91 -0
  58. package/ai-dlc-skill/phases/verify/runners/playwright_local.md +103 -0
  59. package/ai-dlc-skill/practices/bdd.md +119 -0
  60. package/ai-dlc-skill/practices/sdd.md +84 -0
  61. package/ai-dlc-skill/practices/tdd.md +128 -0
  62. package/ai-dlc-skill/providers/README.md +114 -0
  63. package/ai-dlc-skill/providers/aliyun/SKILL.md +204 -0
  64. package/ai-dlc-skill/providers/aliyun/api/rest-api.md +214 -0
  65. package/ai-dlc-skill/providers/aliyun/api/sdk.md +307 -0
  66. package/ai-dlc-skill/providers/aliyun/best-practices/database-design.md +363 -0
  67. package/ai-dlc-skill/providers/aliyun/best-practices/function-design.md +424 -0
  68. package/ai-dlc-skill/providers/aliyun/best-practices/troubleshooting.md +258 -0
  69. package/ai-dlc-skill/providers/aliyun/cli/database.md +263 -0
  70. package/ai-dlc-skill/providers/aliyun/cli/functions.md +263 -0
  71. package/ai-dlc-skill/providers/aliyun/cli/hosting.md +226 -0
  72. package/ai-dlc-skill/providers/aliyun/cli/setup.md +235 -0
  73. package/ai-dlc-skill/providers/aliyun/cli/storage.md +315 -0
  74. package/ai-dlc-skill/providers/aliyun/deployment.yaml +66 -0
  75. package/ai-dlc-skill/providers/aliyun/integration/ci-cd.md +288 -0
  76. package/ai-dlc-skill/providers/aliyun/preview.yaml +84 -0
  77. package/ai-dlc-skill/providers/aliyun/provider.yaml +160 -0
  78. package/ai-dlc-skill/providers/aliyun/security/authentication.md +254 -0
  79. package/ai-dlc-skill/providers/aliyun/services/cdn-hosting.md +220 -0
  80. package/ai-dlc-skill/providers/aliyun/services/database.md +319 -0
  81. package/ai-dlc-skill/providers/aliyun/services/function-compute.md +273 -0
  82. package/ai-dlc-skill/providers/aliyun/services/overview.md +163 -0
  83. package/ai-dlc-skill/providers/aliyun/services/serverless-app-engine.md +266 -0
  84. package/ai-dlc-skill/providers/aliyun/services/storage.md +269 -0
  85. package/ai-dlc-skill/providers/tcb/SKILL.md +208 -0
  86. package/ai-dlc-skill/providers/tcb/api/rest-api.md +338 -0
  87. package/ai-dlc-skill/providers/tcb/api/sdk.md +288 -0
  88. package/ai-dlc-skill/providers/tcb/best-practices/database-design.md +452 -0
  89. package/ai-dlc-skill/providers/tcb/best-practices/function-design.md +502 -0
  90. package/ai-dlc-skill/providers/tcb/best-practices/troubleshooting.md +462 -0
  91. package/ai-dlc-skill/providers/tcb/cli/cls.md +133 -0
  92. package/ai-dlc-skill/providers/tcb/cli/database.md +230 -0
  93. package/ai-dlc-skill/providers/tcb/cli/env.md +207 -0
  94. package/ai-dlc-skill/providers/tcb/cli/functions.md +276 -0
  95. package/ai-dlc-skill/providers/tcb/cli/hosting.md +219 -0
  96. package/ai-dlc-skill/providers/tcb/cli/setup.md +218 -0
  97. package/ai-dlc-skill/providers/tcb/cli/storage.md +233 -0
  98. package/ai-dlc-skill/providers/tcb/deployment.yaml +111 -0
  99. package/ai-dlc-skill/providers/tcb/integration/ci-cd.md +309 -0
  100. package/ai-dlc-skill/providers/tcb/integration/mcp-server.md +371 -0
  101. package/ai-dlc-skill/providers/tcb/preview.yaml +83 -0
  102. package/ai-dlc-skill/providers/tcb/provider.yaml +172 -0
  103. package/ai-dlc-skill/providers/tcb/security/authentication.md +241 -0
  104. package/ai-dlc-skill/providers/tcb/services/cloud-database.md +299 -0
  105. package/ai-dlc-skill/providers/tcb/services/cloud-functions.md +265 -0
  106. package/ai-dlc-skill/providers/tcb/services/cloud-hosting.md +264 -0
  107. package/ai-dlc-skill/providers/tcb/services/cloud-run.md +285 -0
  108. package/ai-dlc-skill/providers/tcb/services/cloud-storage.md +245 -0
  109. package/ai-dlc-skill/providers/tcb/services/overview.md +174 -0
  110. package/ai-dlc-skill/pybdd/README.md +41 -0
  111. package/ai-dlc-skill/pybdd/conftest.py +17 -0
  112. package/ai-dlc-skill/pybdd/example/auth/login.feature +32 -0
  113. package/ai-dlc-skill/pybdd/pytest.ini +5 -0
  114. package/ai-dlc-skill/pybdd/steps/.gitkeep +1 -0
  115. package/ai-dlc-skill/pybdd/steps/test_example_steps.py +65 -0
  116. package/ai-dlc-skill/requirements.md +140 -0
  117. package/ai-dlc-skill/skill.yaml +135 -0
  118. package/ai-dlc-skill/templates/brownfield/context.md +78 -0
  119. package/ai-dlc-skill/templates/integration/CHANGELOG.md +41 -0
  120. package/ai-dlc-skill/templates/integration/asyncapi.yaml +43 -0
  121. package/ai-dlc-skill/templates/integration/contract-diff.md +63 -0
  122. package/ai-dlc-skill/templates/integration/contract-spec.md +49 -0
  123. package/ai-dlc-skill/templates/integration/openapi.yaml +18 -0
  124. package/ai-dlc-skill/templates/integration/runtime-contract.yaml +36 -0
  125. package/ai-dlc-skill/templates/plan/design.md +49 -0
  126. package/ai-dlc-skill/templates/plan/task-list.md +32 -0
  127. package/ai-dlc-skill/templates/project/README.md +126 -0
  128. package/ai-dlc-skill/templates/project/template.md +119 -0
  129. package/ai-dlc-skill/templates/understand/feature.feature +30 -0
  130. package/ai-dlc-skill/templates/understand/intent.md +29 -0
  131. package/ai-dlc-skill/templates/understand/spec-delta.md +47 -0
  132. package/ai-dlc-skill/templates/verify/test-unit.py +27 -0
  133. package/ai-dlc-skill/walkthrough/collect.sh +50 -0
  134. package/ai-dlc-skill/walkthrough/template.md +54 -0
  135. package/cdh/__init__.py +0 -0
  136. package/cdh/__main__.py +4 -0
  137. package/cdh/__pycache__/__init__.cpython-314.pyc +0 -0
  138. package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
  139. package/cdh/__pycache__/cli_logging.cpython-314.pyc +0 -0
  140. package/cdh/__pycache__/config.cpython-314.pyc +0 -0
  141. package/cdh/__pycache__/project_loader.cpython-314.pyc +0 -0
  142. package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
  143. package/cdh/__pycache__/session_store.cpython-314.pyc +0 -0
  144. package/cdh/cdh_session_aggregator.py +258 -0
  145. package/cdh/cli.py +3000 -0
  146. package/cdh/cli_logging.py +45 -0
  147. package/cdh/config.py +28 -0
  148. package/cdh/event_loop/__init__.py +7 -0
  149. package/cdh/event_loop/bus.py +123 -0
  150. package/cdh/event_loop/events.py +25 -0
  151. package/cdh/event_loop/runner.py +28 -0
  152. package/cdh/event_loop/scheduler.py +158 -0
  153. package/cdh/generators/__init__.py +35 -0
  154. package/cdh/generators/_runtime.py +176 -0
  155. package/cdh/generators/ada/MANIFEST.toml +14 -0
  156. package/cdh/generators/ada/template.ads.tmpl +7 -0
  157. package/cdh/generators/bash/MANIFEST.toml +14 -0
  158. package/cdh/generators/bash/template.sh.tmpl +16 -0
  159. package/cdh/generators/builtin_index.json +590 -0
  160. package/cdh/generators/c/MANIFEST.toml +14 -0
  161. package/cdh/generators/c/template.h.tmpl +20 -0
  162. package/cdh/generators/cli.py +379 -0
  163. package/cdh/generators/clojure/MANIFEST.toml +14 -0
  164. package/cdh/generators/clojure/template.clj.tmpl +13 -0
  165. package/cdh/generators/cobol/MANIFEST.toml +14 -0
  166. package/cdh/generators/cobol/template.cbl.tmpl +14 -0
  167. package/cdh/generators/cpp/MANIFEST.toml +14 -0
  168. package/cdh/generators/cpp/template.hpp.tmpl +32 -0
  169. package/cdh/generators/crystal/MANIFEST.toml +14 -0
  170. package/cdh/generators/crystal/template.cr.tmpl +11 -0
  171. package/cdh/generators/csharp/MANIFEST.toml +23 -0
  172. package/cdh/generators/csharp/template.cs.tmpl +14 -0
  173. package/cdh/generators/cython/MANIFEST.toml +14 -0
  174. package/cdh/generators/cython/template.pyx.tmpl +17 -0
  175. package/cdh/generators/d/MANIFEST.toml +14 -0
  176. package/cdh/generators/d/template.d.tmpl +24 -0
  177. package/cdh/generators/dart/MANIFEST.toml +17 -0
  178. package/cdh/generators/dart/template.dart.tmpl +27 -0
  179. package/cdh/generators/elixir/MANIFEST.toml +17 -0
  180. package/cdh/generators/elixir/template.ex.tmpl +27 -0
  181. package/cdh/generators/elm/MANIFEST.toml +14 -0
  182. package/cdh/generators/elm/template.elm.tmpl +20 -0
  183. package/cdh/generators/erlang/MANIFEST.toml +14 -0
  184. package/cdh/generators/erlang/template.erl.tmpl +18 -0
  185. package/cdh/generators/fortran/MANIFEST.toml +14 -0
  186. package/cdh/generators/fortran/template.f90.tmpl +24 -0
  187. package/cdh/generators/fsharp/MANIFEST.toml +14 -0
  188. package/cdh/generators/fsharp/template.fs.tmpl +17 -0
  189. package/cdh/generators/go/MANIFEST.toml +18 -0
  190. package/cdh/generators/go/imports.go.tmpl +3 -0
  191. package/cdh/generators/go/template.go.tmpl +9 -0
  192. package/cdh/generators/graphql-schema/MANIFEST.toml +18 -0
  193. package/cdh/generators/graphql-schema/template.graphqls.tmpl +12 -0
  194. package/cdh/generators/groovy/MANIFEST.toml +14 -0
  195. package/cdh/generators/groovy/template.groovy.tmpl +28 -0
  196. package/cdh/generators/hack/MANIFEST.toml +14 -0
  197. package/cdh/generators/hack/template.hh.tmpl +24 -0
  198. package/cdh/generators/haskell/MANIFEST.toml +14 -0
  199. package/cdh/generators/haskell/template.hs.tmpl +20 -0
  200. package/cdh/generators/haxe/MANIFEST.toml +14 -0
  201. package/cdh/generators/haxe/template.hx.tmpl +20 -0
  202. package/cdh/generators/idris/MANIFEST.toml +14 -0
  203. package/cdh/generators/idris/template.idr.tmpl +22 -0
  204. package/cdh/generators/java/MANIFEST.toml +18 -0
  205. package/cdh/generators/java/template.java.tmpl +13 -0
  206. package/cdh/generators/julia/MANIFEST.toml +14 -0
  207. package/cdh/generators/julia/template.jl.tmpl +27 -0
  208. package/cdh/generators/kotlin/MANIFEST.toml +18 -0
  209. package/cdh/generators/kotlin/template.kt.tmpl +12 -0
  210. package/cdh/generators/lua/MANIFEST.toml +14 -0
  211. package/cdh/generators/lua/template.lua.tmpl +27 -0
  212. package/cdh/generators/matlab/MANIFEST.toml +14 -0
  213. package/cdh/generators/matlab/template.m.tmpl +26 -0
  214. package/cdh/generators/nim/MANIFEST.toml +14 -0
  215. package/cdh/generators/nim/template.nim.tmpl +12 -0
  216. package/cdh/generators/nix/MANIFEST.toml +14 -0
  217. package/cdh/generators/nix/template.nix.tmpl +8 -0
  218. package/cdh/generators/objective-c/MANIFEST.toml +14 -0
  219. package/cdh/generators/objective-c/template.m.tmpl +31 -0
  220. package/cdh/generators/ocaml/MANIFEST.toml +14 -0
  221. package/cdh/generators/ocaml/template.ml.tmpl +13 -0
  222. package/cdh/generators/pascal/MANIFEST.toml +14 -0
  223. package/cdh/generators/pascal/template.pas.tmpl +5 -0
  224. package/cdh/generators/perl/MANIFEST.toml +14 -0
  225. package/cdh/generators/perl/template.pm.tmpl +27 -0
  226. package/cdh/generators/php/MANIFEST.toml +17 -0
  227. package/cdh/generators/php/template.php.tmpl +31 -0
  228. package/cdh/generators/powershell/MANIFEST.toml +14 -0
  229. package/cdh/generators/powershell/template.ps1.tmpl +20 -0
  230. package/cdh/generators/protobuf/MANIFEST.toml +18 -0
  231. package/cdh/generators/protobuf/template.proto.tmpl +13 -0
  232. package/cdh/generators/python/MANIFEST.toml +18 -0
  233. package/cdh/generators/python/template.py.tmpl +12 -0
  234. package/cdh/generators/r/MANIFEST.toml +14 -0
  235. package/cdh/generators/r/template.R.tmpl +29 -0
  236. package/cdh/generators/racket/MANIFEST.toml +14 -0
  237. package/cdh/generators/racket/template.rkt.tmpl +15 -0
  238. package/cdh/generators/registry.py +211 -0
  239. package/cdh/generators/ruby/MANIFEST.toml +17 -0
  240. package/cdh/generators/ruby/template.rb.tmpl +27 -0
  241. package/cdh/generators/rust/MANIFEST.toml +18 -0
  242. package/cdh/generators/rust/template.rs.tmpl +16 -0
  243. package/cdh/generators/scala/MANIFEST.toml +20 -0
  244. package/cdh/generators/scala/template.scala.tmpl +13 -0
  245. package/cdh/generators/scheme/MANIFEST.toml +14 -0
  246. package/cdh/generators/scheme/template.scm.tmpl +16 -0
  247. package/cdh/generators/solidity/MANIFEST.toml +14 -0
  248. package/cdh/generators/solidity/template.sol.tmpl +24 -0
  249. package/cdh/generators/swift/MANIFEST.toml +18 -0
  250. package/cdh/generators/swift/template.swift.tmpl +10 -0
  251. package/cdh/generators/typescript/MANIFEST.toml +18 -0
  252. package/cdh/generators/typescript/template.ts.tmpl +7 -0
  253. package/cdh/generators/version.py +214 -0
  254. package/cdh/generators/zig/MANIFEST.toml +14 -0
  255. package/cdh/generators/zig/template.zig.tmpl +20 -0
  256. package/cdh/logging.py +314 -0
  257. package/cdh/optimizer/__init__.py +7 -0
  258. package/cdh/optimizer/loop.py +201 -0
  259. package/cdh/optimizer/mutation.py +85 -0
  260. package/cdh/optimizer/reward.py +51 -0
  261. package/cdh/optimizer/tracker.py +118 -0
  262. package/cdh/project_loader.py +1022 -0
  263. package/cdh/rules/patterns.yaml +132 -0
  264. package/cdh/rules/spectral.yaml +301 -0
  265. package/cdh/scaffold.py +1436 -0
  266. package/cdh/session_store.py +221 -0
  267. package/cdh/state_schema.py +127 -0
  268. package/cdh/tools/__init__.py +57 -0
  269. package/cdh/tools/cls_search.py +406 -0
  270. package/cdh/tools/contract_diff.py +644 -0
  271. package/cdh/tools/deploy_stack.py +590 -0
  272. package/cdh/tools/generate_shared.py +300 -0
  273. package/cdh/tools/iac_gen.py +224 -0
  274. package/cdh/tools/otel_export.py +125 -0
  275. package/cdh/tools/pattern_detect.py +451 -0
  276. package/cdh/tools/retrofit_labels.py +505 -0
  277. package/cdh/trace/__init__.py +101 -0
  278. package/cdh/trace/__pycache__/__init__.cpython-314.pyc +0 -0
  279. package/cdh/trace/dashboard/__init__.py +61 -0
  280. package/cdh/trace/dashboard/api.py +1032 -0
  281. package/cdh/trace/dashboard/app.html +1321 -0
  282. package/cdh/trace/dashboard/server.py +310 -0
  283. package/cdh/trace/otel_exporter.py +462 -0
  284. package/cdh/trace/otel_tracer.py +281 -0
  285. package/cdh/tui.py +1084 -0
  286. package/cdh/validators/__init__.py +16 -0
  287. package/cdh/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  288. package/cdh/validators/__pycache__/bdd.cpython-314.pyc +0 -0
  289. package/cdh/validators/__pycache__/dag.cpython-314.pyc +0 -0
  290. package/cdh/validators/__pycache__/ears.cpython-314.pyc +0 -0
  291. package/cdh/validators/__pycache__/fr_namespace.cpython-314.pyc +0 -0
  292. package/cdh/validators/bdd.py +144 -0
  293. package/cdh/validators/dag.py +179 -0
  294. package/cdh/validators/ears.py +452 -0
  295. package/cdh/validators/fr_namespace.py +143 -0
  296. package/cdh/validators/spectral.py +475 -0
  297. package/cdh/verification/__init__.py +3 -0
  298. package/cdh/verification/aggregation.py +53 -0
  299. package/cdh/verification/gates/__init__.py +5 -0
  300. package/cdh/verification/gates/base.py +18 -0
  301. package/cdh/verification/gates/lint_gate.py +37 -0
  302. package/cdh/verification/gates/test_gate.py +41 -0
  303. package/cdh/verification/loop.py +93 -0
  304. package/cdh/verification/policy.py +24 -0
  305. package/onecode/__init__.py +1 -0
  306. package/onecode/__main__.py +4 -0
  307. package/onecode/__pycache__/__init__.cpython-314.pyc +0 -0
  308. package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
  309. package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
  310. package/onecode/__pycache__/config.cpython-314.pyc +0 -0
  311. package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
  312. package/onecode/agent/__init__.py +0 -0
  313. package/onecode/agent/__pycache__/__init__.cpython-314.pyc +0 -0
  314. package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
  315. package/onecode/agent/__pycache__/checkpoint.cpython-314.pyc +0 -0
  316. package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
  317. package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
  318. package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
  319. package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
  320. package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
  321. package/onecode/agent/__pycache__/permissions_store.cpython-314.pyc +0 -0
  322. package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
  323. package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
  324. package/onecode/agent/__pycache__/turn_record.cpython-314.pyc +0 -0
  325. package/onecode/agent/agents/__init__.py +29 -0
  326. package/onecode/agent/agents/__pycache__/__init__.cpython-314.pyc +0 -0
  327. package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
  328. package/onecode/agent/agents/prompts/build-agent.md +50 -0
  329. package/onecode/agent/agents/prompts/compaction-instructions.md +12 -0
  330. package/onecode/agent/agents/prompts/explore-agent.md +42 -0
  331. package/onecode/agent/agents/prompts/plan-agent.md +44 -0
  332. package/onecode/agent/agents/prompts/plan-gate-hard.md +4 -0
  333. package/onecode/agent/agents/prompts/plan-gate-soft.md +3 -0
  334. package/onecode/agent/agents/prompts/solo-agent.md +57 -0
  335. package/onecode/agent/agents/prompts/subagent-constraints.md +10 -0
  336. package/onecode/agent/agents/prompts/summary-instructions.md +7 -0
  337. package/onecode/agent/agents/prompts/title-instructions.md +3 -0
  338. package/onecode/agent/agents/prompts/tool-descriptions.md +129 -0
  339. package/onecode/agent/agents/types.py +786 -0
  340. package/onecode/agent/attachments.py +112 -0
  341. package/onecode/agent/cdh_loader.py +3 -0
  342. package/onecode/agent/checkpoint.py +285 -0
  343. package/onecode/agent/context.py +465 -0
  344. package/onecode/agent/engine.py +3547 -0
  345. package/onecode/agent/event_bridge.py +75 -0
  346. package/onecode/agent/hooks.py +86 -0
  347. package/onecode/agent/onecode_agent_acp.py +2993 -0
  348. package/onecode/agent/permissions.py +150 -0
  349. package/onecode/agent/permissions_store.py +73 -0
  350. package/onecode/agent/project_doc.py +19 -0
  351. package/onecode/agent/question_detect.py +230 -0
  352. package/onecode/agent/session.py +3 -0
  353. package/onecode/agent/snapshot.py +144 -0
  354. package/onecode/agent/tools/__init__.py +17 -0
  355. package/onecode/agent/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  356. package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
  357. package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
  358. package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
  359. package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
  360. package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
  361. package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
  362. package/onecode/agent/tools/__pycache__/errors.cpython-314.pyc +0 -0
  363. package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
  364. package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
  365. package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
  366. package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
  367. package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
  368. package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
  369. package/onecode/agent/tools/__pycache__/permissions.cpython-314.pyc +0 -0
  370. package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
  371. package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
  372. package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
  373. package/onecode/agent/tools/__pycache__/schema_validation.cpython-314.pyc +0 -0
  374. package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
  375. package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
  376. package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
  377. package/onecode/agent/tools/agent_tools.py +128 -0
  378. package/onecode/agent/tools/apply_patch_tool.py +138 -0
  379. package/onecode/agent/tools/bash_tool.py +121 -0
  380. package/onecode/agent/tools/communication_tools.py +154 -0
  381. package/onecode/agent/tools/config_tool.py +130 -0
  382. package/onecode/agent/tools/cron_tools.py +178 -0
  383. package/onecode/agent/tools/errors.py +17 -0
  384. package/onecode/agent/tools/file_ops.py +221 -0
  385. package/onecode/agent/tools/file_tools.py +225 -0
  386. package/onecode/agent/tools/git_tools.py +88 -0
  387. package/onecode/agent/tools/lsp_tools.py +404 -0
  388. package/onecode/agent/tools/mcp_tools.py +211 -0
  389. package/onecode/agent/tools/permission_handler.py +46 -0
  390. package/onecode/agent/tools/permissions.py +77 -0
  391. package/onecode/agent/tools/protocol.py +20 -0
  392. package/onecode/agent/tools/registry.py +210 -0
  393. package/onecode/agent/tools/sandbox.py +460 -0
  394. package/onecode/agent/tools/schema_validation.py +100 -0
  395. package/onecode/agent/tools/skill_tools.py +52 -0
  396. package/onecode/agent/tools/todo_tools.py +208 -0
  397. package/onecode/agent/tools/web_tools.py +530 -0
  398. package/onecode/agent/turn_record.py +28 -0
  399. package/onecode/builtin_skills/agent-browser/SKILL.md +212 -0
  400. package/onecode/builtin_skills/agent-browser/skill.yaml +8 -0
  401. package/onecode/builtin_skills/cloudbase/SKILL.md +162 -0
  402. package/onecode/builtin_skills/cloudbase/skill.yaml +7 -0
  403. package/onecode/builtin_skills/git/SKILL.md +64 -0
  404. package/onecode/builtin_skills/git/skill.yaml +7 -0
  405. package/onecode/builtin_skills/shell/SKILL.md +58 -0
  406. package/onecode/builtin_skills/shell/skill.yaml +8 -0
  407. package/onecode/builtin_skills/skill-creator/SKILL.md +106 -0
  408. package/onecode/builtin_skills/skill-creator/skill.yaml +8 -0
  409. package/onecode/cli.py +1325 -0
  410. package/onecode/codebase/__init__.py +69 -0
  411. package/onecode/codebase/__pycache__/__init__.cpython-314.pyc +0 -0
  412. package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
  413. package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
  414. package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
  415. package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
  416. package/onecode/codebase/__pycache__/tools.cpython-314.pyc +0 -0
  417. package/onecode/codebase/chunker.py +125 -0
  418. package/onecode/codebase/indexer.py +154 -0
  419. package/onecode/codebase/retriever.py +240 -0
  420. package/onecode/codebase/storage.py +153 -0
  421. package/onecode/codebase/tools.py +59 -0
  422. package/onecode/commands.py +673 -0
  423. package/onecode/config.py +539 -0
  424. package/onecode/config_screen.py +486 -0
  425. package/onecode/cron/__init__.py +3 -0
  426. package/onecode/lsp/__init__.py +3 -0
  427. package/onecode/mcp/__init__.py +11 -0
  428. package/onecode/mcp/__pycache__/__init__.cpython-314.pyc +0 -0
  429. package/onecode/mcp/__pycache__/client.cpython-314.pyc +0 -0
  430. package/onecode/mcp/__pycache__/cloudbase.cpython-314.pyc +0 -0
  431. package/onecode/mcp/__pycache__/config.cpython-314.pyc +0 -0
  432. package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
  433. package/onecode/mcp/__pycache__/oauth.cpython-314.pyc +0 -0
  434. package/onecode/mcp/client.py +305 -0
  435. package/onecode/mcp/cloudbase.py +188 -0
  436. package/onecode/mcp/config.py +363 -0
  437. package/onecode/mcp/manager.py +603 -0
  438. package/onecode/mcp/oauth.py +199 -0
  439. package/onecode/memory/__init__.py +106 -0
  440. package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
  441. package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
  442. package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
  443. package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
  444. package/onecode/memory/backend.py +179 -0
  445. package/onecode/memory/pyramid.py +145 -0
  446. package/onecode/memory/recall.py +322 -0
  447. package/onecode/migrate.py +122 -0
  448. package/onecode/models/__init__.py +4 -0
  449. package/onecode/models/__pycache__/__init__.cpython-314.pyc +0 -0
  450. package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
  451. package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
  452. package/onecode/models/__pycache__/ollama_manager.cpython-314.pyc +0 -0
  453. package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
  454. package/onecode/models/__pycache__/registry.cpython-314.pyc +0 -0
  455. package/onecode/models/errors.py +104 -0
  456. package/onecode/models/messages.py +750 -0
  457. package/onecode/models/ollama_manager.py +167 -0
  458. package/onecode/models/provider.py +730 -0
  459. package/onecode/models/providers/__init__.py +17 -0
  460. package/onecode/models/providers/__pycache__/__init__.cpython-314.pyc +0 -0
  461. package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
  462. package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
  463. package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
  464. package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
  465. package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
  466. package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
  467. package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
  468. package/onecode/models/providers/anthropic_provider.py +286 -0
  469. package/onecode/models/providers/deepseek_provider.py +221 -0
  470. package/onecode/models/providers/glm_provider.py +219 -0
  471. package/onecode/models/providers/minimax_provider.py +182 -0
  472. package/onecode/models/providers/minimaxi_provider.py +426 -0
  473. package/onecode/models/providers/ollama_provider.py +183 -0
  474. package/onecode/models/providers/openai_provider.py +234 -0
  475. package/onecode/models/registry.py +349 -0
  476. package/onecode/server/__init__.py +3 -0
  477. package/onecode/server/app.py +251 -0
  478. package/onecode/skills/__init__.py +11 -0
  479. package/onecode/skills/__pycache__/__init__.cpython-314.pyc +0 -0
  480. package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
  481. package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
  482. package/onecode/skills/__pycache__/create.cpython-314.pyc +0 -0
  483. package/onecode/skills/__pycache__/frontmatter.cpython-314.pyc +0 -0
  484. package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
  485. package/onecode/skills/__pycache__/model.cpython-314.pyc +0 -0
  486. package/onecode/skills/argument_substitution.py +38 -0
  487. package/onecode/skills/bootstrap.py +37 -0
  488. package/onecode/skills/create.py +56 -0
  489. package/onecode/skills/frontmatter.py +33 -0
  490. package/onecode/skills/loader.py +215 -0
  491. package/onecode/skills/manager.py +75 -0
  492. package/onecode/skills/model.py +43 -0
  493. package/onecode/storage/__init__.py +0 -0
  494. package/onecode/storage/activity.py +63 -0
  495. package/onecode/storage/project.py +54 -0
  496. package/onecode/storage/session.py +112 -0
  497. package/onecode/tasks/__init__.py +26 -0
  498. package/onecode/tasks/manager.py +232 -0
  499. package/onecode/tasks/models.py +240 -0
  500. package/onecode/trace/__init__.py +0 -0
  501. package/onecode/trace/tracer.py +173 -0
  502. package/onecode/utils/__init__.py +0 -0
  503. package/onecode/utils/helpers.py +20 -0
  504. package/onecode/verification/__init__.py +5 -0
  505. package/onecode/verification/__pycache__/__init__.cpython-314.pyc +0 -0
  506. package/onecode/verification/__pycache__/aggregation.cpython-314.pyc +0 -0
  507. package/onecode/verification/__pycache__/loop.cpython-314.pyc +0 -0
  508. package/onecode/verification/__pycache__/policy.cpython-314.pyc +0 -0
  509. package/onecode/verification/aggregation.py +53 -0
  510. package/onecode/verification/gates/__init__.py +6 -0
  511. package/onecode/verification/gates/__pycache__/__init__.cpython-314.pyc +0 -0
  512. package/onecode/verification/gates/__pycache__/base.cpython-314.pyc +0 -0
  513. package/onecode/verification/gates/__pycache__/lint_gate.cpython-314.pyc +0 -0
  514. package/onecode/verification/gates/__pycache__/test_gate.cpython-314.pyc +0 -0
  515. package/onecode/verification/gates/__pycache__/type_gate.cpython-314.pyc +0 -0
  516. package/onecode/verification/gates/base.py +20 -0
  517. package/onecode/verification/gates/lint_gate.py +45 -0
  518. package/onecode/verification/gates/test_gate.py +62 -0
  519. package/onecode/verification/gates/type_gate.py +46 -0
  520. package/onecode/verification/loop.py +95 -0
  521. package/onecode/verification/policy.py +29 -0
  522. package/package.json +2 -2
  523. package/pyproject.toml +84 -0
  524. package/tui/__init__.py +46 -0
  525. package/tui/__main__.py +4 -0
  526. package/tui/__pycache__/__init__.cpython-314.pyc +0 -0
  527. package/tui/__pycache__/_loop.cpython-314.pyc +0 -0
  528. package/tui/__pycache__/_path_fuzzy_search.cpython-314.pyc +0 -0
  529. package/tui/__pycache__/_path_match.cpython-314.pyc +0 -0
  530. package/tui/__pycache__/agent.cpython-314.pyc +0 -0
  531. package/tui/__pycache__/agent_schema.cpython-314.pyc +0 -0
  532. package/tui/__pycache__/agents.cpython-314.pyc +0 -0
  533. package/tui/__pycache__/answer.cpython-314.pyc +0 -0
  534. package/tui/__pycache__/app.cpython-314.pyc +0 -0
  535. package/tui/__pycache__/atomic.cpython-314.pyc +0 -0
  536. package/tui/__pycache__/complete.cpython-314.pyc +0 -0
  537. package/tui/__pycache__/constants.cpython-314.pyc +0 -0
  538. package/tui/__pycache__/conversation_markdown.cpython-314.pyc +0 -0
  539. package/tui/__pycache__/db.cpython-314.pyc +0 -0
  540. package/tui/__pycache__/dec.cpython-314.pyc +0 -0
  541. package/tui/__pycache__/directory.cpython-314.pyc +0 -0
  542. package/tui/__pycache__/directory_watcher.cpython-314.pyc +0 -0
  543. package/tui/__pycache__/format_path.cpython-314.pyc +0 -0
  544. package/tui/__pycache__/fuzzy.cpython-314.pyc +0 -0
  545. package/tui/__pycache__/fuzzy_index.cpython-314.pyc +0 -0
  546. package/tui/__pycache__/history.cpython-314.pyc +0 -0
  547. package/tui/__pycache__/jsonrpc.cpython-314.pyc +0 -0
  548. package/tui/__pycache__/menus.cpython-314.pyc +0 -0
  549. package/tui/__pycache__/message_log.cpython-314.pyc +0 -0
  550. package/tui/__pycache__/messages.cpython-314.pyc +0 -0
  551. package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
  552. package/tui/__pycache__/path_filter.cpython-314.pyc +0 -0
  553. package/tui/__pycache__/paths.cpython-314.pyc +0 -0
  554. package/tui/__pycache__/pill.cpython-314.pyc +0 -0
  555. package/tui/__pycache__/platform_commands.cpython-314.pyc +0 -0
  556. package/tui/__pycache__/protocol.cpython-314.pyc +0 -0
  557. package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
  558. package/tui/__pycache__/settings.cpython-314.pyc +0 -0
  559. package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
  560. package/tui/__pycache__/shell.cpython-314.pyc +0 -0
  561. package/tui/__pycache__/shell_read.cpython-314.pyc +0 -0
  562. package/tui/__pycache__/slash_command.cpython-314.pyc +0 -0
  563. package/tui/__pycache__/version.cpython-314.pyc +0 -0
  564. package/tui/_loop.py +86 -0
  565. package/tui/_path_fuzzy_search.py +48 -0
  566. package/tui/_path_match.py +141 -0
  567. package/tui/about.py +95 -0
  568. package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
  569. package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
  570. package/tui/acp/__pycache__/encode_tool_call_id.cpython-314.pyc +0 -0
  571. package/tui/acp/__pycache__/event_tap.cpython-314.pyc +0 -0
  572. package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
  573. package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
  574. package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
  575. package/tui/acp/agent.py +1212 -0
  576. package/tui/acp/api.py +79 -0
  577. package/tui/acp/encode_tool_call_id.py +12 -0
  578. package/tui/acp/event_tap.py +107 -0
  579. package/tui/acp/messages.py +222 -0
  580. package/tui/acp/prompt.py +53 -0
  581. package/tui/acp/protocol.py +551 -0
  582. package/tui/agent.py +70 -0
  583. package/tui/agent_schema.py +76 -0
  584. package/tui/agents.py +46 -0
  585. package/tui/ansi/__init__.py +1 -0
  586. package/tui/ansi/__pycache__/__init__.cpython-314.pyc +0 -0
  587. package/tui/ansi/__pycache__/_ansi.cpython-314.pyc +0 -0
  588. package/tui/ansi/__pycache__/_ansi_colors.cpython-314.pyc +0 -0
  589. package/tui/ansi/__pycache__/_control_codes.cpython-314.pyc +0 -0
  590. package/tui/ansi/__pycache__/_keys.cpython-314.pyc +0 -0
  591. package/tui/ansi/__pycache__/_sgr_styles.cpython-314.pyc +0 -0
  592. package/tui/ansi/__pycache__/_stream_parser.cpython-314.pyc +0 -0
  593. package/tui/ansi/_ansi.py +1689 -0
  594. package/tui/ansi/_ansi_colors.py +264 -0
  595. package/tui/ansi/_control_codes.py +37 -0
  596. package/tui/ansi/_keys.py +251 -0
  597. package/tui/ansi/_sgr_styles.py +64 -0
  598. package/tui/ansi/_stream_parser.py +418 -0
  599. package/tui/answer.py +12 -0
  600. package/tui/app.py +1195 -0
  601. package/tui/atomic.py +37 -0
  602. package/tui/cli.py +208 -0
  603. package/tui/code_analyze.py +27 -0
  604. package/tui/complete.py +38 -0
  605. package/tui/constants.py +61 -0
  606. package/tui/conversation_markdown.py +30 -0
  607. package/tui/danger.py +372 -0
  608. package/tui/data/agents/ampcode.com.toml +52 -0
  609. package/tui/data/agents/augmentcode.com.toml +41 -0
  610. package/tui/data/agents/cdh.cloud-dev-harness.toml +23 -0
  611. package/tui/data/agents/claude.com.toml +41 -0
  612. package/tui/data/agents/copilot.github.com.toml +29 -0
  613. package/tui/data/agents/crowai.dev.toml +36 -0
  614. package/tui/data/agents/cursor.com.toml +38 -0
  615. package/tui/data/agents/deepagents.langchain.com +34 -0
  616. package/tui/data/agents/docker.com.toml +60 -0
  617. package/tui/data/agents/geminicli.com.toml +28 -0
  618. package/tui/data/agents/goose.ai.toml +52 -0
  619. package/tui/data/agents/inference.huggingface.co.toml +41 -0
  620. package/tui/data/agents/kimi.com.toml +35 -0
  621. package/tui/data/agents/kiro.dev.toml +43 -0
  622. package/tui/data/agents/onecode.dev.toml +22 -0
  623. package/tui/data/agents/openai.com.toml +53 -0
  624. package/tui/data/agents/openclaw.ai.toml +37 -0
  625. package/tui/data/agents/opencode.ai.toml +39 -0
  626. package/tui/data/agents/openhands.dev.toml +46 -0
  627. package/tui/data/agents/stakpak.dev.toml +62 -0
  628. package/tui/data/agents/vibe.mistral.ai.toml +31 -0
  629. package/tui/data/agents/vtcode.dev.toml +63 -0
  630. package/tui/data/images/frog.png +0 -0
  631. package/tui/data/sounds/question.wav +0 -0
  632. package/tui/data/sounds/turn-over.wav +0 -0
  633. package/tui/db.py +213 -0
  634. package/tui/dec.py +332 -0
  635. package/tui/diff_utils.py +131 -0
  636. package/tui/directory.py +234 -0
  637. package/tui/directory_suggester.py +93 -0
  638. package/tui/directory_watcher.py +231 -0
  639. package/tui/format_path.py +25 -0
  640. package/tui/fuzzy.py +140 -0
  641. package/tui/fuzzy_index.py +275 -0
  642. package/tui/gist.py +33 -0
  643. package/tui/history.py +138 -0
  644. package/tui/jsonrpc.py +599 -0
  645. package/tui/menus.py +14 -0
  646. package/tui/message_log.py +69 -0
  647. package/tui/messages.py +144 -0
  648. package/tui/option_content.py +51 -0
  649. package/tui/os.py +0 -0
  650. package/tui/path_complete.py +217 -0
  651. package/tui/path_filter.py +124 -0
  652. package/tui/paths.py +87 -0
  653. package/tui/pill.py +23 -0
  654. package/tui/platform_commands.py +52 -0
  655. package/tui/prompt/__pycache__/extract.cpython-314.pyc +0 -0
  656. package/tui/prompt/__pycache__/resource.cpython-314.pyc +0 -0
  657. package/tui/prompt/extract.py +19 -0
  658. package/tui/prompt/resource.py +68 -0
  659. package/tui/protocol.py +28 -0
  660. package/tui/screens/__init__.py +0 -0
  661. package/tui/screens/__pycache__/__init__.cpython-314.pyc +0 -0
  662. package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
  663. package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
  664. package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
  665. package/tui/screens/action_modal.py +94 -0
  666. package/tui/screens/agent_modal.py +175 -0
  667. package/tui/screens/command_edit_modal.py +74 -0
  668. package/tui/screens/diff_explorer_screen.py +419 -0
  669. package/tui/screens/diff_screen.py +84 -0
  670. package/tui/screens/ide_screen.py +461 -0
  671. package/tui/screens/main.py +397 -0
  672. package/tui/screens/main.tcss +662 -0
  673. package/tui/screens/permissions.py +404 -0
  674. package/tui/screens/permissions.tcss +72 -0
  675. package/tui/screens/projects.tcss +84 -0
  676. package/tui/screens/projects_app.py +341 -0
  677. package/tui/screens/projects_screen.py +277 -0
  678. package/tui/screens/session_resume_modal.py +172 -0
  679. package/tui/screens/session_resume_modal.tcss +35 -0
  680. package/tui/screens/sessions.py +171 -0
  681. package/tui/screens/sessions.tcss +119 -0
  682. package/tui/screens/settings.py +293 -0
  683. package/tui/screens/settings.tcss +113 -0
  684. package/tui/screens/store.py +502 -0
  685. package/tui/screens/store.tcss +274 -0
  686. package/tui/screens/tool_content_screen.py +59 -0
  687. package/tui/screens/trace.py +317 -0
  688. package/tui/session_tracker.py +123 -0
  689. package/tui/settings.py +353 -0
  690. package/tui/settings_schema.py +467 -0
  691. package/tui/shell.py +304 -0
  692. package/tui/shell_read.py +42 -0
  693. package/tui/slash_command.py +34 -0
  694. package/tui/tui.tcss +246 -0
  695. package/tui/twitter.py +38 -0
  696. package/tui/version.py +80 -0
  697. package/tui/visuals/__init__.py +0 -0
  698. package/tui/visuals/__pycache__/__init__.cpython-314.pyc +0 -0
  699. package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
  700. package/tui/visuals/columns.py +272 -0
  701. package/tui/widgets/__init__.py +0 -0
  702. package/tui/widgets/__pycache__/__init__.cpython-314.pyc +0 -0
  703. package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
  704. package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
  705. package/tui/widgets/__pycache__/aidlc.cpython-314.pyc +0 -0
  706. package/tui/widgets/__pycache__/ask_user.cpython-314.pyc +0 -0
  707. package/tui/widgets/__pycache__/condensed_path.cpython-314.pyc +0 -0
  708. package/tui/widgets/__pycache__/context_stats.cpython-314.pyc +0 -0
  709. package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
  710. package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
  711. package/tui/widgets/__pycache__/flash.cpython-314.pyc +0 -0
  712. package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
  713. package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
  714. package/tui/widgets/__pycache__/highlighted_textarea.cpython-314.pyc +0 -0
  715. package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
  716. package/tui/widgets/__pycache__/menu.cpython-314.pyc +0 -0
  717. package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
  718. package/tui/widgets/__pycache__/non_selectable_label.cpython-314.pyc +0 -0
  719. package/tui/widgets/__pycache__/note.cpython-314.pyc +0 -0
  720. package/tui/widgets/__pycache__/path_search.cpython-314.pyc +0 -0
  721. package/tui/widgets/__pycache__/pending_prompts.cpython-314.pyc +0 -0
  722. package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
  723. package/tui/widgets/__pycache__/project_directory_tree.cpython-314.pyc +0 -0
  724. package/tui/widgets/__pycache__/prompt.cpython-314.pyc +0 -0
  725. package/tui/widgets/__pycache__/question.cpython-314.pyc +0 -0
  726. package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
  727. package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
  728. package/tui/widgets/__pycache__/session_tabs.cpython-314.pyc +0 -0
  729. package/tui/widgets/__pycache__/shell_terminal.cpython-314.pyc +0 -0
  730. package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
  731. package/tui/widgets/__pycache__/slash_complete.cpython-314.pyc +0 -0
  732. package/tui/widgets/__pycache__/strike_text.cpython-314.pyc +0 -0
  733. package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
  734. package/tui/widgets/__pycache__/throbber.cpython-314.pyc +0 -0
  735. package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
  736. package/tui/widgets/__pycache__/user_input.cpython-314.pyc +0 -0
  737. package/tui/widgets/acp_content.py +70 -0
  738. package/tui/widgets/agent_response.py +76 -0
  739. package/tui/widgets/agent_thought.py +167 -0
  740. package/tui/widgets/aidlc.py +334 -0
  741. package/tui/widgets/ask_user.py +604 -0
  742. package/tui/widgets/command_pane.py +223 -0
  743. package/tui/widgets/condensed_path.py +115 -0
  744. package/tui/widgets/context_stats.py +66 -0
  745. package/tui/widgets/conversation.py +3235 -0
  746. package/tui/widgets/danger_warning.py +65 -0
  747. package/tui/widgets/diff_view.py +69 -0
  748. package/tui/widgets/directory_input.py +8 -0
  749. package/tui/widgets/edit_field.py +206 -0
  750. package/tui/widgets/flash.py +81 -0
  751. package/tui/widgets/future_text.py +126 -0
  752. package/tui/widgets/grid_select.py +234 -0
  753. package/tui/widgets/highlighted_textarea.py +183 -0
  754. package/tui/widgets/load_more.py +24 -0
  755. package/tui/widgets/mandelbrot.py +294 -0
  756. package/tui/widgets/markdown_note.py +13 -0
  757. package/tui/widgets/menu.py +147 -0
  758. package/tui/widgets/model_status.py +230 -0
  759. package/tui/widgets/modified_files.py +315 -0
  760. package/tui/widgets/non_selectable_label.py +5 -0
  761. package/tui/widgets/note.py +18 -0
  762. package/tui/widgets/path_search.py +492 -0
  763. package/tui/widgets/pending_prompts.py +36 -0
  764. package/tui/widgets/plan.py +285 -0
  765. package/tui/widgets/project_directory_tree.py +102 -0
  766. package/tui/widgets/project_grid_select.py +68 -0
  767. package/tui/widgets/project_summary.py +33 -0
  768. package/tui/widgets/prompt.py +935 -0
  769. package/tui/widgets/question.py +360 -0
  770. package/tui/widgets/session_grid_select.py +230 -0
  771. package/tui/widgets/session_summary.py +115 -0
  772. package/tui/widgets/session_tabs.py +194 -0
  773. package/tui/widgets/shell_result.py +35 -0
  774. package/tui/widgets/shell_terminal.py +40 -0
  775. package/tui/widgets/side_bar.py +124 -0
  776. package/tui/widgets/slash_complete.py +235 -0
  777. package/tui/widgets/strike_text.py +70 -0
  778. package/tui/widgets/subagent.py +287 -0
  779. package/tui/widgets/subagent_screen.py +715 -0
  780. package/tui/widgets/terminal.py +576 -0
  781. package/tui/widgets/terminal_tool.py +360 -0
  782. package/tui/widgets/throbber.py +100 -0
  783. package/tui/widgets/tool_call.py +432 -0
  784. package/tui/widgets/user_input.py +23 -0
  785. package/tui/widgets/version.py +5 -0
  786. package/tui/widgets/welcome.py +31 -0
@@ -0,0 +1,1436 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
5
+ import re
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+
9
+ import yaml
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class ComponentSpec:
16
+ id: str
17
+ kind: str
18
+ owns: str
19
+ fr_prefix: str
20
+ tech: str
21
+ label: str
22
+ description: str
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class CrossCutSpec:
27
+ id: str
28
+ paths: tuple[str, ...]
29
+ label: str
30
+ description: str
31
+
32
+
33
+ COMPONENTS: tuple[ComponentSpec, ...] = (
34
+ ComponentSpec(
35
+ id="native",
36
+ kind="mobile",
37
+ owns="apps/native",
38
+ fr_prefix="NATIVE",
39
+ tech="react-native | flutter",
40
+ label="Mobile App",
41
+ description="iOS/Android cross-platform (RN/Flutter)",
42
+ ),
43
+ ComponentSpec(
44
+ id="desktop",
45
+ kind="desktop",
46
+ owns="apps/desktop",
47
+ fr_prefix="DESKTOP",
48
+ tech="electron | tauri",
49
+ label="Desktop App",
50
+ description="Cross-platform desktop (Electron/Tauri)",
51
+ ),
52
+ ComponentSpec(
53
+ id="backend",
54
+ kind="service",
55
+ owns="apps/backend",
56
+ fr_prefix="BE",
57
+ tech="python | node | go",
58
+ label="Backend Service",
59
+ description="HTTP API/microservice (Python/Node/Go)",
60
+ ),
61
+ ComponentSpec(
62
+ id="wxa",
63
+ kind="mini-program",
64
+ owns="apps/wxa",
65
+ fr_prefix="WXA",
66
+ tech="miniprogram",
67
+ label="WeChat Mini-Program",
68
+ description="WeChat ecosystem mini-program",
69
+ ),
70
+ ComponentSpec(
71
+ id="mya",
72
+ kind="mini-program",
73
+ owns="apps/mya",
74
+ fr_prefix="MYA",
75
+ tech="miniprogram",
76
+ label="Alipay Mini-Program",
77
+ description="Alipay ecosystem mini-program",
78
+ ),
79
+ ComponentSpec(
80
+ id="tta",
81
+ kind="mini-program",
82
+ owns="apps/tta",
83
+ fr_prefix="TTA",
84
+ tech="miniprogram",
85
+ label="TikTok Mini-Program",
86
+ description="TikTok/Douyin ecosystem mini-program",
87
+ ),
88
+ )
89
+
90
+
91
+ COMPONENT_BY_ID: dict[str, ComponentSpec] = {c.id: c for c in COMPONENTS}
92
+
93
+
94
+ CROSS_CUTTING: tuple[CrossCutSpec, ...] = (
95
+ CrossCutSpec(
96
+ id="contracts",
97
+ paths=("aidlc/contracts/CHANGELOG.md",),
98
+ label="Interface Contracts",
99
+ description="API/event contracts and changelog",
100
+ ),
101
+ CrossCutSpec(
102
+ id="shared",
103
+ paths=("aidlc/packages/shared",),
104
+ label="Shared Types",
105
+ description="Cross-component shared types package",
106
+ ),
107
+ CrossCutSpec(
108
+ id="openspec",
109
+ paths=(),
110
+ label="OpenSpec Changes",
111
+ description="OpenSpec change proposals",
112
+ ),
113
+ CrossCutSpec(
114
+ id="cross_stack_features",
115
+ paths=(),
116
+ label="Cross-Stack BDD",
117
+ description="End-to-end BDD features across components",
118
+ ),
119
+ CrossCutSpec(
120
+ id="cross_stack_tests",
121
+ paths=("aidlc/tests/contract", "aidlc/tests/cross-stack"),
122
+ label="Cross-Stack Tests",
123
+ description="Contract tests and cross-stack integration tests",
124
+ ),
125
+ CrossCutSpec(
126
+ id="provider",
127
+ paths=(
128
+ "aidlc/providers/tcb/provider.yaml",
129
+ "aidlc/providers/tcb/deployment.yaml",
130
+ "aidlc/providers/tcb/preview.yaml",
131
+ ),
132
+ label="Cloud Provider",
133
+ description="TCB (Tencent CloudBase) provider config",
134
+ ),
135
+ CrossCutSpec(
136
+ id="tools",
137
+ paths=(
138
+ "aidlc/tools/deploy_stack.py",
139
+ "aidlc/tools/contract_diff.py",
140
+ "aidlc/tools/generate_shared.py",
141
+ "aidlc/tools/bvt.py",
142
+ ),
143
+ label="Tooling Scripts",
144
+ description="deploy_stack / contract_diff / generate_shared / bvt scripts",
145
+ ),
146
+ )
147
+
148
+
149
+ CROSS_CUTTING_BY_ID: dict[str, CrossCutSpec] = {c.id: c for c in CROSS_CUTTING}
150
+
151
+
152
+ TCB_PROVIDER_YAML = """provider:
153
+ name: tcb
154
+ display_name: Tencent CloudBase
155
+ default: true
156
+ version: 3.0.0
157
+
158
+ storage:
159
+ object_storage: cloudbase-storage
160
+ document_db: docdb
161
+ relational_db: mysql
162
+ cdn: tencent-cloud-cdn
163
+ """
164
+
165
+ TCB_DEPLOYMENT_YAML = """environments:
166
+ preview:
167
+ orchestrator: deploy_stack
168
+ strategy: unified
169
+ ttl: 24h
170
+ staging:
171
+ orchestrator: deploy_stack
172
+ production:
173
+ orchestrator: deploy_stack
174
+ pre_conditions:
175
+ - human-approval-gate
176
+ """
177
+
178
+ TCB_PREVIEW_YAML = """preview:
179
+ orchestrator: deploy_stack
180
+ strategy: unified
181
+ ttl: 24h
182
+ auto_cleanup: true
183
+ db_sandbox: true
184
+ """
185
+
186
+ CONTRACT_DIFF_PY = '''#!/usr/bin/env python3
187
+ """Contract diff tool — checks API/event contract compatibility."""
188
+ import argparse
189
+ import sys
190
+ from pathlib import Path
191
+
192
+
193
+ def main():
194
+ parser = argparse.ArgumentParser(description="Check contract compatibility")
195
+ parser.add_argument("--base", default="origin/main", help="Base commit/branch")
196
+ parser.add_argument("--head", default="HEAD", help="Head commit/branch")
197
+ parser.add_argument("--contracts-dir", default="aidlc/contracts", help="Contracts directory")
198
+ parser.add_argument("--output", default="json", choices=["json", "text"], help="Output format")
199
+ args = parser.parse_args()
200
+
201
+ contracts_dir = Path(args.contracts_dir)
202
+ if not contracts_dir.exists():
203
+ print(f"No contracts directory found: {contracts_dir}")
204
+ sys.exit(1)
205
+
206
+ api_dir = contracts_dir / "api"
207
+ events_dir = contracts_dir / "events"
208
+
209
+ changes = {"breaking": [], "additions": [], "deletions": []}
210
+
211
+ if args.output == "json":
212
+ import json
213
+ print(json.dumps(changes, indent=2))
214
+ else:
215
+ print("Contract diff complete. No breaking changes detected.")
216
+ sys.exit(0)
217
+
218
+
219
+ if __name__ == "__main__":
220
+ main()
221
+ '''
222
+
223
+ DEPLOY_STACK_PY = '''#!/usr/bin/env python3
224
+ """Deploy stack tool — deploys unified stack to target environment."""
225
+ import argparse
226
+ import sys
227
+
228
+
229
+ def main():
230
+ parser = argparse.ArgumentParser(description="Deploy unified stack")
231
+ parser.add_argument("--environment", "-e", required=True, choices=["preview", "staging", "production"])
232
+ parser.add_argument("--components", nargs="*", help="Components to deploy (default: all)")
233
+ parser.add_argument("--output", choices=["url", "json"], help="Output format")
234
+ args = parser.parse_args()
235
+
236
+ if args.environment == "production":
237
+ print("WARNING: Deploying to production requires human approval gate")
238
+ print("Use --approve flag to confirm production deployment")
239
+
240
+ output = {
241
+ "environment": args.environment,
242
+ "components": args.components or ["all"],
243
+ "url": f"https://preview.example.com",
244
+ }
245
+
246
+ if args.output == "json":
247
+ import json
248
+ print(json.dumps(output, indent=2))
249
+ else:
250
+ print(f"Deployed to {args.environment}")
251
+ print(f"URL: {output['url']}")
252
+ sys.exit(0)
253
+
254
+
255
+ if __name__ == "__main__":
256
+ main()
257
+ '''
258
+
259
+ GENERATE_SHARED_PY = '''#!/usr/bin/env python3
260
+ """Generate shared types from OpenAPI/AsyncAPI contracts."""
261
+ import argparse
262
+ import sys
263
+
264
+
265
+ def main():
266
+ parser = argparse.ArgumentParser(description="Generate shared type definitions")
267
+ parser.add_argument("--contracts-dir", default="aidlc/contracts", help="Contracts directory")
268
+ parser.add_argument("--output-dir", default="aidlc/packages/shared", help="Output directory")
269
+ parser.add_argument("--lang", default="typescript", choices=["typescript", "python", "go"], help="Target language")
270
+ args = parser.parse_args()
271
+
272
+ contracts_dir = Path(args.contracts_dir)
273
+ if not contracts_dir.exists():
274
+ print(f"No contracts directory found: {contracts_dir}")
275
+ sys.exit(1)
276
+
277
+ output_dir = Path(args.output_dir)
278
+ output_dir.mkdir(parents=True, exist_ok=True)
279
+
280
+ print(f"Generated {args.lang} types in {output_dir}")
281
+ sys.exit(0)
282
+
283
+
284
+ if __name__ == "__main__":
285
+ main()
286
+ '''
287
+
288
+ BVT_PY = '''#!/usr/bin/env python3
289
+ """BVT (Baseline Verification Test) — smoke test for production deployment."""
290
+ import argparse
291
+ import sys
292
+
293
+
294
+ CHECKS = {
295
+ "health": ("Backend /health endpoint", lambda url: True),
296
+ "home": ("Web home page loads", lambda url: True),
297
+ "login": ("Core login flow works", lambda url: True),
298
+ "db": ("Database connectivity", lambda url: True),
299
+ "error_rate": ("Error rate < 0.1%", lambda url: True),
300
+ }
301
+
302
+
303
+ def main():
304
+ parser = argparse.ArgumentParser(description="Run BVT smoke tests")
305
+ parser.add_argument("--url", required=True, help="Stack URL to test")
306
+ parser.add_argument("--checks", nargs="*", default=list(CHECKS.keys()), help="Checks to run")
307
+ parser.add_argument("--json", action="store_true", help="JSON output")
308
+ args = parser.parse_args()
309
+
310
+ results = {}
311
+ for check in args.checks:
312
+ if check in CHECKS:
313
+ results[check] = {"passed": True, "description": CHECKS[check][0]}
314
+ else:
315
+ results[check] = {"passed": False, "error": f"Unknown check: {check}"}
316
+
317
+ passed = sum(1 for r in results.values() if r.get("passed"))
318
+ total = len(results)
319
+
320
+ if args.json:
321
+ import json
322
+ print(json.dumps({"passed": passed, "total": total, "results": results}, indent=2))
323
+ else:
324
+ print(f"BVT: {passed}/{total} checks passed")
325
+ for check, result in results.items():
326
+ status = "✓" if result.get("passed") else "✗"
327
+ print(f" {status} {check}: {result.get('description') or result.get('error')}")
328
+
329
+ sys.exit(0 if passed == total else 1)
330
+
331
+
332
+ if __name__ == "__main__":
333
+ main()
334
+ '''
335
+
336
+ TOOL_STUB = '''#!/usr/bin/env python3
337
+ """Stub — auto-generated by cdh scaffold."""
338
+ import sys
339
+
340
+
341
+ def main():
342
+ print(f"{__file__}: not yet implemented")
343
+ sys.exit(1)
344
+
345
+
346
+ if __name__ == "__main__":
347
+ main()
348
+ '''
349
+
350
+ ALIYUN_PROVIDER_YAML = """provider:
351
+ name: aliyun
352
+ display_name: Alibaba Cloud
353
+ default: false
354
+ version: 3.0.0
355
+
356
+ storage:
357
+ object_storage: oss
358
+ document_db: mongodb
359
+ relational_db: rds-mysql
360
+ cdn: aliyun-cdn
361
+ """
362
+
363
+ ALIYUN_DEPLOYMENT_YAML = """environments:
364
+ preview:
365
+ orchestrator: deploy_stack
366
+ strategy: unified
367
+ ttl: 24h
368
+ staging:
369
+ orchestrator: deploy_stack
370
+ production:
371
+ orchestrator: deploy_stack
372
+ pre_conditions:
373
+ - human-approval-gate
374
+ """
375
+
376
+ ALIYUN_PREVIEW_YAML = """preview:
377
+ orchestrator: deploy_stack
378
+ strategy: unified
379
+ ttl: 24h
380
+ auto_cleanup: true
381
+ db_sandbox: true
382
+ """
383
+
384
+ GITHUB_ACTIONS_CI_YAML = """name: AIDLC Quality Gates
385
+ on:
386
+ push:
387
+ branches: [main]
388
+ pull_request:
389
+ branches: [main]
390
+
391
+ jobs:
392
+ validate:
393
+ runs-on: ubuntu-latest
394
+ steps:
395
+ - uses: actions/checkout@v4
396
+ with:
397
+ fetch-depth: 0
398
+ - uses: actions/setup-python@v5
399
+ with:
400
+ python-version: "3.14"
401
+ - name: Install cdh
402
+ run: pip install cdh
403
+ - name: Validate spec quality
404
+ run: cdh aidlc validate --format json
405
+ - name: Contract compat check
406
+ run: |
407
+ cdh aidlc tools install
408
+ python aidlc/tools/contract_diff.py --base origin/main --head HEAD \\
409
+ --project-root .
410
+ - name: Run tests
411
+ run: |
412
+ pip install pytest pytest-cov pytest-bdd
413
+ pytest --cov --cov-fail-under=80
414
+ """
415
+
416
+ PRE_COMMIT_CONFIG_YAML = """repos:
417
+ - repo: local
418
+ hooks:
419
+ - id: aidlc-validate
420
+ name: aidlc validate
421
+ entry: cdh aidlc validate
422
+ language: system
423
+ pass_filenames: false
424
+ always_run: true
425
+ - id: aidlc-contract-diff
426
+ name: aidlc contract diff
427
+ entry: python aidlc/tools/contract_diff.py --base origin/main --head HEAD
428
+ language: system
429
+ pass_filenames: false
430
+ always_run: true
431
+ """
432
+
433
+ CONFTEST_PY = '''"""Auto-generated by cdh scaffold."""
434
+ import json
435
+ from pathlib import Path
436
+ import pytest
437
+
438
+
439
+ def pytest_addoption(parser):
440
+ parser.addoption("--base-url", default="http://localhost:8080", help="Base URL for e2e tests")
441
+ parser.addoption("--api-url", default="", help="API URL")
442
+ parser.addoption("--stack-url", default="", help="Stack preview URL")
443
+
444
+
445
+ @pytest.fixture
446
+ def base_url(request):
447
+ return request.config.getoption("--base-url")
448
+
449
+
450
+ @pytest.fixture
451
+ def api_url(request):
452
+ return request.config.getoption("--api-url") or request.config.getoption("--base-url")
453
+ '''
454
+
455
+ PYPROJECT_TOML = """[tool.pytest.ini_options]
456
+ minversion = "8.0"
457
+ testpaths = ["tests"]
458
+ python_files = ["test_*.py"]
459
+ markers = [
460
+ "unit: unit tests",
461
+ "integration: integration tests",
462
+ "e2e: end-to-end tests",
463
+ "contract: contract tests",
464
+ "cross_stack: cross-stack tests",
465
+ "positive: positive scenarios",
466
+ "negative: negative/error scenarios",
467
+ "edge: edge case scenarios",
468
+ ]
469
+ """
470
+
471
+ DOCKER_COMPOSE_YAML = """version: "3.9"
472
+ services:
473
+ postgres:
474
+ image: postgres:16-alpine
475
+ environment:
476
+ POSTGRES_DB: aidlc
477
+ POSTGRES_USER: aidlc
478
+ POSTGRES_PASSWORD: aidlc
479
+ ports:
480
+ - "5432:5432"
481
+ tmpfs: /var/lib/postgresql/data
482
+
483
+ redis:
484
+ image: redis:7-alpine
485
+ ports:
486
+ - "6379:6379"
487
+
488
+ minio:
489
+ image: minio/minio:latest
490
+ command: server /data --console-address ":9001"
491
+ environment:
492
+ MINIO_ROOT_USER: aidlc
493
+ MINIO_ROOT_PASSWORD: aidlc123456
494
+ ports:
495
+ - "9000:9000"
496
+ - "9001:9001"
497
+ """
498
+
499
+ ENV_LOCAL = """BACKEND_URL=http://localhost:8080
500
+ DATABASE_URL=postgresql://aidlc:aidlc@localhost:5432/aidlc
501
+ REDIS_URL=redis://localhost:6379/0
502
+ S3_ENDPOINT=http://localhost:9000
503
+ S3_ACCESS_KEY=aidlc
504
+ S3_SECRET_KEY=aidlc123456
505
+ """
506
+
507
+ GITIGNORE_CONTENT = """# Python
508
+ __pycache__/
509
+ *.py[cod]
510
+ *.egg-info/
511
+ dist/
512
+ build/
513
+ .venv/
514
+ venv/
515
+ *.egg
516
+
517
+ # Node
518
+ node_modules/
519
+ .next/
520
+ dist/
521
+ .nuxt/
522
+ .cache/
523
+
524
+ # IDE
525
+ .vscode/
526
+ .idea/
527
+ *.swp
528
+ *.swo
529
+ *~
530
+
531
+ # OS
532
+ .DS_Store
533
+ Thumbs.db
534
+
535
+ # CDH
536
+ .cdh/
537
+ """
538
+
539
+ CHANGELOG_MD = "# Changelog\n\n## [0.1.0] - Initial scaffold\n\n- Project created via cdh scaffold\n"
540
+
541
+
542
+
543
+
544
+ AGENTS_HEADER = """# AGENTS.md — {project_name}
545
+
546
+ <!-- ═══════════════════════════════════════════════════════════
547
+ AI-DLC Project Context — version {ai_dlc_version}
548
+ Skill Location: {{SKILL_PATH}}
549
+ This file contains PROJECT-SPECIFIC rules only.
550
+ Core skill definitions are in `SKILL.md` (injected separately).
551
+ DO NOT duplicate skill content here.
552
+ ═══════════════════════════════════════════════════════════ -->
553
+
554
+ """
555
+
556
+ PROJECT_RULES_BLOCK = """
557
+ ## Quality Gates
558
+
559
+ | Gate | Threshold |
560
+ |------|-----------|
561
+ | Coverage | ≥{coverage_min}% |
562
+ | BDD pass rate | {bdd_pass_rate}% |
563
+ | Contract diff | required |
564
+ | No TODO in diff | true |
565
+ | No secrets in diff | true |
566
+
567
+ ## Project Rules
568
+
569
+ 1. Intent → Spec (EARS) → BDD → Design (DAG) → TDD → Deploy
570
+ 2. Contract-first for cross-component changes
571
+ 3. Cross-stack e2e mandatory for ≥2 components
572
+ 4. Breaking changes require human approval
573
+ 5. Never commit secrets; never force-push to main/master
574
+ """
575
+
576
+ CDH_COMMANDS_BLOCK = """
577
+ ## CDH Commands
578
+
579
+ ```bash
580
+ # AI-DLC lifecycle
581
+ cdh aidlc phase <understand|plan|verify|deliver> # Set current phase
582
+ cdh aidlc gate <name> --status <passed|failed> # Record gate result
583
+ cdh aidlc sync # Regenerate AGENTS.md
584
+
585
+ # Validation
586
+ cdh aidlc validate --ears # EARS format check
587
+ cdh aidlc validate --bdd # BDD coverage check
588
+ cdh aidlc validate --fr # FR namespace check
589
+ cdh aidlc validate --dag # Task DAG check
590
+
591
+ # Project management
592
+ cdh project list # List projects
593
+ cdh project load <name> # Load project
594
+ ```
595
+ """
596
+
597
+ STATE_FILE_BLOCK = """
598
+ ## State File
599
+
600
+ `.cdh/state.json` — AI-DLC project state
601
+
602
+ | Field | Description |
603
+ |-------|-------------|
604
+ | `current_phase` | Current phase (understand/plan/verify/deliver) |
605
+ | `completed_phases` | Array of completed phase names |
606
+ | `gate_results` | Gate validation results |
607
+ | `task_registry` | Task history with fingerprints |
608
+ """
609
+
610
+ MDC_FRONTMATTER = """---
611
+ description: AI-DLC Project Context
612
+ globs: ["*"]
613
+ ---
614
+
615
+ """
616
+
617
+ REQUIREMENTS_MD = """# {project_name}
618
+
619
+ ## Intent
620
+
621
+ {description}
622
+
623
+ ## Stack Topology
624
+
625
+ Monorepo multi-component stack with the following components:
626
+
627
+ | Component | FR Prefix | Default Language | Default UI Framework | Directory |
628
+ |-----------|-----------|-----------------|---------------------|-----------|
629
+ {component_table}
630
+
631
+ ## Quality Gates
632
+
633
+ | Gate | Threshold |
634
+ |------|-----------|
635
+ | Unit/integration coverage | >= 80% |
636
+ | BDD scenarios pass | 100% |
637
+ | Contract tests pass | 100% |
638
+ | Cross-stack e2e pass | 100% |
639
+ | Security vulns | 0 |
640
+
641
+ Default cloud provider: TCB (Tencent CloudBase).
642
+ """
643
+
644
+ CONFIG_MD = """# AI-DLC Configuration
645
+
646
+ This file defines path variables and settings used across AI-DLC phases.
647
+
648
+ ## Path Variables
649
+
650
+ | Variable | Default | Description |
651
+ |----------|---------|-------------|
652
+ | `{spec_dir}` | `aidlc/openspec/changes/` | Spec delta documents |
653
+ | `{features_dir}` | `apps/{component}/features/` | BDD feature files |
654
+ | `{contracts_api}` | `aidlc/contracts/api/` | OpenAPI contract definitions |
655
+ | `{contracts_events}` | `aidlc/contracts/events/` | AsyncAPI event definitions |
656
+ | `{shared_types}` | `aidlc/packages/shared/` | Generated shared types |
657
+ | `{cross_stack_features}` | `aidlc/features/cross-stack/` | Cross-stack BDD features |
658
+ | `{unit_tests}` | `apps/{component}/tests/unit/` | Unit tests |
659
+ | `{integration_tests}` | `apps/{component}/tests/integration/` | Integration tests |
660
+ | `{e2e_tests}` | `apps/{component}/tests/e2e/` | E2E tests |
661
+ | `{cross_stack_tests}` | `aidlc/tests/cross-stack/` | Cross-stack integration tests |
662
+
663
+ ## Phase Settings
664
+
665
+ ### Understand Phase
666
+ - `und_min_scenarios`: 3 # Minimum BDD scenarios per FR
667
+ - `und_require_ears`: true # Require EARS format
668
+
669
+ ### Plan Phase
670
+ - `plan_require_dag`: true # Require task dependency DAG
671
+ - `plan_require_test_plan`: true # Require test plan before implementation
672
+
673
+ ### Verify Phase
674
+ - `vrf_coverage_min`: 80 # Minimum coverage percentage
675
+ - `vrf_bdd_pass_rate`: 100 # Required BDD pass rate
676
+ - `vrf_contract_compat`: true # Require contract backward compatibility
677
+
678
+ ### Deliver Phase
679
+ - `dlv_preview_ttl`: 24h # Preview environment TTL
680
+ - `dlv_bvt_checks`: ["health", "home", "login", "db", "error_rate"] # BVT check list
681
+
682
+ ## Component Overrides
683
+
684
+ Components can override defaults:
685
+
686
+ ```yaml
687
+ components:
688
+ backend:
689
+ features_dir: apps/backend/src/features/
690
+ test_dir: apps/backend/__tests__/
691
+ ```
692
+ """
693
+
694
+
695
+ def _mkdir(path: Path) -> None:
696
+ path.mkdir(parents=True, exist_ok=True)
697
+
698
+
699
+ def _gitkeep(path: Path) -> None:
700
+ keep = path / ".gitkeep"
701
+ if not keep.exists():
702
+ keep.write_text("", encoding="utf-8")
703
+
704
+
705
+ def _write(path: Path, content: str) -> None:
706
+ path.parent.mkdir(parents=True, exist_ok=True)
707
+ path.write_text(content.lstrip("\n"), encoding="utf-8")
708
+
709
+
710
+ def _build_agents_component_table(active: list[ComponentSpec]) -> str:
711
+ rows = ["| Prefix | Component | Directory | FR Namespace |"]
712
+ rows.append("|--------|-----------|-----------|--------------|")
713
+ for c in active:
714
+ component_map = {
715
+ "native": "Mobile",
716
+ "desktop": "Desktop",
717
+ "web": "Browser",
718
+ "backend": "Service",
719
+ "wxa": "WeChat Mini",
720
+ "mya": "Alipay Mini",
721
+ "tta": "TikTok Mini",
722
+ }
723
+ component = component_map.get(c.id, c.id.title())
724
+ rows.append(f"| {c.fr_prefix} | {component} | `{c.owns}/` | {c.fr_prefix}-FR-NNN |")
725
+ rows.append("| INT | Contracts | `aidlc/contracts/`, `aidlc/packages/shared/` | INT-FR-NNN |")
726
+ return "\n".join(rows)
727
+
728
+
729
+ ENGINE_SKILL_PATHS = {
730
+ "opencode": Path.home() / ".opencode" / "skills",
731
+ "claude": Path.home() / ".claude" / "skills",
732
+ "onecode": Path.home() / ".onecode" / "skills",
733
+ }
734
+
735
+
736
+ def _find_skill_installation() -> Path | None:
737
+ """Find ai-dlc-skill installation (project-local or global).
738
+
739
+ Search order:
740
+ 1. ~/.cdh/skills/ai-dlc-skill (canonical skill cache)
741
+ 2. Engine-specific paths (symlinks created by cdh skills install)
742
+ 3. cdh project-local ai-dlc-skill/
743
+ """
744
+ candidates = [
745
+ Path.home() / ".cdh" / "skills" / "ai-dlc-skill",
746
+ ]
747
+ for engine, engine_dir in ENGINE_SKILL_PATHS.items():
748
+ candidates.append(engine_dir / "ai-dlc-skill")
749
+
750
+ script_path = Path(__file__).resolve()
751
+ cdh_root = script_path.parents[1]
752
+ candidates.append(cdh_root / "ai-dlc-skill")
753
+ candidates.append(Path.home() / ".local" / "share" / "cdh" / "ai-dlc-skill")
754
+
755
+ for p in candidates:
756
+ if (p / "SKILL.md").exists():
757
+ return p
758
+ return None
759
+
760
+
761
+ def create_engine_symlinks(skill_source: Path, workspace_root: Path) -> list[str]:
762
+ """Create symlinks from engine skill directories to the skill source.
763
+
764
+ Args:
765
+ skill_source: Path to the skill (e.g., ~/.cdh/skills/ai-dlc-skill/)
766
+ workspace_root: Path to the project workspace (for AGENTS.md symlinks)
767
+
768
+ Returns:
769
+ List of created symlink paths.
770
+ """
771
+ created = []
772
+ skipped = []
773
+
774
+ for engine, engine_dir in ENGINE_SKILL_PATHS.items():
775
+ if not engine_dir.exists():
776
+ skipped.append(engine)
777
+ logger.debug("Engine directory does not exist, skipping: %s", engine_dir)
778
+ continue
779
+
780
+ skill_link = engine_dir / skill_source.name
781
+ if not skill_link.exists() and not skill_link.is_symlink():
782
+ try:
783
+ skill_link.parent.mkdir(parents=True, exist_ok=True)
784
+ os.symlink(skill_source, skill_link)
785
+ created.append(str(skill_link))
786
+ except OSError as e:
787
+ logger.warning("Failed to create symlink for %s: %s", engine, e)
788
+
789
+ if skipped:
790
+ logger.info("Skipped symlinks for engines without directories: %s", ", ".join(skipped))
791
+
792
+ return created
793
+
794
+
795
+ def _read_skill_body(skill_path: Path) -> str:
796
+ """Read SKILL.md and strip YAML frontmatter, return body only."""
797
+ if not skill_path.exists():
798
+ return ""
799
+ raw = skill_path.read_text(encoding="utf-8")
800
+ body = re.sub(r'^---[\s\S]*?\n---\n?', '', raw)
801
+ return body.strip()
802
+
803
+
804
+ def _read_skill_file(skill_root: Path | None, relative_path: str) -> str:
805
+ """Read a file from the skill installation directory."""
806
+ if not skill_root:
807
+ return ""
808
+ file_path = skill_root / relative_path
809
+ if not file_path.exists():
810
+ return ""
811
+ try:
812
+ return file_path.read_text(encoding="utf-8")
813
+ except Exception:
814
+ return ""
815
+
816
+
817
+ _COMPLEXITY_SECTION_PATTERN = re.compile(
818
+ r'(##\s+Complexity\s+Evaluation\s+Checklist.*?)'
819
+ r'(##\s+Quick\s+Decision\s+Table)',
820
+ re.DOTALL
821
+ )
822
+
823
+
824
+ def _extract_complexity_section(content: str) -> str:
825
+ """Extract the complexity evaluation checklist section."""
826
+ match = _COMPLEXITY_SECTION_PATTERN.search(content)
827
+ if match:
828
+ return "\n## Complexity Evaluation Checklist\n\n" + match.group(1).strip() + "\n"
829
+ return ""
830
+
831
+
832
+ def _write_symlink(target: Path, link_path: Path) -> None:
833
+ """Create a relative symlink link_path → target."""
834
+ link_path.parent.mkdir(parents=True, exist_ok=True)
835
+ if link_path.is_symlink() or link_path.exists():
836
+ link_path.unlink()
837
+ rel = os.path.relpath(target, link_path.parent)
838
+ link_path.symlink_to(rel)
839
+
840
+
841
+ def _get_aidlc_version(skill_yaml_path: Path) -> str:
842
+ """Get AI-DLC version from skill.yaml."""
843
+ if skill_yaml_path.exists():
844
+ try:
845
+ data = yaml.safe_load(skill_yaml_path.read_text(encoding="utf-8"))
846
+ return str(data.get("version", "unknown"))
847
+ except Exception:
848
+ pass
849
+ return "unknown"
850
+
851
+
852
+ def _get_quality_gates(skill_yaml_path: Path) -> dict:
853
+ """Get quality gates from skill.yaml."""
854
+ defaults = {
855
+ "coverage_min": 80,
856
+ "bdd_pass_rate": 100,
857
+ "contract_diff": True,
858
+ "no_todo": True,
859
+ "no_secrets_in_diff": True,
860
+ }
861
+ if not skill_yaml_path.exists():
862
+ return defaults
863
+ try:
864
+ data = yaml.safe_load(skill_yaml_path.read_text(encoding="utf-8"))
865
+ gates = data.get("quality_gates", {}) if data else {}
866
+ return {
867
+ "coverage_min": gates.get("coverage_min", defaults["coverage_min"]),
868
+ "bdd_pass_rate": gates.get("bdd_pass_rate", defaults["bdd_pass_rate"]),
869
+ "contract_diff": gates.get("contract_diff", defaults["contract_diff"]),
870
+ "no_todo": gates.get("no_todo", defaults["no_todo"]),
871
+ "no_secrets_in_diff": gates.get("no_secrets_in_diff", defaults["no_secrets_in_diff"]),
872
+ }
873
+ except Exception:
874
+ return defaults
875
+
876
+
877
+ def _get_skill_path_for_agents(skill_instal: Path) -> str:
878
+ """Get the skill path for AGENTS.md header.
879
+
880
+ Returns the canonical path if skill is in ~/.cdh/skills/, otherwise
881
+ returns the actual resolved path. This helps LLM locate SKILL.md.
882
+ """
883
+ canonical = Path.home() / ".cdh" / "skills" / "ai-dlc-skill"
884
+ if skill_instal.resolve() == canonical.resolve():
885
+ return str(canonical)
886
+ return str(skill_instal)
887
+
888
+
889
+ def _write_agents_and_claude_md(
890
+ root: Path,
891
+ project_name: str,
892
+ description: str,
893
+ active: list[ComponentSpec],
894
+ ) -> None:
895
+ # Read AI-DLC skill installation
896
+ skill_instal = _find_skill_installation()
897
+ if skill_instal:
898
+ skill_yaml = skill_instal / "skill.yaml"
899
+ else:
900
+ skill_yaml = root / "ai-dlc-skill" / "skill.yaml"
901
+ skill_instal = root / "ai-dlc-skill"
902
+
903
+ aidlc_version = _get_aidlc_version(skill_yaml)
904
+ quality_gates = _get_quality_gates(skill_yaml)
905
+
906
+ skill_path = _get_skill_path_for_agents(skill_instal)
907
+
908
+ component_table = _build_agents_component_table(active)
909
+
910
+ adaptive_flow_content = _read_skill_file(skill_instal, "core/adaptive-flow.md")
911
+ complexity_section = ""
912
+ if adaptive_flow_content:
913
+ complexity_section = _extract_complexity_section(adaptive_flow_content)
914
+
915
+ agents_content = (
916
+ AGENTS_HEADER.format(project_name=project_name, ai_dlc_version=aidlc_version, SKILL_PATH=skill_path)
917
+ + PROJECT_RULES_BLOCK.format(
918
+ coverage_min=quality_gates["coverage_min"],
919
+ bdd_pass_rate=quality_gates["bdd_pass_rate"],
920
+ )
921
+ + CDH_COMMANDS_BLOCK
922
+ + STATE_FILE_BLOCK
923
+ + "\n## Components\n\n"
924
+ + component_table
925
+ + "\n"
926
+ + complexity_section
927
+ )
928
+ _write(root / "AGENTS.md", agents_content)
929
+
930
+ # ── Symlinks to AGENTS.md for engine-native discovery ──
931
+ symlinks = [
932
+ root / "CLAUDE.md",
933
+ root / ".clinerules",
934
+ root / ".github" / "copilot-instructions.md",
935
+ ]
936
+ for link_path in symlinks:
937
+ _write_symlink(root / "AGENTS.md", link_path)
938
+
939
+ # ── .cursor/rules/ai-dlc-core.mdc (same as AGENTS.md for Cursor) ──
940
+ cursor_dir = root / ".cursor" / "rules"
941
+ cursor_dir.mkdir(parents=True, exist_ok=True)
942
+ mdc_content = (
943
+ MDC_FRONTMATTER
944
+ + PROJECT_RULES_BLOCK.format(
945
+ coverage_min=quality_gates["coverage_min"],
946
+ bdd_pass_rate=quality_gates["bdd_pass_rate"],
947
+ )
948
+ + CDH_COMMANDS_BLOCK
949
+ + STATE_FILE_BLOCK
950
+ + "\n## Components\n\n"
951
+ + component_table
952
+ + "\n"
953
+ + complexity_section
954
+ )
955
+ (cursor_dir / "ai-dlc-core.mdc").write_text(mdc_content.lstrip("\n"), encoding="utf-8")
956
+
957
+
958
+ def _component_to_dict(c: ComponentSpec) -> dict:
959
+ out = {
960
+ "id": c.id,
961
+ "kind": c.kind,
962
+ "tech": c.tech,
963
+ "owns": c.owns,
964
+ "fr_prefix": c.fr_prefix,
965
+ }
966
+ return out
967
+
968
+
969
+ def _build_project_yaml(
970
+ active: list[ComponentSpec],
971
+ cross_cutting_ids: list[str],
972
+ name: str = "",
973
+ description: str = "",
974
+ ) -> dict:
975
+ cross_cutting: dict = {"fr_prefix": "INT"}
976
+ if "contracts" in cross_cutting_ids:
977
+ cross_cutting["contracts"] = "aidlc/contracts/"
978
+ if "shared" in cross_cutting_ids:
979
+ cross_cutting["shared_types"] = "aidlc/packages/shared/"
980
+ doc: dict = {
981
+ "name": name,
982
+ "description": description,
983
+ "stack": {
984
+ "topology": "monorepo",
985
+ "components": [_component_to_dict(c) for c in active],
986
+ "cross_cutting": cross_cutting,
987
+ },
988
+ "settings": {
989
+ "aidlc_mode": "L2",
990
+ },
991
+ }
992
+ return doc
993
+
994
+
995
+ def _build_component_table(active: list[ComponentSpec]) -> str:
996
+ if not active:
997
+ return "| (none) | - | - | - | - |"
998
+ return "\n".join(
999
+ f"| {c.id:8s} | {c.fr_prefix + '-FR-*':14s} | {'-':17s} | {'-':21s} | {c.owns:20s} |"
1000
+ for c in active
1001
+ )
1002
+
1003
+
1004
+ def _scaffold_component(c: ComponentSpec, root: Path) -> None:
1005
+ comp_dir = root / c.owns
1006
+ _mkdir(comp_dir / "src")
1007
+ if c.kind == "mini-program":
1008
+ _mkdir(comp_dir / "tests" / "e2e")
1009
+ _gitkeep(comp_dir / "tests" / "e2e")
1010
+ else:
1011
+ _mkdir(comp_dir / "tests" / "unit")
1012
+ _mkdir(comp_dir / "tests" / "integration")
1013
+ _mkdir(comp_dir / "tests" / "e2e")
1014
+ _gitkeep(comp_dir / "tests" / "unit")
1015
+ _gitkeep(comp_dir / "tests" / "integration")
1016
+ _gitkeep(comp_dir / "tests" / "e2e")
1017
+ _mkdir(comp_dir / "features")
1018
+ _gitkeep(comp_dir / "features")
1019
+ _gitkeep(comp_dir / "src")
1020
+ _gitkeep(comp_dir)
1021
+
1022
+
1023
+ def _scaffold_cross_cutting(cross_ids: list[str], root: Path) -> None:
1024
+ for cid in cross_ids:
1025
+ spec = CROSS_CUTTING_BY_ID.get(cid)
1026
+ if spec is None:
1027
+ continue
1028
+ for p in spec.paths:
1029
+ target = root / p
1030
+ if p.endswith((".yaml", ".py", ".md")):
1031
+ if p == "aidlc/contracts/CHANGELOG.md":
1032
+ _write(target, CHANGELOG_MD)
1033
+ elif p == "aidlc/providers/tcb/provider.yaml":
1034
+ _write(target, TCB_PROVIDER_YAML)
1035
+ elif p == "aidlc/providers/tcb/deployment.yaml":
1036
+ _write(target, TCB_DEPLOYMENT_YAML)
1037
+ elif p == "aidlc/providers/tcb/preview.yaml":
1038
+ _write(target, TCB_PREVIEW_YAML)
1039
+ elif p == "aidlc/tools/deploy_stack.py":
1040
+ _write(target, DEPLOY_STACK_PY)
1041
+ target.chmod(0o755)
1042
+ elif p == "aidlc/tools/contract_diff.py":
1043
+ _write(target, CONTRACT_DIFF_PY)
1044
+ target.chmod(0o755)
1045
+ elif p == "aidlc/tools/generate_shared.py":
1046
+ _write(target, GENERATE_SHARED_PY)
1047
+ target.chmod(0o755)
1048
+ elif p == "aidlc/tools/bvt.py":
1049
+ _write(target, BVT_PY)
1050
+ target.chmod(0o755)
1051
+ else:
1052
+ _write(target, TOOL_STUB if p.endswith(".py") else "")
1053
+ if p.endswith(".py"):
1054
+ target.chmod(0o755)
1055
+ else:
1056
+ _mkdir(target)
1057
+ _gitkeep(target)
1058
+
1059
+
1060
+ def _scaffold_ci_templates(root: Path, component_ids: list[str] | None = None) -> None:
1061
+ ci_dir = root / ".github" / "workflows"
1062
+ ci_dir.mkdir(parents=True, exist_ok=True)
1063
+ (ci_dir / "aidlc-ci.yaml").write_text(GITHUB_ACTIONS_CI_YAML, encoding="utf-8")
1064
+ (root / ".pre-commit-config.yaml").write_text(PRE_COMMIT_CONFIG_YAML, encoding="utf-8")
1065
+
1066
+
1067
+ def _scaffold_test_templates(root: Path, component_ids: list[str] | None = None) -> None:
1068
+ _write(root / "conftest.py", CONFTEST_PY)
1069
+ _write(root / "pyproject.toml", PYPROJECT_TOML)
1070
+
1071
+
1072
+ def _scaffold_local_env(root: Path) -> None:
1073
+ _write(root / "docker-compose.yaml", DOCKER_COMPOSE_YAML)
1074
+ _write(root / ".env.local", ENV_LOCAL)
1075
+ _write(root / ".env.example", ENV_LOCAL)
1076
+
1077
+
1078
+ def _scaffold_provider_templates(root: Path, provider: str | None) -> None:
1079
+ if provider is None or provider == "tcb":
1080
+ return
1081
+ provider_dir = root / "aidlc" / "providers" / provider
1082
+ provider_dir.mkdir(parents=True, exist_ok=True)
1083
+ if provider == "aliyun":
1084
+ _write(provider_dir / "provider.yaml", ALIYUN_PROVIDER_YAML)
1085
+ _write(provider_dir / "deployment.yaml", ALIYUN_DEPLOYMENT_YAML)
1086
+ _write(provider_dir / "preview.yaml", ALIYUN_PREVIEW_YAML)
1087
+
1088
+
1089
+ def _write_project_yaml(
1090
+ root: Path,
1091
+ project_name: str,
1092
+ active: list[ComponentSpec],
1093
+ cross_cutting_ids: list[str],
1094
+ description: str,
1095
+ ) -> None:
1096
+ _write(
1097
+ root / "aidlc" / "project.yaml",
1098
+ yaml.dump(
1099
+ _build_project_yaml(active, cross_cutting_ids, name=project_name, description=description),
1100
+ default_flow_style=False,
1101
+ ),
1102
+ )
1103
+ _write(
1104
+ root / "aidlc" / "requirements.md",
1105
+ REQUIREMENTS_MD.format(
1106
+ project_name=project_name,
1107
+ description=description or f"AI-DLC monorepo project: {project_name}",
1108
+ component_table=_build_component_table(active),
1109
+ ),
1110
+ )
1111
+ _write(root / "aidlc" / "CONFIG.md", CONFIG_MD)
1112
+ _write(root / ".gitignore", GITIGNORE_CONTENT)
1113
+ _write(root / "aidlc" / "CHANGELOG.md", CHANGELOG_MD)
1114
+
1115
+
1116
+ def init_dlc_project(
1117
+ workspace_root: Path,
1118
+ project_name: str,
1119
+ description: str = "",
1120
+ with_ci: bool = False,
1121
+ with_tests: bool = False,
1122
+ with_local: bool = False,
1123
+ provider: str | None = None,
1124
+ ) -> bool:
1125
+ """Scaffold project metadata only (no apps/*, no cross-cutting dirs)."""
1126
+
1127
+ root = workspace_root.resolve()
1128
+ _write_project_yaml(
1129
+ root=root,
1130
+ project_name=project_name,
1131
+ active=[],
1132
+ cross_cutting_ids=[],
1133
+ description=description,
1134
+ )
1135
+ _write_agents_and_claude_md(root, project_name, description, [])
1136
+
1137
+ skill_instal = _find_skill_installation()
1138
+ if skill_instal:
1139
+ create_engine_symlinks(skill_instal, root)
1140
+
1141
+ if with_ci:
1142
+ _scaffold_ci_templates(root)
1143
+ if with_tests:
1144
+ _scaffold_test_templates(root)
1145
+ if with_local:
1146
+ _scaffold_local_env(root)
1147
+ if provider:
1148
+ _scaffold_provider_templates(root, provider)
1149
+ return True
1150
+
1151
+
1152
+ def scaffold_dlc_project(
1153
+ workspace_root: Path,
1154
+ project_name: str,
1155
+ components: list[str] | None = None,
1156
+ description: str = "",
1157
+ with_ci: bool = False,
1158
+ with_tests: bool = False,
1159
+ with_local: bool = False,
1160
+ provider: str | None = None,
1161
+ ) -> bool:
1162
+ """Scaffold a full ai-dlc-skill monorepo project structure.
1163
+
1164
+ Application components are optional — when omitted only cross-cutting
1165
+ items (contracts, shared types, openspec, etc.) are created.
1166
+ Components can be added later with add_component().
1167
+
1168
+ Args:
1169
+ components: list of component ids (e.g. ["web", "backend"]).
1170
+ If None or empty, only cross-cutting items are scaffolded.
1171
+
1172
+ Returns True if scaffolding was performed.
1173
+
1174
+ Raises ValueError if any component id is unknown.
1175
+ """
1176
+ if components is None:
1177
+ components = []
1178
+
1179
+ unknown = [c for c in components if c not in COMPONENT_BY_ID]
1180
+ if unknown:
1181
+ raise ValueError(
1182
+ f"Unknown component id(s): {', '.join(unknown)}. "
1183
+ f"Valid ids: {', '.join(COMPONENT_BY_ID)}."
1184
+ )
1185
+
1186
+ root = workspace_root.resolve()
1187
+ active = [COMPONENT_BY_ID[cid] for cid in components]
1188
+ all_cross_ids = [
1189
+ c.id for c in CROSS_CUTTING if c.id not in ("provider", "tools")
1190
+ ]
1191
+
1192
+ _write_project_yaml(
1193
+ root=root,
1194
+ project_name=project_name,
1195
+ active=active,
1196
+ cross_cutting_ids=all_cross_ids,
1197
+ description=description,
1198
+ )
1199
+
1200
+ for c in active:
1201
+ _scaffold_component(c, root)
1202
+
1203
+ _scaffold_cross_cutting(all_cross_ids, root)
1204
+ _write_agents_and_claude_md(root, project_name, description, active)
1205
+
1206
+ skill_instal = _find_skill_installation()
1207
+ if skill_instal:
1208
+ create_engine_symlinks(skill_instal, root)
1209
+
1210
+ if with_ci:
1211
+ _scaffold_ci_templates(root, components)
1212
+ if with_tests:
1213
+ _scaffold_test_templates(root, components)
1214
+ if with_local:
1215
+ _scaffold_local_env(root)
1216
+ if provider:
1217
+ _scaffold_provider_templates(root, provider)
1218
+
1219
+ return True
1220
+
1221
+
1222
+ def _regenerate_agents_and_claude_md(root: Path) -> None:
1223
+ project_yaml = root / "aidlc" / "project.yaml"
1224
+ if not project_yaml.exists():
1225
+ return
1226
+ data = yaml.safe_load(project_yaml.read_text(encoding="utf-8")) or {}
1227
+ name = data.get("name", root.name)
1228
+ description = data.get("description", "")
1229
+ components = data.get("stack", {}).get("components", []) or []
1230
+ active = []
1231
+ for c in components:
1232
+ spec = COMPONENT_BY_ID.get(c.get("id", ""))
1233
+ if spec:
1234
+ active.append(spec)
1235
+ _write_agents_and_claude_md(root, name, description, active)
1236
+
1237
+
1238
+ def add_component(
1239
+ workspace_root: Path,
1240
+ component_id: str,
1241
+ ) -> bool:
1242
+ """Add a single application component to an existing project.
1243
+
1244
+ Creates apps/<owns>/{src,tests/unit,tests/e2e,features} with
1245
+ .gitkeep files and updates aidlc/project.yaml's stack.components list.
1246
+
1247
+ Returns True if the component was added, False if it was already
1248
+ present. Raises ValueError on unknown component id.
1249
+ """
1250
+ spec = COMPONENT_BY_ID.get(component_id)
1251
+ if spec is None:
1252
+ raise ValueError(
1253
+ f"Unknown component id: {component_id}. "
1254
+ f"Valid ids: {', '.join(COMPONENT_BY_ID)}."
1255
+ )
1256
+
1257
+ root = workspace_root.resolve()
1258
+ project_yaml = root / "aidlc" / "project.yaml"
1259
+ if not project_yaml.exists():
1260
+ raise FileNotFoundError(
1261
+ f"aidlc/project.yaml not found at {root}. Run 'cdh project init' first."
1262
+ )
1263
+
1264
+ data = yaml.safe_load(project_yaml.read_text(encoding="utf-8")) or {}
1265
+ components = data.get("stack", {}).get("components", []) or []
1266
+ if any(c.get("id") == component_id for c in components):
1267
+ return False
1268
+
1269
+ _scaffold_component(spec, root)
1270
+
1271
+ components.append(_component_to_dict(spec))
1272
+ data["stack"]["components"] = components
1273
+ project_yaml.write_text(
1274
+ yaml.dump(data, default_flow_style=False),
1275
+ encoding="utf-8",
1276
+ )
1277
+ _regenerate_agents_and_claude_md(root)
1278
+ return True
1279
+
1280
+
1281
+ def add_cross_cutting(
1282
+ workspace_root: Path,
1283
+ cross_id: str,
1284
+ ) -> bool:
1285
+ """Add a single cross-cutting item to an existing project.
1286
+
1287
+ Creates the relevant directories/files and updates aidlc/project.yaml
1288
+ so that stack.cross_cutting references the new path.
1289
+
1290
+ Returns True if the item was added, False if it was already present.
1291
+ Raises ValueError on unknown cross-cutting id.
1292
+ """
1293
+ spec = CROSS_CUTTING_BY_ID.get(cross_id)
1294
+ if spec is None:
1295
+ raise ValueError(
1296
+ f"Unknown cross-cutting id: {cross_id}. "
1297
+ f"Valid ids: {', '.join(CROSS_CUTTING_BY_ID)}."
1298
+ )
1299
+
1300
+ root = workspace_root.resolve()
1301
+ project_yaml = root / "aidlc" / "project.yaml"
1302
+ if not project_yaml.exists():
1303
+ raise FileNotFoundError(
1304
+ f"aidlc/project.yaml not found at {root}. Run 'cdh project init' first."
1305
+ )
1306
+
1307
+ cross_paths = [root / p for p in spec.paths]
1308
+ if all(p.exists() for p in cross_paths):
1309
+ return False
1310
+
1311
+ _scaffold_cross_cutting([cross_id], root)
1312
+
1313
+ data = yaml.safe_load(project_yaml.read_text(encoding="utf-8")) or {}
1314
+ cross_cutting = data.setdefault("stack", {}).setdefault("cross_cutting", {})
1315
+ if cross_id == "contracts":
1316
+ cross_cutting["contracts"] = "aidlc/contracts/"
1317
+ elif cross_id == "shared":
1318
+ cross_cutting["shared_types"] = "packages/shared/"
1319
+
1320
+ project_yaml.write_text(
1321
+ yaml.dump(data, default_flow_style=False),
1322
+ encoding="utf-8",
1323
+ )
1324
+ _regenerate_agents_and_claude_md(root)
1325
+ return True
1326
+
1327
+
1328
+ def check_dlc_project(workspace_root: Path) -> dict:
1329
+ """Check whether a directory is a valid AIDC project and return diagnostics.
1330
+
1331
+ Returns a dict with keys:
1332
+ valid — bool, whether the project is minimally valid
1333
+ name — str or None
1334
+ path — str (resolved root)
1335
+ components — list of component ids
1336
+ has_cdh — bool
1337
+ suggestions — list of human-readable improvement suggestions
1338
+ """
1339
+ root = workspace_root.resolve()
1340
+ result: dict = {
1341
+ "valid": True,
1342
+ "name": None,
1343
+ "path": str(root),
1344
+ "components": [],
1345
+ "has_cdh": False,
1346
+ "suggestions": [],
1347
+ }
1348
+
1349
+ project_yaml = root / "aidlc" / "project.yaml"
1350
+ if not project_yaml.exists():
1351
+ result["suggestions"].append(
1352
+ f"Missing aidlc/project.yaml — run 'cdh aidlc init {root}' first"
1353
+ )
1354
+ result["valid"] = False
1355
+ return result
1356
+
1357
+ try:
1358
+ data = yaml.safe_load(project_yaml.read_text(encoding="utf-8"))
1359
+ except Exception as e:
1360
+ result["suggestions"].append(f"Invalid YAML in aidlc/project.yaml: {e}")
1361
+ result["valid"] = False
1362
+ return result
1363
+
1364
+ if not isinstance(data, dict):
1365
+ result["suggestions"].append("aidlc/project.yaml is not a valid YAML mapping")
1366
+ result["valid"] = False
1367
+ return result
1368
+
1369
+ name = data.get("name", "")
1370
+ if not name:
1371
+ result["suggestions"].append("Missing 'name' field in aidlc/project.yaml")
1372
+ result["valid"] = False
1373
+ name = root.name
1374
+ result["name"] = name
1375
+
1376
+ components = data.get("stack", {}).get("components", [])
1377
+ if not components:
1378
+ result["suggestions"].append(
1379
+ "No components defined in stack.components — "
1380
+ "use 'cdh aidlc add-component' to add one"
1381
+ )
1382
+ else:
1383
+ ids = []
1384
+ for c in components:
1385
+ cid = c.get("id", "")
1386
+ if not cid:
1387
+ result["suggestions"].append(
1388
+ "A component entry is missing its 'id' field"
1389
+ )
1390
+ continue
1391
+ ids.append(cid)
1392
+ if cid not in COMPONENT_BY_ID:
1393
+ result["suggestions"].append(
1394
+ f"Unknown component id '{cid}' — expected one of: "
1395
+ f"{', '.join(COMPONENT_BY_ID)}"
1396
+ )
1397
+ else:
1398
+ owns = COMPONENT_BY_ID[cid].owns
1399
+ if not (root / owns).exists():
1400
+ result["suggestions"].append(
1401
+ f"Component '{cid}' directory '{owns}/' not found on disk"
1402
+ )
1403
+ result["components"] = ids
1404
+
1405
+ cross_cutting = data.get("stack", {}).get("cross_cutting", {})
1406
+ if isinstance(cross_cutting, dict):
1407
+ for key, path_val in cross_cutting.items():
1408
+ if isinstance(path_val, str) and not (root / path_val).exists():
1409
+ result["suggestions"].append(
1410
+ f"Cross-cutting '{key}' path '{path_val}' not found on disk"
1411
+ )
1412
+
1413
+ from cdh.project_loader import CdhProjectLoader
1414
+ result["has_cdh"] = CdhProjectLoader.find_cdh_dir(root) is not None
1415
+ if not result["has_cdh"]:
1416
+ result["suggestions"].append(
1417
+ ".cdh/ not found — run 'cdh aidlc init' to set up project state"
1418
+ )
1419
+
1420
+ return result
1421
+
1422
+
1423
+ __all__ = [
1424
+ "COMPONENTS",
1425
+ "COMPONENT_BY_ID",
1426
+ "CROSS_CUTTING",
1427
+ "CROSS_CUTTING_BY_ID",
1428
+ "ComponentSpec",
1429
+ "CrossCutSpec",
1430
+ "init_dlc_project",
1431
+ "scaffold_dlc_project",
1432
+ "add_component",
1433
+ "add_cross_cutting",
1434
+ "check_dlc_project",
1435
+ "_regenerate_agents_and_claude_md",
1436
+ ]