@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,540 @@
1
+ """Shared TRTC apply tool.
2
+
3
+ Default CLI contract:
4
+
5
+ python3 -m tools.apply --slice <slice_id>
6
+ python3 -m tools.apply --unit <unit_id>
7
+ python3 -m tools.apply --slice <slice_id> --product <product> --platform <platform>
8
+
9
+ This default mode is topic-facing: it runs the shared apply gate, advances the
10
+ state machine on pass/fail, writes evidence, and prints the human-readable
11
+ result expected by the topic loop. Exit codes match the legacy topic wrapper:
12
+
13
+ 0 - apply pass
14
+ 1 - apply fail
15
+ 2 - usage / orchestration error
16
+
17
+ Raw JSON contract:
18
+
19
+ python3 -m tools.apply --json --slice <slice_id>
20
+
21
+ `--json` exposes the shared-tool contract directly. It emits structured JSON
22
+ (``status`` = ``passed`` / ``failed`` / ``usage_error`` / ``dependency_error`` /
23
+ ``internal_error``) and does NOT mutate the topic state machine; orchestration
24
+ layers are responsible for reading ``state_transition_suggested`` and advancing
25
+ session state themselves.
26
+
27
+ Plugin discovery: for each product, the dispatcher looks for
28
+ skills/trtc-{product}/tools/apply_checks.py
29
+ and calls its ``build_checks(target_id, slice_ids, project_root, platform)`` function.
30
+ If no checker is found, the tool passes with empty checks (no-checker mode).
31
+ """
32
+ from __future__ import annotations
33
+
34
+ import argparse
35
+ import importlib.util
36
+ import json
37
+ import os
38
+ import re
39
+ import sys
40
+ from datetime import datetime, timezone
41
+ from pathlib import Path
42
+
43
+ try:
44
+ import yaml
45
+ except Exception as exc: # pragma: no cover
46
+ yaml = None # type: ignore[assignment]
47
+ _YAML_IMPORT_ERROR = exc
48
+ else:
49
+ _YAML_IMPORT_ERROR = None
50
+
51
+
52
+ EXIT_SUCCESS = 0
53
+ EXIT_INPUT_ERROR = 1
54
+ EXIT_DEPENDENCY_ERROR = 2
55
+ EXIT_INTERNAL_ERROR = 3
56
+
57
+ # Product names must be simple lowercase identifiers to prevent path traversal.
58
+ _PRODUCT_RE = re.compile(r"^[a-z0-9][a-z0-9-]*$")
59
+
60
+ _REPO_ROOT = Path(__file__).resolve().parents[3]
61
+ _STATE_MACHINE_DIR = _REPO_ROOT / "skills" / "trtc" / "tools" / "lib"
62
+
63
+ _STATE_MACHINE_IMPORT_ERROR: Exception | None = None
64
+ try:
65
+ sys.path.insert(0, str(_STATE_MACHINE_DIR))
66
+ import state_machine # noqa: E402
67
+ except ImportError as exc: # pragma: no cover
68
+ state_machine = None # type: ignore[assignment]
69
+ _STATE_MACHINE_IMPORT_ERROR = exc
70
+ finally:
71
+ try:
72
+ sys.path.remove(str(_STATE_MACHINE_DIR))
73
+ except ValueError: # pragma: no cover
74
+ pass
75
+
76
+
77
+ class InputError(RuntimeError):
78
+ """Invalid CLI / session input."""
79
+
80
+
81
+ class DependencyError(RuntimeError):
82
+ """Local dependency / import failure."""
83
+
84
+
85
+ def _utc_now_z() -> str:
86
+ return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
87
+
88
+
89
+ def _resolve_session_path() -> Path:
90
+ explicit = os.environ.get("TRTC_SESSION_PATH")
91
+ if explicit:
92
+ return Path(explicit)
93
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR")
94
+ if project_dir:
95
+ return Path(project_dir) / ".trtc-session.yaml"
96
+ return Path.cwd() / ".trtc-session.yaml"
97
+
98
+
99
+ def _slice_id_to_slug(slice_id: str) -> str:
100
+ return slice_id.replace("/", "__")
101
+
102
+
103
+ def _load_session(session_path: Path) -> dict:
104
+ if yaml is None:
105
+ raise DependencyError(f"PyYAML import failed: {_YAML_IMPORT_ERROR}")
106
+ return yaml.safe_load(session_path.read_text()) or {}
107
+
108
+
109
+ def _ensure_dependencies() -> None:
110
+ if yaml is None:
111
+ raise DependencyError(f"PyYAML import failed: {_YAML_IMPORT_ERROR}")
112
+ if _STATE_MACHINE_IMPORT_ERROR is not None:
113
+ raise DependencyError(str(_STATE_MACHINE_IMPORT_ERROR))
114
+
115
+
116
+ def _load_product_checker(product: str) -> tuple:
117
+ """Dynamically load skills/trtc-{product}/tools/apply_checks.py.
118
+
119
+ Returns (module, None) if found and loadable.
120
+ Returns (None, None) if no checker file exists — this is the normal
121
+ no-checker case (product does not yet have apply verification).
122
+ Returns (None, error_str) if the file EXISTS but is broken (syntax error,
123
+ import error, missing build_checks, etc.) — callers must treat this as a
124
+ hard error, not a silent pass.
125
+ """
126
+ if not _PRODUCT_RE.match(product):
127
+ return None, f"invalid product name '{product}': must match [a-z0-9][a-z0-9-]*"
128
+ checker_path = _REPO_ROOT / "skills" / f"trtc-{product}" / "tools" / "apply_checks.py"
129
+ # Guard against path traversal after Path resolution (e.g. symlinks).
130
+ expected_parent = (_REPO_ROOT / "skills").resolve()
131
+ try:
132
+ checker_path.resolve().relative_to(expected_parent)
133
+ except ValueError:
134
+ return None, f"checker path for '{product}' escapes expected directory"
135
+ if not checker_path.exists():
136
+ return None, None # normal: no checker for this product
137
+ spec = importlib.util.spec_from_file_location(f"_apply_checks_{product}", checker_path)
138
+ if spec is None or spec.loader is None: # pragma: no cover
139
+ return None, f"could not create import spec for {checker_path}"
140
+ module = importlib.util.module_from_spec(spec)
141
+ try:
142
+ spec.loader.exec_module(module) # type: ignore[union-attr]
143
+ except Exception as exc:
144
+ return None, f"apply_checks.py failed to load: {exc}"
145
+ if not callable(getattr(module, "build_checks", None)):
146
+ return None, f"apply_checks.py for '{product}' is missing required build_checks() function"
147
+ return module, None
148
+
149
+
150
+ def _product_from_target(target_id: str, slice_ids: list[str]) -> str | None:
151
+ """Infer product from target_id / slice_ids prefix (the part before '/').
152
+
153
+ Returns the inferred product name if all IDs share the same prefix, or
154
+ None if no ID contains '/' (target_id is a bare unit name with no
155
+ associated slice_ids — no inference possible; validation skipped).
156
+ Raises InputError if:
157
+ - any slice_id lacks '/' (malformed / hand-edited session)
158
+ - IDs span multiple product prefixes (mixed-product unit)
159
+ """
160
+ malformed = [sid for sid in slice_ids if "/" not in sid]
161
+ if malformed:
162
+ raise InputError(
163
+ f"malformed slice id(s): {', '.join(repr(s) for s in malformed)}; "
164
+ "slice ids must be in 'product/slug' format"
165
+ )
166
+ ids = [target_id] + list(slice_ids)
167
+ prefixes = {sid.split("/")[0] for sid in ids if "/" in sid}
168
+ if len(prefixes) > 1:
169
+ raise InputError(
170
+ f"mixed-product unit: slices span multiple products "
171
+ f"({', '.join(sorted(prefixes))}); all slices in a unit must belong to the same product"
172
+ )
173
+ return prefixes.pop() if len(prefixes) == 1 else None
174
+
175
+
176
+ def _resolve_target(scope: dict, slice_id: str | None, unit_id: str | None) -> tuple[str, str, list[str]]:
177
+ if not scope.get("initialised"):
178
+ raise InputError("execution_queue not initialised")
179
+ if scope.get("state") != "code_written":
180
+ raise InputError(
181
+ f"current_execution_state must be 'code_written' before apply; got '{scope.get('state')}'"
182
+ )
183
+ current_id = scope.get("id")
184
+ current_kind = scope.get("kind")
185
+ slice_ids = list(scope.get("slice_ids") or [])
186
+ if current_kind == "unit":
187
+ if not unit_id:
188
+ raise InputError(f"current execution step is unit '{current_id}'; use --unit {current_id}")
189
+ if unit_id != current_id:
190
+ raise InputError(f"--unit '{unit_id}' does not match current unit '{current_id}'")
191
+ return "unit", current_id, slice_ids
192
+
193
+ if not slice_id:
194
+ raise InputError(f"current execution step is slice '{current_id}'; use --slice {current_id}")
195
+ if slice_id != current_id:
196
+ raise InputError(f"--slice '{slice_id}' does not match current slice '{current_id}'")
197
+ return "slice", current_id, slice_ids
198
+
199
+
200
+ def _resolve_product_platform(session_data: dict, product: str | None, platform: str | None) -> tuple[str, str]:
201
+ resolved_product = product or session_data.get("product")
202
+ resolved_platform = platform or session_data.get("platform")
203
+ if not resolved_product:
204
+ raise InputError("product is missing; pass --product or populate session.product")
205
+ if not resolved_platform:
206
+ raise InputError("platform is missing; pass --platform or populate session.platform")
207
+ return str(resolved_product), str(resolved_platform)
208
+
209
+
210
+ def _resolve_project_root(session_data: dict, project_root: Path | None) -> Path:
211
+ if project_root is not None:
212
+ return project_root
213
+ raw = (session_data.get("project_state") or {}).get("project_root")
214
+ if not raw:
215
+ raise InputError("project root missing; pass --project or populate session.project_state.project_root")
216
+ return Path(raw)
217
+
218
+
219
+ def _write_evidence(session_path: Path, target_id: str, payload: dict) -> str:
220
+ evidence_dir = session_path.parent / ".trtc-apply-evidence"
221
+ evidence_dir.mkdir(parents=True, exist_ok=True)
222
+ relative_path = f".trtc-apply-evidence/{_slice_id_to_slug(target_id)}.json"
223
+ (session_path.parent / relative_path).write_text(
224
+ json.dumps(payload, ensure_ascii=False, indent=2) + "\n",
225
+ encoding="utf-8",
226
+ )
227
+ return relative_path
228
+
229
+
230
+ def _build_parser(*, include_json: bool = False) -> argparse.ArgumentParser:
231
+ parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
232
+ parser.add_argument("--slice", dest="slice_id", default=None)
233
+ parser.add_argument("--unit", dest="unit_id", default=None)
234
+ parser.add_argument("--product", default=None)
235
+ parser.add_argument("--platform", default=None)
236
+ parser.add_argument("--session", type=Path, default=None)
237
+ parser.add_argument("--project", type=Path, default=None)
238
+ parser.add_argument("--dry-run", action="store_true")
239
+ if include_json:
240
+ parser.add_argument("--json", action="store_true")
241
+ return parser
242
+
243
+
244
+ def _count_entry_checks(shared_checks: list[dict]) -> int:
245
+ return sum(1 for check in shared_checks if check.get("id") == "entry_symbol_present")
246
+
247
+
248
+ def _failed_checks(shared_checks: list[dict]) -> list[dict]:
249
+ return [check for check in shared_checks if check.get("status") == "failed"]
250
+
251
+
252
+ _BD_REGISTRY: frozenset[str] = frozenset({
253
+ "conference/login-auth",
254
+ "conference/room-lifecycle",
255
+ "conference/participant-management",
256
+ "conference/room-call",
257
+ "conference/room-schedule",
258
+ })
259
+
260
+ _BD_NAMES: dict[str, str] = {
261
+ "conference/login-auth": "登录与鉴权",
262
+ "conference/room-lifecycle": "房间生命周期",
263
+ "conference/participant-management": "会控 / 成员管理",
264
+ "conference/room-call": "通话",
265
+ "conference/room-schedule": "会议预约",
266
+ }
267
+
268
+
269
+ def _check_conference_business_decisions(
270
+ session: dict,
271
+ slice_ids: list[str],
272
+ target_id: str,
273
+ scope_name: str,
274
+ session_path: "Path",
275
+ ) -> "tuple[int, dict] | None":
276
+ """Return a failure result if conference business_decisions are missing, else None."""
277
+ if session.get("active_domain_skill") != "trtc-conference":
278
+ return None
279
+ if session.get("active_flow") != "topic":
280
+ return None
281
+ if session.get("integration_path") in {"medical-quickstart", "official-roomkit"}:
282
+ return None
283
+
284
+ bd: dict = (session.get("session_context") or {}).get("business_decisions") or {}
285
+ missing = [s for s in slice_ids if s in _BD_REGISTRY and not bd.get(s)]
286
+ if not missing:
287
+ return None
288
+
289
+ missing_names = "、".join(_BD_NAMES.get(s, s) for s in missing)
290
+ check = {
291
+ "status": "failed",
292
+ "summary": (
293
+ f"[business-decisions] BLOCKED — do not show this message verbatim to the user. "
294
+ f"Business configuration not collected for: {missing_names}. "
295
+ f"Recovery: return to the business configuration step, ask the user the pending "
296
+ f"questions for these modules, then re-run apply. "
297
+ f"Do NOT show internal field names to the user. Say instead: "
298
+ f"「在生成代码之前,还有关于「{missing_names}」的几个配置问题需要确认。」"
299
+ ),
300
+ "detail": f"missing business_decisions for registry slices: {missing}",
301
+ }
302
+ result = {
303
+ "status": "failed",
304
+ "scope": scope_name,
305
+ "target_id": target_id,
306
+ "shared_checks": [check],
307
+ "state_transition_suggested": {"from": "code_written", "to": "apply_failed"},
308
+ "evidence_path": None,
309
+ "debug": {"mode": "business-decisions-pre-check", "missing_slices": missing, "session_path": str(session_path)},
310
+ }
311
+ return 1, result
312
+
313
+
314
+ def _run_parsed(args: argparse.Namespace) -> tuple[int, dict]:
315
+ _ensure_dependencies()
316
+
317
+ if bool(args.slice_id) == bool(args.unit_id):
318
+ raise InputError("provide exactly one of --slice <slice_id> or --unit <unit_id>")
319
+
320
+ session_path = args.session if args.session is not None else _resolve_session_path()
321
+ if not session_path.exists():
322
+ raise InputError(
323
+ f"session file not found: {session_path}; cd to the user project root or set TRTC_SESSION_PATH / CLAUDE_PROJECT_DIR"
324
+ )
325
+
326
+ session_data = _load_session(session_path)
327
+ scope = state_machine.current_scope(session_path)
328
+ scope_name, target_id, slice_ids = _resolve_target(scope, args.slice_id, args.unit_id)
329
+ product, platform = _resolve_product_platform(session_data, args.product, args.platform)
330
+ project_root = _resolve_project_root(session_data, args.project)
331
+
332
+ # Cross-validate: if all slice/unit IDs share a product prefix, it must
333
+ # match the supplied product. Mismatches indicate a caller passing
334
+ # --product chat while running conference slices, which would silently
335
+ # bypass all conference checks via the no-checker path.
336
+ inferred_product = _product_from_target(target_id, slice_ids)
337
+ if inferred_product and inferred_product != product:
338
+ raise InputError(
339
+ f"product mismatch: --product '{product}' was supplied but "
340
+ f"target '{target_id}' belongs to product '{inferred_product}'"
341
+ )
342
+
343
+ # Conference-specific pre-check: block if registry slice has no business_decisions.
344
+ # This is a second enforcement layer — the PreToolUse hook is the first.
345
+ bd_block = _check_conference_business_decisions(session_data, slice_ids, target_id, scope_name, session_path)
346
+ if bd_block is not None:
347
+ return bd_block
348
+
349
+ # Plugin dispatch: load product-specific checks if available.
350
+ checker, checker_error = _load_product_checker(product)
351
+ if checker_error is not None:
352
+ # Checker file exists but is broken — hard error, do not silently pass.
353
+ raise DependencyError(checker_error)
354
+ if checker is not None:
355
+ status, shared_checks, debug_checks = checker.build_checks(
356
+ target_id, slice_ids, project_root, platform
357
+ )
358
+ else:
359
+ # No apply_checks.py for this product yet — pass with an informational note.
360
+ status = "passed"
361
+ shared_checks = []
362
+ debug_checks = {
363
+ "mode": "no-checker",
364
+ "files_scanned": 0,
365
+ "slice_results": [],
366
+ "issues": [],
367
+ "note": f"no apply_checks.py found for product '{product}'; content checks skipped",
368
+ }
369
+
370
+ state_transition = {
371
+ "from": "code_written",
372
+ "to": "apply_passed" if status == "passed" else "apply_failed",
373
+ }
374
+ result = {
375
+ "status": status,
376
+ "scope": scope_name,
377
+ "target_id": target_id,
378
+ "shared_checks": shared_checks,
379
+ "state_transition_suggested": state_transition,
380
+ "evidence_path": None,
381
+ "debug": {
382
+ "project_root": str(project_root),
383
+ "product": product,
384
+ "platform": platform,
385
+ "session_path": str(session_path),
386
+ "dry_run": bool(args.dry_run),
387
+ **debug_checks,
388
+ },
389
+ }
390
+
391
+ if not args.dry_run:
392
+ evidence_payload = {
393
+ "schema_version": 1,
394
+ "target_id": target_id,
395
+ "scope": scope_name,
396
+ "status": status,
397
+ "checked_at": _utc_now_z(),
398
+ "shared_checks": shared_checks,
399
+ "product_checks": [],
400
+ # Legacy compat fields — consumers must not depend on these.
401
+ # See debug.legacy_field_notice.
402
+ "slice_id": slice_ids[0] if scope_name == "slice" else None,
403
+ "unit_id": target_id if scope_name == "unit" else None,
404
+ "slice_ids": slice_ids,
405
+ "kind": scope_name,
406
+ "mode": debug_checks.get("mode", "unknown"),
407
+ "issues": debug_checks.get("issues", []),
408
+ "debug": {
409
+ "legacy_field_notice": (
410
+ "slice_id/unit_id/slice_ids/kind/mode/issues are compat fields. "
411
+ "Use target_id + scope for new consumers."
412
+ ),
413
+ "project_root": str(project_root),
414
+ "product": product,
415
+ "platform": platform,
416
+ **{k: v for k, v in debug_checks.items() if k != "issues"},
417
+ },
418
+ }
419
+ result["evidence_path"] = _write_evidence(session_path, target_id, evidence_payload)
420
+
421
+ return EXIT_SUCCESS, result
422
+
423
+
424
+ def run(argv: list[str] | None = None) -> tuple[int, dict]:
425
+ args = _build_parser().parse_args(argv)
426
+ return _run_parsed(args)
427
+
428
+
429
+ def _error_payload(status: str, reason: str) -> dict:
430
+ return {
431
+ "status": status,
432
+ "scope": None,
433
+ "target_id": None,
434
+ "shared_checks": [],
435
+ "state_transition_suggested": None,
436
+ "evidence_path": None,
437
+ "reason": reason,
438
+ }
439
+
440
+
441
+ def _transition_name(payload: dict) -> str:
442
+ transition = payload.get("state_transition_suggested") or {}
443
+ next_state_name = transition.get("to")
444
+ if next_state_name == "apply_passed":
445
+ return "mark_apply_passed"
446
+ if next_state_name == "apply_failed":
447
+ return "mark_apply_failed"
448
+ raise RuntimeError(f"unsupported state transition suggestion: {transition}")
449
+
450
+
451
+ def _advance_human_cli(payload: dict, *, dry_run: bool) -> int:
452
+ status = payload["status"]
453
+ target_id = payload["target_id"]
454
+ shared_checks = payload.get("shared_checks") or []
455
+ session_path = Path(payload["debug"]["session_path"])
456
+
457
+ if not dry_run:
458
+ state_machine.advance(session_path, _transition_name(payload))
459
+
460
+ if status == "passed":
461
+ entries_checked = _count_entry_checks(shared_checks)
462
+ if dry_run:
463
+ print(
464
+ f"apply pass (dry-run): {entries_checked} slice "
465
+ f"entr{'y' if entries_checked == 1 else 'ies'} wired up for {target_id}"
466
+ )
467
+ return 0
468
+
469
+ session_data = _load_session(session_path)
470
+ policy = session_data.get("auto_advance_policy")
471
+ if policy in {"pause_on_failure", "pause_at_end"}:
472
+ new_state = state_machine.advance(session_path, "mark_user_confirmed")
473
+ print(
474
+ f"apply pass: {entries_checked} slice entr"
475
+ f"{'y' if entries_checked == 1 else 'ies'} wired up for "
476
+ f"{target_id} — auto-advanced ({policy}); next state: {new_state}"
477
+ )
478
+ if new_state == "all_done":
479
+ print("")
480
+ print("=" * 60)
481
+ print("ALL SLICES COMPLETE — POST-LOOP CHECKLIST (mandatory)")
482
+ print("=" * 60)
483
+ print("The slice loop is finished, but the topic flow is NOT done.")
484
+ print("You MUST now execute these steps from topic/SKILL.md:")
485
+ print("")
486
+ print(" □ Step 4: Present the verification checklist to the user")
487
+ print(" □ Step 4.5: Offer runtime verification & telemetry")
488
+ print(" (ask consent if telemetry.opted_in is null)")
489
+ print("")
490
+ print("Do NOT output a final summary and stop. Read topic/SKILL.md")
491
+ print("Step 4 and Step 4.5 sections and execute them now.")
492
+ print("=" * 60)
493
+ return 0
494
+ print(
495
+ f"apply pass: {entries_checked} slice entr"
496
+ f"{'y' if entries_checked == 1 else 'ies'} wired up for {target_id}"
497
+ )
498
+ return 0
499
+
500
+ failed_checks = _failed_checks(shared_checks)
501
+ if dry_run:
502
+ print(f"apply fail (dry-run): {len(failed_checks)} shared check(s) failed for {target_id}")
503
+ return 1
504
+
505
+ print(f"apply fail: {len(failed_checks)} shared check(s) failed for {target_id}")
506
+ for check in failed_checks[:5]:
507
+ print(f" - {check.get('summary', '')[:160]}")
508
+ return 1
509
+
510
+
511
+ def main(argv: list[str] | None = None) -> int:
512
+ args = _build_parser(include_json=True).parse_args(argv)
513
+ try:
514
+ exit_code, payload = _run_parsed(args)
515
+ if args.json:
516
+ print(json.dumps(payload, ensure_ascii=False))
517
+ return exit_code
518
+ return _advance_human_cli(payload, dry_run=bool(args.dry_run))
519
+ except InputError as exc:
520
+ if args.json:
521
+ print(json.dumps(_error_payload("usage_error", str(exc)), ensure_ascii=False))
522
+ return EXIT_INPUT_ERROR
523
+ print(f"error: {exc}", file=sys.stderr)
524
+ return 2
525
+ except DependencyError as exc:
526
+ if args.json:
527
+ print(json.dumps(_error_payload("dependency_error", str(exc)), ensure_ascii=False))
528
+ return EXIT_DEPENDENCY_ERROR
529
+ print(f"error: {exc}", file=sys.stderr)
530
+ return 2
531
+ except Exception as exc: # pragma: no cover
532
+ if args.json:
533
+ print(json.dumps(_error_payload("internal_error", str(exc)), ensure_ascii=False))
534
+ return EXIT_INTERNAL_ERROR
535
+ print(f"error: {exc}", file=sys.stderr)
536
+ return 2
537
+
538
+
539
+ if __name__ == "__main__":
540
+ sys.exit(main())