@tencent-rtc/trtc-agent-skills 0.1.3 → 0.1.4

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 (360) hide show
  1. package/.cursor/rules/main.mdc +12 -0
  2. package/AGENTS.md +14 -104
  3. package/CLAUDE.md +15 -127
  4. package/CODEBUDDY.md +32 -118
  5. package/README.md +7 -5
  6. package/README.zh.md +7 -5
  7. package/bin/cli.js +133 -41
  8. package/hooks/__pycache__/cursor-adapter.cpython-313.pyc +0 -0
  9. package/hooks/cursor-adapter.py +45 -18
  10. package/hooks/hooks-cursor.json +5 -18
  11. package/hooks/hooks.json +6 -31
  12. package/knowledge-base/conference/web/index.yaml +143 -0
  13. package/knowledge-base/platform-slice-template.md +1041 -133
  14. package/knowledge-base/products.yaml +76 -0
  15. package/knowledge-base/scenario-spec.md +1316 -115
  16. package/knowledge-base/scenarios/conference/base/general-conference.md +22 -2
  17. package/knowledge-base/scenarios/conference/base/webinar-conference.md +14 -0
  18. package/knowledge-base/scenarios/conference/medical/1v1-video-consultation.md +19 -0
  19. package/knowledge-base/scenarios/conference/medical/medical-multidoctor-consultation.md +13 -0
  20. package/knowledge-base/scenarios/live/entertainment-live-room.md +12 -0
  21. package/knowledge-base/slice-spec.md +2377 -299
  22. package/knowledge-base/slices/conference/web/integration-audit.md +1 -1
  23. package/knowledge-base/slices/conference/web/login-auth.md +14 -1
  24. package/knowledge-base/tooling/aliases.yaml +92 -0
  25. package/knowledge-base/tooling/intent-signals.yaml +181 -0
  26. package/knowledge-base/tooling/symptom-keywords.yaml +21 -0
  27. package/package.json +1 -1
  28. package/skills/trtc/SKILL.md +202 -245
  29. package/skills/trtc/hooks/__pycache__/report_prompt.cpython-313.pyc +0 -0
  30. package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_read.py +12 -8
  31. package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_write.py +16 -12
  32. package/skills/{trtc-topic/guardrails → trtc/hooks}/stop_require_apply_evidence.py +22 -14
  33. package/skills/trtc/hooks/topic_phase_gate.py +161 -0
  34. package/skills/{trtc-topic → trtc}/runtime/README.md +2 -2
  35. package/skills/{trtc-onboarding/reference/reporting-protocol.md → trtc/runtime/REPORTING.md} +5 -5
  36. package/skills/{trtc-topic → trtc}/runtime/RUNTIME.md +5 -5
  37. package/skills/trtc/runtime/lib/__init__.py +0 -0
  38. package/skills/{trtc-topic → trtc}/runtime/package-lock.json +2 -2
  39. package/skills/{trtc-topic → trtc}/runtime/package.json +2 -2
  40. package/skills/{trtc-topic → trtc}/runtime/telemetry-bridge.mjs +1 -1
  41. package/skills/{trtc-topic/scripts → trtc/tools}/STATE-MACHINE-GUIDE.md +23 -23
  42. package/skills/trtc/tools/__init__.py +2 -0
  43. package/skills/trtc/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  44. package/skills/trtc/tools/__pycache__/query_classifier.cpython-313.pyc +0 -0
  45. package/skills/trtc/tools/__pycache__/reporting.cpython-313.pyc +0 -0
  46. package/skills/trtc/tools/__pycache__/search.cpython-313.pyc +0 -0
  47. package/skills/trtc/tools/__pycache__/session.cpython-313.pyc +0 -0
  48. package/skills/trtc/tools/apply.py +540 -0
  49. package/skills/trtc/tools/docs.py +712 -0
  50. package/skills/trtc/tools/docsbot.py +182 -0
  51. package/skills/trtc/tools/entry/render_ai_instructions.py +92 -0
  52. package/skills/trtc/tools/flow.py +1089 -0
  53. package/skills/{trtc-topic/scripts → trtc/tools}/init_slice_queue.py +5 -4
  54. package/skills/{trtc-topic/scripts → trtc/tools}/next_slice.py +5 -4
  55. package/skills/trtc/tools/query_classifier.py +301 -0
  56. package/skills/trtc/tools/reporting.py +447 -0
  57. package/skills/trtc/tools/search.py +817 -0
  58. package/skills/trtc/tools/session.py +1261 -0
  59. package/skills/trtc/tools/state_machine.py +690 -0
  60. package/skills/trtc-ai-service/README.md +195 -0
  61. package/skills/trtc-ai-service/README.zh-CN.md +193 -0
  62. package/skills/trtc-ai-service/SKILL.md +945 -0
  63. package/skills/trtc-ai-service/auto_adapters/README.md +40 -0
  64. package/skills/trtc-ai-service/auto_adapters/frontend-spa/README.md +27 -0
  65. package/skills/trtc-ai-service/auto_adapters/frontend-spa/angular/voice-agent.component.ts.tpl +131 -0
  66. package/skills/trtc-ai-service/auto_adapters/frontend-spa/manifest.yaml +57 -0
  67. package/skills/trtc-ai-service/auto_adapters/frontend-spa/react/VoiceAgent.tsx.tpl +142 -0
  68. package/skills/trtc-ai-service/auto_adapters/frontend-spa/vue/VoiceAgent.vue.tpl +121 -0
  69. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-backend.md +45 -0
  70. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-frontend.md +51 -0
  71. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-rest-api.md +93 -0
  72. package/skills/trtc-ai-service/auto_adapters/java-backend/README.md +25 -0
  73. package/skills/trtc-ai-service/auto_adapters/java-backend/manifest.yaml +30 -0
  74. package/skills/trtc-ai-service/auto_adapters/java-backend/quarkus/VoiceAgentFilter.java.tpl +64 -0
  75. package/skills/trtc-ai-service/auto_adapters/java-backend/springboot/VoiceAgentFilter.java.tpl +91 -0
  76. package/skills/trtc-ai-service/auto_adapters/manifest.yaml +43 -0
  77. package/skills/trtc-ai-service/auto_adapters/node-backend/README.md +25 -0
  78. package/skills/trtc-ai-service/auto_adapters/node-backend/express.js.tpl +40 -0
  79. package/skills/trtc-ai-service/auto_adapters/node-backend/fastify.js.tpl +27 -0
  80. package/skills/trtc-ai-service/auto_adapters/node-backend/koa.js.tpl +31 -0
  81. package/skills/trtc-ai-service/auto_adapters/node-backend/manifest.yaml +47 -0
  82. package/skills/trtc-ai-service/auto_adapters/python-backend/README.md +22 -0
  83. package/skills/trtc-ai-service/auto_adapters/python-backend/django.py.tpl +32 -0
  84. package/skills/trtc-ai-service/auto_adapters/python-backend/fastapi.py.tpl +35 -0
  85. package/skills/trtc-ai-service/auto_adapters/python-backend/flask.py.tpl +31 -0
  86. package/skills/trtc-ai-service/auto_adapters/python-backend/manifest.yaml +45 -0
  87. package/skills/trtc-ai-service/capabilities/__init__.py +43 -0
  88. package/skills/trtc-ai-service/capabilities/conversation-core/.env.example +29 -0
  89. package/skills/trtc-ai-service/capabilities/conversation-core/INTEGRATION.md +134 -0
  90. package/skills/trtc-ai-service/capabilities/conversation-core/INTERFACE_ADAPT.md +111 -0
  91. package/skills/trtc-ai-service/capabilities/conversation-core/QUICK_START.md +62 -0
  92. package/skills/trtc-ai-service/capabilities/conversation-core/manifest.yaml +250 -0
  93. package/skills/trtc-ai-service/capabilities/conversation-core/requirements.txt +6 -0
  94. package/skills/trtc-ai-service/capabilities/conversation-core/src/__init__.py +10 -0
  95. package/skills/trtc-ai-service/capabilities/conversation-core/src/_capability_loader.py +218 -0
  96. package/skills/trtc-ai-service/capabilities/conversation-core/src/agent.py +231 -0
  97. package/skills/trtc-ai-service/capabilities/conversation-core/src/credentials.py +132 -0
  98. package/skills/trtc-ai-service/capabilities/conversation-core/src/health.py +355 -0
  99. package/skills/trtc-ai-service/capabilities/conversation-core/src/log_filter.py +76 -0
  100. package/skills/trtc-ai-service/capabilities/conversation-core/src/modality.py +109 -0
  101. package/skills/trtc-ai-service/capabilities/conversation-core/src/server.py +312 -0
  102. package/skills/trtc-ai-service/capabilities/conversation-core/src/trtc_client.py +315 -0
  103. package/skills/trtc-ai-service/capabilities/conversation-core/src/usersig.py +90 -0
  104. package/skills/trtc-ai-service/capabilities/conversation-core/tests/test_skeleton.py +216 -0
  105. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/README.md +48 -0
  106. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/app.js +415 -0
  107. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/index.html +68 -0
  108. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/styles.css +136 -0
  109. package/skills/trtc-ai-service/capabilities/digital-human/README.md +31 -0
  110. package/skills/trtc-ai-service/capabilities/digital-human/manifest.yaml +64 -0
  111. package/skills/trtc-ai-service/capabilities/digital-human/src/__init__.py +2 -0
  112. package/skills/trtc-ai-service/capabilities/digital-human/src/router.py +43 -0
  113. package/skills/trtc-ai-service/capabilities/human-handoff/INTERFACE_ADAPT.md +353 -0
  114. package/skills/trtc-ai-service/capabilities/human-handoff/README.md +44 -0
  115. package/skills/trtc-ai-service/capabilities/human-handoff/manifest.yaml +227 -0
  116. package/skills/trtc-ai-service/capabilities/human-handoff/src/__init__.py +2 -0
  117. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/__init__.py +9 -0
  118. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/default_rest.py +242 -0
  119. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/factory.py +89 -0
  120. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/local_queue.py +258 -0
  121. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/mock.py +132 -0
  122. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/__init__.py +25 -0
  123. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/intent_detector.py +75 -0
  124. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/models.py +163 -0
  125. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/service.py +192 -0
  126. package/skills/trtc-ai-service/capabilities/human-handoff/src/feedback_store.py +54 -0
  127. package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/__init__.py +4 -0
  128. package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/handoff_client.py +86 -0
  129. package/skills/trtc-ai-service/capabilities/human-handoff/src/queue.py +62 -0
  130. package/skills/trtc-ai-service/capabilities/human-handoff/src/router.py +201 -0
  131. package/skills/trtc-ai-service/capabilities/human-handoff/src/summary_link.py +77 -0
  132. package/skills/trtc-ai-service/capabilities/human-handoff/src/trigger.py +25 -0
  133. package/skills/trtc-ai-service/capabilities/knowledge-base/INTERFACE_ADAPT.md +297 -0
  134. package/skills/trtc-ai-service/capabilities/knowledge-base/README.md +51 -0
  135. package/skills/trtc-ai-service/capabilities/knowledge-base/data/faq.json +20 -0
  136. package/skills/trtc-ai-service/capabilities/knowledge-base/manifest.yaml +211 -0
  137. package/skills/trtc-ai-service/capabilities/knowledge-base/src/__init__.py +8 -0
  138. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/__init__.py +9 -0
  139. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/default_rest.py +209 -0
  140. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/factory.py +86 -0
  141. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/local_json.py +172 -0
  142. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/mock.py +91 -0
  143. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/__init__.py +12 -0
  144. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/models.py +77 -0
  145. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/scoring.py +73 -0
  146. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/service.py +78 -0
  147. package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/__init__.py +4 -0
  148. package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/kb_client.py +61 -0
  149. package/skills/trtc-ai-service/capabilities/knowledge-base/src/retriever.py +56 -0
  150. package/skills/trtc-ai-service/capabilities/knowledge-base/src/router.py +85 -0
  151. package/skills/trtc-ai-service/capabilities/session-summary/INTERFACE_ADAPT.md +99 -0
  152. package/skills/trtc-ai-service/capabilities/session-summary/README.md +47 -0
  153. package/skills/trtc-ai-service/capabilities/session-summary/data/test_session.json +18 -0
  154. package/skills/trtc-ai-service/capabilities/session-summary/manifest.yaml +165 -0
  155. package/skills/trtc-ai-service/capabilities/session-summary/src/__init__.py +2 -0
  156. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/__init__.py +5 -0
  157. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/base.py +31 -0
  158. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/default_rest.py +67 -0
  159. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/factory.py +51 -0
  160. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/local_json.py +42 -0
  161. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/mock.py +22 -0
  162. package/skills/trtc-ai-service/capabilities/session-summary/src/recorder.py +210 -0
  163. package/skills/trtc-ai-service/capabilities/session-summary/src/router.py +93 -0
  164. package/skills/trtc-ai-service/capabilities/session-summary/src/summarizer.py +163 -0
  165. package/skills/trtc-ai-service/capabilities/tool-calling/INTERFACE_ADAPT.md +158 -0
  166. package/skills/trtc-ai-service/capabilities/tool-calling/README.md +50 -0
  167. package/skills/trtc-ai-service/capabilities/tool-calling/data/tools.yaml +58 -0
  168. package/skills/trtc-ai-service/capabilities/tool-calling/examples/__init__.py +1 -0
  169. package/skills/trtc-ai-service/capabilities/tool-calling/examples/local_tools.py +101 -0
  170. package/skills/trtc-ai-service/capabilities/tool-calling/manifest.yaml +146 -0
  171. package/skills/trtc-ai-service/capabilities/tool-calling/src/__init__.py +8 -0
  172. package/skills/trtc-ai-service/capabilities/tool-calling/src/dispatcher.py +54 -0
  173. package/skills/trtc-ai-service/capabilities/tool-calling/src/registry.py +219 -0
  174. package/skills/trtc-ai-service/capabilities/tool-calling/src/router.py +50 -0
  175. package/skills/trtc-ai-service/references/business-contract-spec.md +263 -0
  176. package/skills/trtc-ai-service/scenarios/custom-builder/README.md +86 -0
  177. package/skills/trtc-ai-service/scenarios/custom-builder/output-templates/recipe.yaml.j2 +194 -0
  178. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q1-business-scenario.md +43 -0
  179. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q2-io-modality.md +57 -0
  180. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q3-ui-form.md +55 -0
  181. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q4-capabilities.md +78 -0
  182. package/skills/trtc-ai-service/scenarios/customer-service/README.md +114 -0
  183. package/skills/trtc-ai-service/scenarios/customer-service/recipe.yaml +154 -0
  184. package/skills/trtc-ai-service/scenarios/customer-service/sample-data/README.md +32 -0
  185. package/skills/trtc-ai-service/scenarios/customer-service/sample-data/faq-sample.json +37 -0
  186. package/skills/trtc-ai-service/scenarios/customer-service/system-prompt.template.md +94 -0
  187. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/app.js +347 -0
  188. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/index.html +125 -0
  189. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/styles.css +487 -0
  190. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/tokens.css +71 -0
  191. package/skills/trtc-ai-service/scenarios/customer-service/ui/design-system/DESIGN_GUIDELINES.md +370 -0
  192. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/README.md +68 -0
  193. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/app.js +1307 -0
  194. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/data.js +40 -0
  195. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/index.html +233 -0
  196. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/mock-shop.json +21 -0
  197. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/styles.css +603 -0
  198. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/tokens.css +71 -0
  199. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/agent-link.js +323 -0
  200. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/app.js +458 -0
  201. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/index.html +109 -0
  202. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/styles.css +489 -0
  203. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/tokens.css +59 -0
  204. package/skills/trtc-ai-service/scripts/add-capability.py +364 -0
  205. package/skills/trtc-ai-service/scripts/contract-adapt.py +334 -0
  206. package/skills/trtc-ai-service/scripts/detect-stack.py +40 -0
  207. package/skills/trtc-ai-service/scripts/lib/__init__.py +20 -0
  208. package/skills/trtc-ai-service/scripts/lib/adapter_codegen.py +509 -0
  209. package/skills/trtc-ai-service/scripts/lib/arbitrator.py +152 -0
  210. package/skills/trtc-ai-service/scripts/lib/contract_resolver.py +519 -0
  211. package/skills/trtc-ai-service/scripts/lib/credential_validators.py +253 -0
  212. package/skills/trtc-ai-service/scripts/lib/curl_parser.py +303 -0
  213. package/skills/trtc-ai-service/scripts/lib/degrader.py +140 -0
  214. package/skills/trtc-ai-service/scripts/lib/injector.py +347 -0
  215. package/skills/trtc-ai-service/scripts/lib/manifest_resolver.py +288 -0
  216. package/skills/trtc-ai-service/scripts/lib/openapi_parser.py +289 -0
  217. package/skills/trtc-ai-service/scripts/lib/stack_detector.py +159 -0
  218. package/skills/trtc-ai-service/scripts/lib/tokens_compile.py +204 -0
  219. package/skills/trtc-ai-service/scripts/post-install-patch.py +225 -0
  220. package/skills/trtc-ai-service/scripts/setup-credentials.py +393 -0
  221. package/skills/trtc-ai-service/scripts/verify-credentials.py +108 -0
  222. package/skills/trtc-ai-service/start.sh +111 -0
  223. package/skills/trtc-ai-service/tests/__init__.py +1 -0
  224. package/skills/trtc-ai-service/tests/test_arbitrator.py +64 -0
  225. package/skills/trtc-ai-service/tests/test_capability_overlay.py +85 -0
  226. package/skills/trtc-ai-service/tests/test_contract_resolver.py +190 -0
  227. package/skills/trtc-ai-service/tests/test_handoff_ports.py +195 -0
  228. package/skills/trtc-ai-service/tests/test_kb_ports.py +195 -0
  229. package/skills/trtc-ai-service/tests/test_manifest_resolver.py +95 -0
  230. package/skills/trtc-ai-service/tests/test_recipe_assembly.py +175 -0
  231. package/skills/trtc-ai-service/tests/test_stack_and_degrader.py +101 -0
  232. package/skills/trtc-ai-service/tests/test_verify_credentials.py +285 -0
  233. package/skills/trtc-ai-service/triggers.yaml +29 -0
  234. package/skills/trtc-conference/SKILL.md +324 -0
  235. package/skills/trtc-conference/flows/onboarding.md +205 -0
  236. package/skills/trtc-conference/flows/topic.md +474 -0
  237. package/skills/trtc-conference/flows/troubleshoot.md +85 -0
  238. package/skills/trtc-conference/hooks/pretooluse_require_business_decisions.py +213 -0
  239. package/skills/trtc-conference/playbooks/medical-quickstart.md +84 -0
  240. package/skills/trtc-conference/playbooks/official-roomkit.md +97 -0
  241. package/skills/trtc-conference/references/local-usersig/basic-info-config.ts +39 -0
  242. package/skills/trtc-conference/references/usersig-handling.md +134 -0
  243. package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.d.ts +4 -0
  244. package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.js +2 -0
  245. package/skills/trtc-conference/tests/__pycache__/test_conference_onboarding_contract.cpython-313-pytest-9.0.2.pyc +0 -0
  246. package/skills/trtc-conference/tests/__pycache__/test_conference_topic_flow_contract.cpython-313-pytest-9.0.2.pyc +0 -0
  247. package/skills/trtc-conference/tests/test_conference_index_contract.py +43 -0
  248. package/skills/trtc-conference/tests/test_conference_onboarding_contract.py +103 -0
  249. package/skills/trtc-conference/tests/test_conference_template_contract.py +25 -0
  250. package/skills/trtc-conference/tests/test_conference_topic_flow_contract.py +132 -0
  251. package/skills/trtc-conference/tools/apply_checks.py +328 -0
  252. package/skills/trtc-conference/verify_lib/__init__.py +0 -0
  253. package/skills/{trtc-apply/guardrails/apply_lib → trtc-conference/verify_lib}/rule_parser.py +1 -1
  254. package/skills/trtc-docs/SKILL.md +91 -119
  255. package/.cursor/rules/ui-mode.mdc +0 -99
  256. package/ai-instructions/base.md +0 -13
  257. package/ai-instructions/ui-mode.md +0 -93
  258. package/knowledge-base/index.yaml +0 -462
  259. package/skills/trtc/room-builder/SKILL.md +0 -133
  260. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/README.md +0 -108
  261. package/skills/trtc/room-builder/tools/render_ai_instructions.py +0 -226
  262. package/skills/trtc-apply/SKILL.md +0 -97
  263. package/skills/trtc-onboarding/SKILL.md +0 -841
  264. package/skills/trtc-onboarding/reference/path-a1-demo.md +0 -103
  265. package/skills/trtc-onboarding/reference/path-a2-integrate.md +0 -737
  266. package/skills/trtc-onboarding/reference/path-b-troubleshoot.md +0 -186
  267. package/skills/trtc-onboarding/reference/path-c-expand.md +0 -43
  268. package/skills/trtc-onboarding/reference/supported-matrix.md +0 -100
  269. package/skills/trtc-search/SKILL.md +0 -228
  270. package/skills/trtc-topic/SKILL.md +0 -622
  271. package/skills/trtc-topic/scripts/apply.py +0 -581
  272. package/skills/trtc-topic/scripts/lib/state_machine.py +0 -328
  273. package/skills/trtc-topic/tests/README.md +0 -70
  274. package/skills/trtc-topic/tests/conftest.py +0 -72
  275. package/skills/trtc-topic/tests/test_apply_cli.py +0 -480
  276. package/skills/trtc-topic/tests/test_end_to_end.py +0 -305
  277. package/skills/trtc-topic/tests/test_finalize_session.py +0 -51
  278. package/skills/trtc-topic/tests/test_gates.py +0 -316
  279. package/skills/trtc-topic/tests/test_session_resolver.py +0 -260
  280. package/skills/trtc-topic/tests/test_state_machine.py +0 -414
  281. package/skills/trtc-topic/tests/test_stop_require_apply.py +0 -99
  282. package/skills/trtc-topic/tests/test_topic_skill_invariants.py +0 -130
  283. /package/skills/{trtc-topic → trtc}/runtime/lib/platforms.py +0 -0
  284. /package/skills/{trtc-topic → trtc}/runtime/telemetry_collector.py +0 -0
  285. /package/skills/{trtc-onboarding/reference → trtc/runtime}/usersig-handling.md +0 -0
  286. /package/skills/{trtc-topic/scripts → trtc/tools}/finalize_session.py +0 -0
  287. /package/skills/{trtc-apply/guardrails/apply_lib → trtc-ai-service/capabilities/conversation-core/tests}/__init__.py +0 -0
  288. /package/skills/{trtc-topic → trtc-conference}/references/execution-units.yaml +0 -0
  289. /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.d.ts +0 -0
  290. /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.js +0 -0
  291. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/backend-contract.zh-CN.md +0 -0
  292. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/integration.zh-CN.md +0 -0
  293. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/theme.zh-CN.md +0 -0
  294. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/index.html +0 -0
  295. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/package.json +0 -0
  296. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/postcss.config.js +0 -0
  297. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/App.vue +0 -0
  298. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/ConsultationManagePanel.vue +0 -0
  299. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LanguageSwitch.vue +0 -0
  300. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LoadingSpinner.vue +0 -0
  301. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalAlert.vue +0 -0
  302. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalBusinessPanel.vue +0 -0
  303. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalButton.vue +0 -0
  304. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalConfirmDialog.vue +0 -0
  305. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalDataPanel.vue +0 -0
  306. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalRecordPanel.vue +0 -0
  307. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/PrescriptionPanel.vue +0 -0
  308. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/basic-info-config.ts +0 -0
  309. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/runtime-config.ts +0 -0
  310. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/env.d.ts +0 -0
  311. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationChatPanel.vue +0 -0
  312. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationMembersPanel.vue +0 -0
  313. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationTranscriptionPanel.vue +0 -0
  314. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationVideoStage.vue +0 -0
  315. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/InviteDoctorDialog.vue +0 -0
  316. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/KickMemberConfirmDialog.vue +0 -0
  317. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/types.ts +0 -0
  318. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationChat.ts +0 -0
  319. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationDevices.ts +0 -0
  320. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationParticipants.ts +0 -0
  321. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationPermissions.ts +0 -0
  322. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/utils.ts +0 -0
  323. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/en-US/index.ts +0 -0
  324. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/index.ts +0 -0
  325. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/medicalTranslate.ts +0 -0
  326. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/state.ts +0 -0
  327. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/zh-CN/index.ts +0 -0
  328. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/main.ts +0 -0
  329. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/appointments.ts +0 -0
  330. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/users.ts +0 -0
  331. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/router/index.ts +0 -0
  332. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/index.ts +0 -0
  333. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/appointmentService.ts +0 -0
  334. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/authService.ts +0 -0
  335. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/launchContext.ts +0 -0
  336. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/userService.ts +0 -0
  337. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/appointmentService.ts +0 -0
  338. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/authService.ts +0 -0
  339. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/userService.ts +0 -0
  340. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/types.ts +0 -0
  341. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/shared/icons.ts +0 -0
  342. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/index.css +0 -0
  343. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/tailwind.css +0 -0
  344. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/theme.css +0 -0
  345. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/auth.ts +0 -0
  346. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/format.ts +0 -0
  347. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/navigation.ts +0 -0
  348. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/session.ts +0 -0
  349. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorConsultationView.vue +0 -0
  350. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorDashboardView.vue +0 -0
  351. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/LoginView.vue +0 -0
  352. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationFinishedView.vue +0 -0
  353. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationView.vue +0 -0
  354. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientSelectDoctorView.vue +0 -0
  355. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientWaitingView.vue +0 -0
  356. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.json +0 -0
  357. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.node.json +0 -0
  358. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/vite.config.ts +0 -0
  359. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation//346/216/245/345/205/245/350/257/264/346/230/216.md" +0 -0
  360. /package/skills/{trtc-topic/runtime/lib → trtc-conference/tools}/__init__.py +0 -0
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Capability overlay CLI.
4
+
5
+ Usage
6
+ -----
7
+ # List discovered capability packages and their topological order
8
+ python scripts/add-capability.py --list
9
+
10
+ # Add capability packages to the current project (injects extensions into conversation-core by default)
11
+ python scripts/add-capability.py knowledge-base
12
+ python scripts/add-capability.py knowledge-base tool-calling --dry-run
13
+
14
+ # Render frontend / backend adapters in an external user project
15
+ python scripts/add-capability.py knowledge-base \
16
+ --target-project /path/to/user/repo \
17
+ --tech-stack react
18
+
19
+ # Output capability dependency graph (DOT format)
20
+ python scripts/add-capability.py --graph
21
+
22
+ Behavior
23
+ --------
24
+ 1. Scan all manifests under capabilities/, validate topological order, circular dependencies, version compatibility
25
+ 2. Execute manifest.extensions injection into skeleton for capability packages to be installed (dry-run by default)
26
+ 3. If --target-project is provided, invoke auto_adapters three-level degradation rendering based on tech_stack detection
27
+ 4. Output diagnostic JSON for easy Agent parsing
28
+ """
29
+ from __future__ import annotations
30
+
31
+ import argparse
32
+ import json
33
+ import os
34
+ import re
35
+ import shutil
36
+ import sys
37
+ from dataclasses import dataclass
38
+ from pathlib import Path
39
+ from typing import Any, Dict, List, Optional
40
+
41
+ _HERE = Path(__file__).resolve().parent
42
+ _ROOT = _HERE.parent
43
+ sys.path.insert(0, str(_ROOT))
44
+
45
+ from scripts.lib import manifest_resolver as mr
46
+ from scripts.lib import stack_detector as sd
47
+ from scripts.lib import degrader as dg
48
+ from scripts.lib import injector as ij
49
+
50
+
51
+ CAPS_ROOT = _ROOT / "capabilities"
52
+ ADAPTERS_ROOT = _ROOT / "auto_adapters"
53
+ SKELETON_NAME = "conversation-core"
54
+
55
+
56
+ # ---------------------------------------------------------------------------
57
+ # Template rendering
58
+ # ---------------------------------------------------------------------------
59
+ _VAR_RE = re.compile(r"\$\{([A-Z_][A-Z0-9_]*)\}")
60
+
61
+
62
+ def render_template(text: str, variables: Dict[str, str]) -> str:
63
+ def _sub(m: re.Match) -> str:
64
+ return variables.get(m.group(1), m.group(0))
65
+
66
+ return _VAR_RE.sub(_sub, text)
67
+
68
+
69
+ def load_yaml(path: Path) -> Dict[str, Any]:
70
+ import yaml
71
+
72
+ return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
73
+
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Install / Inject
77
+ # ---------------------------------------------------------------------------
78
+ @dataclass
79
+ class InstallReport:
80
+ capability: str
81
+ skeleton_injection: List[Dict[str, Any]]
82
+ adapter: Optional[Dict[str, Any]] = None
83
+ degrade: Optional[Dict[str, Any]] = None
84
+ errors: List[str] = None # type: ignore[assignment]
85
+
86
+ def to_dict(self) -> Dict[str, Any]:
87
+ return {
88
+ "capability": self.capability,
89
+ "skeleton_injection": self.skeleton_injection,
90
+ "adapter": self.adapter,
91
+ "degrade": self.degrade,
92
+ "errors": self.errors or [],
93
+ }
94
+
95
+
96
+ def inject_into_skeleton(
97
+ skeleton: mr.Manifest,
98
+ cap: mr.Manifest,
99
+ *,
100
+ dry_run: bool,
101
+ ) -> List[Dict[str, Any]]:
102
+ """Inject cap.extensions into corresponding skeleton files."""
103
+ skeleton_root = skeleton.path.parent if skeleton.path else CAPS_ROOT / SKELETON_NAME
104
+ cap_root = cap.path.parent if cap.path else CAPS_ROOT / cap.name
105
+ plans = ij.plan(
106
+ skeleton_root,
107
+ skeleton.injection_points,
108
+ [(cap_root, cap.extensions)],
109
+ )
110
+ results = ij.apply_plans(plans, dry_run=dry_run)
111
+ out = []
112
+ for r in results:
113
+ out.append(
114
+ {
115
+ "capability": cap.name,
116
+ "inject_at": r.plan.extension.inject_at,
117
+ "target": str(r.plan.target_abs_path.relative_to(_ROOT))
118
+ if r.plan.target_abs_path.is_relative_to(_ROOT)
119
+ else str(r.plan.target_abs_path),
120
+ "op": r.plan.op,
121
+ "anchor": r.plan.anchor,
122
+ "applied": r.applied,
123
+ "dry_run": r.dry_run,
124
+ "error": r.error,
125
+ "diff_preview": r.diff_preview[:200] if r.diff_preview else "",
126
+ }
127
+ )
128
+ return out
129
+
130
+
131
+ def render_adapter(
132
+ cap: mr.Manifest,
133
+ target_project: Path,
134
+ tech_stack: Optional[str],
135
+ *,
136
+ dry_run: bool,
137
+ ) -> Dict[str, Any]:
138
+ """Execute auto_adapters three-level degradation rendering for an external user project."""
139
+ integration = cap.integration or {}
140
+ auto_adapters = integration.get("auto_adapters") or []
141
+ fallback = integration.get("fallback") or {}
142
+
143
+ # Detect tech stack (auto-detect if not provided)
144
+ detected = sd.detect(target_project) if not tech_stack else None
145
+ primary = tech_stack or (detected.primary if detected else None)
146
+ adapter_name = sd.match_adapter(primary or "", auto_adapters) if primary else None
147
+
148
+ artifacts: List[Dict[str, Any]] = []
149
+ code_gen_ok = False
150
+ code_gen_error = ""
151
+
152
+ if adapter_name:
153
+ adapter_dir = ADAPTERS_ROOT / adapter_name
154
+ if adapter_dir.exists():
155
+ try:
156
+ adapter_mf = load_yaml(adapter_dir / "manifest.yaml")
157
+ tpl_def = (adapter_mf.get("templates") or {}).get(primary)
158
+ if not tpl_def:
159
+ code_gen_error = f"adapter '{adapter_name}' has no template for '{primary}'"
160
+ else:
161
+ variables = _merge_variables(adapter_mf, primary)
162
+ src_tpl = adapter_dir / tpl_def["file"]
163
+ target_path = Path(
164
+ render_template(tpl_def["target_path"], variables)
165
+ )
166
+ abs_target = target_project / target_path
167
+ rendered = render_template(
168
+ src_tpl.read_text(encoding="utf-8"), variables
169
+ )
170
+ if abs_target.exists() and not dry_run:
171
+ # Path conflict → treated as code generation failure → degrade to L2
172
+ code_gen_error = (
173
+ f"target file already exists: {abs_target}, refuse to overwrite"
174
+ )
175
+ else:
176
+ if not dry_run:
177
+ abs_target.parent.mkdir(parents=True, exist_ok=True)
178
+ abs_target.write_text(rendered, encoding="utf-8")
179
+ artifacts.append(
180
+ {
181
+ "type": "rendered_file",
182
+ "path": str(abs_target),
183
+ "size": len(rendered),
184
+ "dry_run": dry_run,
185
+ }
186
+ )
187
+ code_gen_ok = True
188
+ # Output install_hint
189
+ artifacts.append(
190
+ {
191
+ "type": "install_hint",
192
+ "content": tpl_def.get("install_hint", "").strip(),
193
+ "package_dependencies": tpl_def.get("package_dependencies") or [],
194
+ }
195
+ )
196
+ except Exception as exc: # noqa: BLE001
197
+ code_gen_error = f"{type(exc).__name__}: {exc}"
198
+
199
+ decision = dg.decide(
200
+ primary, adapter_name, code_gen_ok,
201
+ fallback=fallback,
202
+ code_gen_error=code_gen_error,
203
+ )
204
+
205
+ return {
206
+ "tech_stack_detected": detected.to_dict() if detected else None,
207
+ "tech_stack_used": primary,
208
+ "adapter": adapter_name,
209
+ "artifacts": artifacts,
210
+ "degrade": decision.to_dict(),
211
+ }
212
+
213
+
214
+ def _merge_variables(adapter_mf: Dict[str, Any], tech_stack: str) -> Dict[str, str]:
215
+ # Priority: env > adapters/manifest.yaml.default_variables > adapter.defaults
216
+ top = load_yaml(ADAPTERS_ROOT / "manifest.yaml")
217
+ out = {}
218
+ out.update(top.get("default_variables") or {})
219
+ out.update(adapter_mf.get("defaults") or {})
220
+ for k in list(out.keys()):
221
+ if os.getenv(k):
222
+ out[k] = os.getenv(k, "")
223
+ # Force all values to str
224
+ return {k: str(v) for k, v in out.items()}
225
+
226
+
227
+ # ---------------------------------------------------------------------------
228
+ # CLI
229
+ # ---------------------------------------------------------------------------
230
+ def cmd_list() -> Dict[str, Any]:
231
+ mfs = mr.discover_manifests(CAPS_ROOT)
232
+ graph = mr.resolve(mfs)
233
+ return {
234
+ "skeleton": graph.skeleton.name,
235
+ "topo_order": graph.order,
236
+ "capabilities": [
237
+ {
238
+ "name": m.name,
239
+ "version": m.version,
240
+ "type": m.type,
241
+ "dependencies": [{"name": d.name, "version": d.version} for d in m.dependencies],
242
+ "extensions_count": len(m.extensions),
243
+ }
244
+ for m in mfs
245
+ ],
246
+ }
247
+
248
+
249
+ def cmd_graph() -> str:
250
+ mfs = mr.discover_manifests(CAPS_ROOT)
251
+ graph = mr.resolve(mfs)
252
+ return mr.to_dot(graph)
253
+
254
+
255
+ def cmd_install(
256
+ cap_names: List[str],
257
+ *,
258
+ target_project: Optional[Path],
259
+ tech_stack: Optional[str],
260
+ dry_run: bool,
261
+ ) -> Dict[str, Any]:
262
+ mfs = mr.discover_manifests(CAPS_ROOT)
263
+ graph = mr.resolve(mfs)
264
+ name_set = set(cap_names)
265
+ unknown = [n for n in name_set if n not in graph.manifests]
266
+ if unknown:
267
+ raise SystemExit(f"unknown capabilities: {unknown}")
268
+ install_order = [n for n in graph.order if n in name_set]
269
+ reports: List[Dict[str, Any]] = []
270
+ for n in install_order:
271
+ cap = graph.manifests[n]
272
+ sk_inj = inject_into_skeleton(graph.skeleton, cap, dry_run=dry_run)
273
+ adapter_info = None
274
+ if target_project is not None:
275
+ adapter_info = render_adapter(
276
+ cap, target_project, tech_stack, dry_run=dry_run
277
+ )
278
+ reports.append(
279
+ InstallReport(
280
+ capability=n,
281
+ skeleton_injection=sk_inj,
282
+ adapter=adapter_info,
283
+ degrade=adapter_info["degrade"] if adapter_info else None,
284
+ ).to_dict()
285
+ )
286
+ return {
287
+ "skeleton": graph.skeleton.name,
288
+ "install_order": install_order,
289
+ "dry_run": dry_run,
290
+ "reports": reports,
291
+ }
292
+
293
+
294
+ def main() -> None:
295
+ parser = argparse.ArgumentParser(description="Capability overlay CLI")
296
+ parser.add_argument("capabilities", nargs="*", help="Capability package names to install")
297
+ parser.add_argument("--list", action="store_true", help="List discovered capability packages")
298
+ parser.add_argument("--graph", action="store_true", help="Output dependency graph in DOT format")
299
+ parser.add_argument(
300
+ "--target-project", type=Path, default=None,
301
+ help="External user project root directory (enables auto_adapters rendering)",
302
+ )
303
+ parser.add_argument("--tech-stack", default=None, help="Override auto-detected tech stack")
304
+ parser.add_argument("--apply", action="store_true", help="Actually write changes (default is dry-run)")
305
+ parser.add_argument("--json", action="store_true", help="Output JSON for easy Agent parsing")
306
+ args = parser.parse_args()
307
+
308
+ if args.list:
309
+ out = cmd_list()
310
+ print(json.dumps(out, ensure_ascii=False, indent=2) if args.json else _pretty_list(out))
311
+ return
312
+ if args.graph:
313
+ print(cmd_graph())
314
+ return
315
+ if not args.capabilities:
316
+ parser.print_help()
317
+ return
318
+
319
+ out = cmd_install(
320
+ args.capabilities,
321
+ target_project=args.target_project,
322
+ tech_stack=args.tech_stack,
323
+ dry_run=not args.apply,
324
+ )
325
+ if args.json:
326
+ print(json.dumps(out, ensure_ascii=False, indent=2))
327
+ else:
328
+ print(_pretty_install(out))
329
+
330
+
331
+ def _pretty_list(out: Dict[str, Any]) -> str:
332
+ lines = [f"skeleton: {out['skeleton']}", f"topo_order: {' -> '.join(out['topo_order'])}", ""]
333
+ for c in out["capabilities"]:
334
+ deps = ", ".join(f"{d['name']}@{d['version']}" for d in c["dependencies"]) or "-"
335
+ lines.append(f" · {c['name']} {c['version']} [{c['type']}] deps={deps} extensions={c['extensions_count']}")
336
+ return "\n".join(lines)
337
+
338
+
339
+ def _pretty_install(out: Dict[str, Any]) -> str:
340
+ lines = [
341
+ f"skeleton: {out['skeleton']}",
342
+ f"install_order: {' -> '.join(out['install_order'])}",
343
+ f"dry_run: {out['dry_run']}",
344
+ "",
345
+ ]
346
+ for r in out["reports"]:
347
+ lines.append(f"[{r['capability']}]")
348
+ for inj in r["skeleton_injection"]:
349
+ mark = "✓" if inj["applied"] else ("·" if not inj["error"] else "✗")
350
+ lines.append(
351
+ f" {mark} {inj['inject_at']} -> {inj['target']} ({inj['op']}:{inj['anchor']})"
352
+ + (f" err={inj['error']}" if inj["error"] else "")
353
+ )
354
+ if r.get("adapter"):
355
+ lines.append(
356
+ f" adapter={r['adapter']['adapter']} stack={r['adapter']['tech_stack_used']} "
357
+ f"degrade={r['adapter']['degrade']['level']}"
358
+ )
359
+ lines.append("")
360
+ return "\n".join(lines)
361
+
362
+
363
+ if __name__ == "__main__":
364
+ main()
@@ -0,0 +1,334 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Capability contract adapter (Phase 3 Stage 4).
4
+
5
+ Adapts the user's existing system interfaces (curl or OpenAPI) to the capability's default contract,
6
+ generates ``capabilities/<name>/src/adapters/user_custom.py``, with L1/L2/L3 three-tier fallback.
7
+
8
+ Usage
9
+ -----
10
+ # 1) Show the current default contract for a capability
11
+ python3 scripts/contract-adapt.py human-handoff --show-default --json
12
+
13
+ # 2) Align a single API using a curl file
14
+ python3 scripts/contract-adapt.py human-handoff \
15
+ --api-name ticket.create \
16
+ --curl-file /tmp/user_create.curl \
17
+ --base-url https://crm.example.com \
18
+ --apply --json
19
+
20
+ # 3) Align an entire capability using an OpenAPI file (all outbound APIs at once)
21
+ python3 scripts/contract-adapt.py knowledge-base \
22
+ --openapi-file /tmp/user-faq.yaml \
23
+ --apply --json
24
+
25
+ # 4) dry-run (no files written)
26
+ python3 scripts/contract-adapt.py human-handoff \
27
+ --curl-file /tmp/x.curl --json # omit --apply for dry-run
28
+
29
+ Security Constraints
30
+ --------------------
31
+ - User API descriptions only accept **file paths**; inline input is not allowed (avoids shell history logging tokens)
32
+ - Generated code is automatically backed up as ``user_custom.py.bak``
33
+ """
34
+ from __future__ import annotations
35
+
36
+ import argparse
37
+ import json
38
+ import sys
39
+ from pathlib import Path
40
+ from typing import Dict, List, Optional, Tuple
41
+
42
+ _HERE = Path(__file__).resolve().parent
43
+ _ROOT = _HERE.parent
44
+ if str(_ROOT) not in sys.path:
45
+ sys.path.insert(0, str(_ROOT))
46
+
47
+ from scripts.lib import adapter_codegen as cg # noqa: E402
48
+ from scripts.lib import contract_resolver as cr # noqa: E402
49
+ from scripts.lib import curl_parser as cp # noqa: E402
50
+ from scripts.lib import openapi_parser as op # noqa: E402
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Output utilities
55
+ # ---------------------------------------------------------------------------
56
+ def _emit(payload: Dict, json_mode: bool) -> None:
57
+ if json_mode:
58
+ sys.stdout.write(json.dumps(payload, ensure_ascii=False, indent=2))
59
+ sys.stdout.write("\n")
60
+ sys.stdout.flush()
61
+ else:
62
+ sys.stdout.write(json.dumps(payload, ensure_ascii=False, indent=2))
63
+ sys.stdout.write("\n")
64
+
65
+
66
+ def _emit_error(message: str, json_mode: bool, *, code: str = "GENERAL") -> int:
67
+ _emit({"ok": False, "error": code, "message": message}, json_mode)
68
+ return 1
69
+
70
+
71
+ # ---------------------------------------------------------------------------
72
+ # Default contract display
73
+ # ---------------------------------------------------------------------------
74
+ def _show_default(contract: cr.BusinessContract, json_mode: bool) -> int:
75
+ payload = {
76
+ "ok": True,
77
+ "capability": contract.capability,
78
+ "port_class": contract.port_class,
79
+ "default_adapter": contract.default_adapter,
80
+ "mock_adapter": contract.mock_adapter,
81
+ "customization_sop": contract.customization_sop,
82
+ "outbound_apis": [
83
+ {
84
+ "name": a.name,
85
+ "method": a.method,
86
+ "path": a.path,
87
+ "description": a.description,
88
+ "request_schema": a.request_schema,
89
+ "response_schema": a.response_schema,
90
+ "adapter_slots": a.adapter_slots,
91
+ "auth": a.auth.to_dict(),
92
+ "timeout_ms": a.timeout_ms,
93
+ }
94
+ for a in contract.outbound_apis()
95
+ ],
96
+ }
97
+ _emit(payload, json_mode)
98
+ return 0
99
+
100
+
101
+ # ---------------------------------------------------------------------------
102
+ # User API loading
103
+ # ---------------------------------------------------------------------------
104
+ def _load_user_apis(
105
+ *,
106
+ curl_file: Optional[Path],
107
+ openapi_file: Optional[Path],
108
+ api_name: Optional[str],
109
+ ) -> Tuple[List[cp.ParsedApi], List[str]]:
110
+ """Return (user ParsedApi list, warnings); the caller decides how to pair them with the default contract."""
111
+ warnings: List[str] = []
112
+ apis: List[cp.ParsedApi] = []
113
+
114
+ if curl_file:
115
+ if not curl_file.exists():
116
+ raise FileNotFoundError(f"curl file not found: {curl_file}")
117
+ text = curl_file.read_text(encoding="utf-8")
118
+ try:
119
+ apis.append(cp.parse_curl_with_response(text))
120
+ except cp.CurlParseError as exc:
121
+ raise RuntimeError(f"curl parse failed: {exc}") from exc
122
+
123
+ if openapi_file:
124
+ if not openapi_file.exists():
125
+ raise FileNotFoundError(f"openapi file not found: {openapi_file}")
126
+ try:
127
+ ops = op.parse_openapi(openapi_file)
128
+ except op.OpenApiParseError as exc:
129
+ raise RuntimeError(f"openapi parse failed: {exc}") from exc
130
+ if not ops:
131
+ warnings.append("openapi file contains no operations")
132
+ apis.extend(ops)
133
+
134
+ return apis, warnings
135
+
136
+
137
+ # ---------------------------------------------------------------------------
138
+ # pairing: match user APIs with the default contract's outbound apis
139
+ # ---------------------------------------------------------------------------
140
+ def _pair_apis(
141
+ contract: cr.BusinessContract,
142
+ user_apis: List[cp.ParsedApi],
143
+ explicit_name: Optional[str],
144
+ ) -> List[cg.ApiAdaptation]:
145
+ outbound = contract.outbound_apis()
146
+ out: List[cg.ApiAdaptation] = []
147
+
148
+ if explicit_name:
149
+ target = contract.get_api(explicit_name)
150
+ if target is None:
151
+ raise ValueError(f"no api named {explicit_name!r} in contract {contract.capability}")
152
+ # explicit name → pair with the first user api
153
+ if not user_apis:
154
+ return [cg.ApiAdaptation(default=target, user=None, diff=None)]
155
+ diff = cr.diff_contracts(target, user_apis[0])
156
+ return [cg.ApiAdaptation(default=target, user=user_apis[0], diff=diff)]
157
+
158
+ # auto pairing: match by method + path suffix similarity
159
+ paired: Dict[str, cp.ParsedApi] = {}
160
+ used: set = set()
161
+ for default_api in outbound:
162
+ match = _best_match(default_api, user_apis, used)
163
+ if match is not None:
164
+ paired[default_api.name] = match
165
+ used.add(id(match))
166
+
167
+ for default_api in outbound:
168
+ user_api = paired.get(default_api.name)
169
+ if user_api is None:
170
+ out.append(cg.ApiAdaptation(default=default_api, user=None, diff=None))
171
+ else:
172
+ diff = cr.diff_contracts(default_api, user_api)
173
+ out.append(cg.ApiAdaptation(default=default_api, user=user_api, diff=diff))
174
+ return out
175
+
176
+
177
+ def _best_match(
178
+ default_api: cr.ExternalApi,
179
+ user_apis: List[cp.ParsedApi],
180
+ used: set,
181
+ ) -> Optional[cp.ParsedApi]:
182
+ """Simple match: method must match; best path tail similarity wins."""
183
+ candidates = [u for u in user_apis if id(u) not in used and u.method.upper() == default_api.method.upper()]
184
+ if not candidates:
185
+ return None
186
+ if len(candidates) == 1:
187
+ return candidates[0]
188
+ # best path tail semantic similarity
189
+ default_tail = default_api.path.rstrip("/").rsplit("/", 1)[-1] or default_api.path
190
+ best = candidates[0]
191
+ best_score = -1
192
+ for c in candidates:
193
+ c_tail = c.path.rstrip("/").rsplit("/", 1)[-1] or c.path
194
+ score = _similarity(default_tail, c_tail)
195
+ if score > best_score:
196
+ best_score = score
197
+ best = c
198
+ return best
199
+
200
+
201
+ def _similarity(a: str, b: str) -> int:
202
+ a_low = a.lower()
203
+ b_low = b.lower()
204
+ if a_low == b_low:
205
+ return 100
206
+ if a_low in b_low or b_low in a_low:
207
+ return 60
208
+ common = set(a_low) & set(b_low)
209
+ return len(common)
210
+
211
+
212
+ # ---------------------------------------------------------------------------
213
+ # Main entry
214
+ # ---------------------------------------------------------------------------
215
+ def main(argv=None) -> int:
216
+ parser = argparse.ArgumentParser(
217
+ prog="contract-adapt",
218
+ description="Capability contract adaptation (curl / OpenAPI → user_custom.py)",
219
+ )
220
+ parser.add_argument("capability", help="Capability name (subdirectory under capabilities/)")
221
+ parser.add_argument("--curl-file", type=Path, default=None, help="User API curl file path")
222
+ parser.add_argument(
223
+ "--openapi-file",
224
+ type=Path,
225
+ default=None,
226
+ help="User API OpenAPI YAML / JSON file path",
227
+ )
228
+ parser.add_argument(
229
+ "--api-name",
230
+ default="",
231
+ help="Align only the specified contract name (e.g., ticket.create); default attempts to auto-pair all outbound APIs",
232
+ )
233
+ parser.add_argument(
234
+ "--base-url",
235
+ default="",
236
+ help="Default base_url hint written into user_custom.py (not hardcoded)",
237
+ )
238
+ parser.add_argument(
239
+ "--auth-header",
240
+ default="",
241
+ help="Override auth header name (e.g., X-Auth-Token); defaults to Authorization if empty",
242
+ )
243
+ parser.add_argument(
244
+ "--show-default",
245
+ action="store_true",
246
+ help="Print the current default contract list without adapting",
247
+ )
248
+ parser.add_argument("--apply", action="store_true", help="Write generated code to file (default is dry-run)")
249
+ parser.add_argument("--json", action="store_true", help="Output JSON")
250
+ args = parser.parse_args(argv)
251
+
252
+ json_mode = args.json
253
+ cap_dir = _ROOT / "capabilities" / args.capability
254
+ if not cap_dir.exists():
255
+ return _emit_error(
256
+ f"capability not found: {cap_dir}", json_mode, code="CAP_NOT_FOUND"
257
+ )
258
+
259
+ # 1) Load default contract
260
+ try:
261
+ contract = cr.load_business_contract(cap_dir)
262
+ except cr.ContractError as exc:
263
+ return _emit_error(str(exc), json_mode, code=exc.code)
264
+
265
+ if args.show_default:
266
+ return _show_default(contract, json_mode)
267
+
268
+ if not args.curl_file and not args.openapi_file:
269
+ return _emit_error(
270
+ "must provide --curl-file or --openapi-file (or use --show-default)",
271
+ json_mode,
272
+ code="MISSING_INPUT",
273
+ )
274
+
275
+ # 2) Load user API
276
+ try:
277
+ user_apis, warnings = _load_user_apis(
278
+ curl_file=args.curl_file,
279
+ openapi_file=args.openapi_file,
280
+ api_name=args.api_name or None,
281
+ )
282
+ except (FileNotFoundError, RuntimeError, ValueError) as exc:
283
+ return _emit_error(str(exc), json_mode, code="PARSE_FAILED")
284
+
285
+ if not user_apis:
286
+ return _emit_error("no user API parsed", json_mode, code="EMPTY_INPUT")
287
+
288
+ # 3) Pairing & diff
289
+ try:
290
+ adaptations = _pair_apis(contract, user_apis, args.api_name or None)
291
+ except ValueError as exc:
292
+ return _emit_error(str(exc), json_mode, code="PAIRING_FAILED")
293
+
294
+ # 4) Static manifest validation (warnings only in payload)
295
+ manifest_warnings = cr.validate_manifest(cap_dir)
296
+
297
+ # 5) Code generation
298
+ result = cg.generate_user_custom(
299
+ contract,
300
+ adaptations,
301
+ cap_dir,
302
+ base_url=args.base_url,
303
+ auth_header=args.auth_header,
304
+ dry_run=not args.apply,
305
+ )
306
+
307
+ payload: Dict = {
308
+ "ok": True,
309
+ "capability": contract.capability,
310
+ "level": result.level.value,
311
+ "artifact": result.artifact,
312
+ "todos": result.todos,
313
+ "notes": result.notes,
314
+ "enable_env": result.enable_env,
315
+ "warnings": warnings + manifest_warnings,
316
+ "applied": args.apply,
317
+ "adaptations": [
318
+ {
319
+ "api_name": a.default.name,
320
+ "level": a.level.value,
321
+ "method_match": (a.diff.method_match if a.diff else True),
322
+ "path_match": (a.diff.path_match if a.diff else True),
323
+ "diff": a.diff.to_dict() if a.diff else None,
324
+ "user_api": a.user.to_dict() if a.user else None,
325
+ }
326
+ for a in adaptations
327
+ ],
328
+ }
329
+ _emit(payload, json_mode)
330
+ return 0 if result.level != cr.DegradeLevel.L3 else 0 # L3 also exits normally; AI decides next step
331
+
332
+
333
+ if __name__ == "__main__":
334
+ sys.exit(main())