@tencent-rtc/trtc-agent-skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/README.zh.md +173 -0
  4. package/bin/cli.js +434 -0
  5. package/knowledge-base/index.yaml +454 -0
  6. package/knowledge-base/platform-slice-template.md +233 -0
  7. package/knowledge-base/scenario-spec.md +350 -0
  8. package/knowledge-base/scenarios/conference/base/general-conference.md +365 -0
  9. package/knowledge-base/scenarios/conference/base/webinar-conference.md +130 -0
  10. package/knowledge-base/scenarios/conference/medical/1v1-video-consultation.md +145 -0
  11. package/knowledge-base/scenarios/conference/medical/medical-multidoctor-consultation.md +113 -0
  12. package/knowledge-base/scenarios/live/entertainment-live-room.md +118 -0
  13. package/knowledge-base/slice-spec.md +546 -0
  14. package/knowledge-base/slices/conference/web/ai-tools.md +225 -0
  15. package/knowledge-base/slices/conference/web/beauty-effects.md +188 -0
  16. package/knowledge-base/slices/conference/web/device-control.md +338 -0
  17. package/knowledge-base/slices/conference/web/login-auth.md +261 -0
  18. package/knowledge-base/slices/conference/web/network-quality.md +190 -0
  19. package/knowledge-base/slices/conference/web/official-roomkit-api.md +298 -0
  20. package/knowledge-base/slices/conference/web/official-roomkit-login-ui.md +246 -0
  21. package/knowledge-base/slices/conference/web/participant-list.md +238 -0
  22. package/knowledge-base/slices/conference/web/participant-management.md +718 -0
  23. package/knowledge-base/slices/conference/web/prejoin-check.md +293 -0
  24. package/knowledge-base/slices/conference/web/room-call.md +213 -0
  25. package/knowledge-base/slices/conference/web/room-chat.md +426 -0
  26. package/knowledge-base/slices/conference/web/room-lifecycle.md +534 -0
  27. package/knowledge-base/slices/conference/web/room-schedule.md +281 -0
  28. package/knowledge-base/slices/conference/web/screen-share.md +211 -0
  29. package/knowledge-base/slices/conference/web/video-layout.md +675 -0
  30. package/knowledge-base/slices/conference/web/virtual-background.md +197 -0
  31. package/knowledge-base/slices/conference/web/webinar-interaction.md +206 -0
  32. package/knowledge-base/slices/live/anchor-lifecycle.md +122 -0
  33. package/knowledge-base/slices/live/anchor-preview.md +90 -0
  34. package/knowledge-base/slices/live/anchor-room-config.md +104 -0
  35. package/knowledge-base/slices/live/audience-list.md +86 -0
  36. package/knowledge-base/slices/live/audience-manage.md +92 -0
  37. package/knowledge-base/slices/live/audience-watch.md +85 -0
  38. package/knowledge-base/slices/live/audio.md +116 -0
  39. package/knowledge-base/slices/live/barrage.md +88 -0
  40. package/knowledge-base/slices/live/beauty.md +99 -0
  41. package/knowledge-base/slices/live/coguest-apply.md +105 -0
  42. package/knowledge-base/slices/live/device-control.md +91 -0
  43. package/knowledge-base/slices/live/error-codes.md +167 -0
  44. package/knowledge-base/slices/live/gift.md +84 -0
  45. package/knowledge-base/slices/live/ios/.gitkeep +0 -0
  46. package/knowledge-base/slices/live/ios/anchor-lifecycle.md +313 -0
  47. package/knowledge-base/slices/live/ios/anchor-preview.md +228 -0
  48. package/knowledge-base/slices/live/ios/anchor-room-config.md +257 -0
  49. package/knowledge-base/slices/live/ios/audience-list.md +353 -0
  50. package/knowledge-base/slices/live/ios/audience-manage.md +381 -0
  51. package/knowledge-base/slices/live/ios/audience-watch.md +286 -0
  52. package/knowledge-base/slices/live/ios/audio.md +373 -0
  53. package/knowledge-base/slices/live/ios/barrage.md +285 -0
  54. package/knowledge-base/slices/live/ios/beauty.md +323 -0
  55. package/knowledge-base/slices/live/ios/coguest-apply.md +506 -0
  56. package/knowledge-base/slices/live/ios/device-control.md +286 -0
  57. package/knowledge-base/slices/live/ios/error-codes.md +270 -0
  58. package/knowledge-base/slices/live/ios/gift.md +315 -0
  59. package/knowledge-base/slices/live/ios/live-list.md +269 -0
  60. package/knowledge-base/slices/live/ios/login-auth.md +247 -0
  61. package/knowledge-base/slices/live/live-list.md +82 -0
  62. package/knowledge-base/slices/live/login-auth.md +78 -0
  63. package/package.json +34 -0
  64. package/skills/trtc/SKILL.md +326 -0
  65. package/skills/trtc/room-builder/SKILL.md +138 -0
  66. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/README.md +108 -0
  67. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/docs/backend-contract.zh-CN.md +162 -0
  68. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/docs/integration.zh-CN.md +154 -0
  69. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/docs/theme.zh-CN.md +78 -0
  70. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/index.html +12 -0
  71. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/package.json +28 -0
  72. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/postcss.config.js +5 -0
  73. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/App.vue +25 -0
  74. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/ConsultationManagePanel.vue +838 -0
  75. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/LanguageSwitch.vue +102 -0
  76. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/LoadingSpinner.vue +6 -0
  77. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalAlert.vue +34 -0
  78. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalBusinessPanel.vue +148 -0
  79. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalButton.vue +49 -0
  80. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalConfirmDialog.vue +68 -0
  81. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalDataPanel.vue +196 -0
  82. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalRecordPanel.vue +270 -0
  83. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/PrescriptionPanel.vue +363 -0
  84. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/basic-info-config.ts +29 -0
  85. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/lib-generate-test-usersig-es.min.d.ts +4 -0
  86. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/lib-generate-test-usersig-es.min.js +2 -0
  87. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/runtime-config.ts +12 -0
  88. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/env.d.ts +32 -0
  89. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationChatPanel.vue +123 -0
  90. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationMembersPanel.vue +230 -0
  91. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationTranscriptionPanel.vue +135 -0
  92. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationVideoStage.vue +113 -0
  93. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/InviteDoctorDialog.vue +132 -0
  94. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/KickMemberConfirmDialog.vue +50 -0
  95. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/types.ts +77 -0
  96. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationChat.ts +97 -0
  97. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationDevices.ts +48 -0
  98. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationParticipants.ts +121 -0
  99. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationPermissions.ts +25 -0
  100. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/utils.ts +70 -0
  101. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/en-US/index.ts +553 -0
  102. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/index.ts +25 -0
  103. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/medicalTranslate.ts +85 -0
  104. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/state.ts +49 -0
  105. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/zh-CN/index.ts +463 -0
  106. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/main.ts +12 -0
  107. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/mock/appointments.ts +96 -0
  108. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/mock/users.ts +79 -0
  109. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/router/index.ts +63 -0
  110. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/index.ts +25 -0
  111. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/appointmentService.ts +77 -0
  112. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/authService.ts +38 -0
  113. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/launchContext.ts +31 -0
  114. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/userService.ts +35 -0
  115. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/mock/appointmentService.ts +43 -0
  116. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/mock/authService.ts +33 -0
  117. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/mock/userService.ts +43 -0
  118. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/types.ts +135 -0
  119. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/shared/icons.ts +53 -0
  120. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/styles/index.css +106 -0
  121. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/styles/tailwind.css +3 -0
  122. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/styles/theme.css +209 -0
  123. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/auth.ts +50 -0
  124. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/format.ts +24 -0
  125. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/navigation.ts +12 -0
  126. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/session.ts +28 -0
  127. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/DoctorConsultationView.vue +777 -0
  128. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/DoctorDashboardView.vue +678 -0
  129. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/LoginView.vue +441 -0
  130. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientConsultationFinishedView.vue +185 -0
  131. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientConsultationView.vue +1003 -0
  132. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientSelectDoctorView.vue +317 -0
  133. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientWaitingView.vue +454 -0
  134. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/tsconfig.json +21 -0
  135. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/tsconfig.node.json +8 -0
  136. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/vite.config.ts +17 -0
  137. package/skills/trtc/room-builder/templates/scenarios/medical-consultation//346/216/245/345/205/245/350/257/264/346/230/216.md +6 -0
  138. package/skills/trtc/room-builder/tools/render_ai_instructions.py +226 -0
  139. package/skills/trtc-apply/SKILL.md +97 -0
  140. package/skills/trtc-apply/guardrails/apply_lib/__init__.py +0 -0
  141. package/skills/trtc-apply/guardrails/apply_lib/__pycache__/__init__.cpython-313.pyc +0 -0
  142. package/skills/trtc-apply/guardrails/apply_lib/__pycache__/rule_parser.cpython-313.pyc +0 -0
  143. package/skills/trtc-apply/guardrails/apply_lib/rule_parser.py +268 -0
  144. package/skills/trtc-docs/SKILL.md +207 -0
  145. package/skills/trtc-onboarding/SKILL.md +839 -0
  146. package/skills/trtc-onboarding/reference/path-a1-demo.md +103 -0
  147. package/skills/trtc-onboarding/reference/path-a2-integrate.md +693 -0
  148. package/skills/trtc-onboarding/reference/path-b-troubleshoot.md +115 -0
  149. package/skills/trtc-onboarding/reference/path-c-expand.md +43 -0
  150. package/skills/trtc-onboarding/reference/reporting-protocol.md +174 -0
  151. package/skills/trtc-onboarding/reference/supported-matrix.md +100 -0
  152. package/skills/trtc-onboarding/reference/usersig-handling.md +140 -0
  153. package/skills/trtc-search/SKILL.md +221 -0
  154. package/skills/trtc-topic/SKILL.md +638 -0
  155. package/skills/trtc-topic/guardrails/__pycache__/gate_slice_read.cpython-313.pyc +0 -0
  156. package/skills/trtc-topic/guardrails/__pycache__/gate_slice_write.cpython-313.pyc +0 -0
  157. package/skills/trtc-topic/guardrails/__pycache__/stop_require_apply_evidence.cpython-313.pyc +0 -0
  158. package/skills/trtc-topic/guardrails/gate_slice_read.py +133 -0
  159. package/skills/trtc-topic/guardrails/gate_slice_write.py +169 -0
  160. package/skills/trtc-topic/guardrails/stop_require_apply_evidence.py +97 -0
  161. package/skills/trtc-topic/references/execution-units.yaml +58 -0
  162. package/skills/trtc-topic/runtime/README.md +50 -0
  163. package/skills/trtc-topic/runtime/RUNTIME.md +128 -0
  164. package/skills/trtc-topic/runtime/lib/__init__.py +0 -0
  165. package/skills/trtc-topic/runtime/lib/platforms.py +194 -0
  166. package/skills/trtc-topic/runtime/package-lock.json +1211 -0
  167. package/skills/trtc-topic/runtime/package.json +13 -0
  168. package/skills/trtc-topic/runtime/telemetry-bridge.mjs +339 -0
  169. package/skills/trtc-topic/runtime/telemetry_collector.py +293 -0
  170. package/skills/trtc-topic/scripts/STATE-MACHINE-GUIDE.md +186 -0
  171. package/skills/trtc-topic/scripts/__pycache__/apply.cpython-313.pyc +0 -0
  172. package/skills/trtc-topic/scripts/apply.py +581 -0
  173. package/skills/trtc-topic/scripts/finalize_session.py +113 -0
  174. package/skills/trtc-topic/scripts/init_slice_queue.py +96 -0
  175. package/skills/trtc-topic/scripts/lib/__pycache__/state_machine.cpython-313.pyc +0 -0
  176. package/skills/trtc-topic/scripts/lib/state_machine.py +328 -0
  177. package/skills/trtc-topic/scripts/next_slice.py +137 -0
  178. package/skills/trtc-topic/tests/README.md +70 -0
  179. package/skills/trtc-topic/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  180. package/skills/trtc-topic/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  181. package/skills/trtc-topic/tests/__pycache__/test_apply_cli.cpython-313-pytest-9.0.2.pyc +0 -0
  182. package/skills/trtc-topic/tests/__pycache__/test_apply_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  183. package/skills/trtc-topic/tests/__pycache__/test_end_to_end.cpython-313-pytest-9.0.2.pyc +0 -0
  184. package/skills/trtc-topic/tests/__pycache__/test_end_to_end.cpython-313-pytest-9.0.3.pyc +0 -0
  185. package/skills/trtc-topic/tests/__pycache__/test_finalize_session.cpython-313-pytest-9.0.2.pyc +0 -0
  186. package/skills/trtc-topic/tests/__pycache__/test_finalize_session.cpython-313-pytest-9.0.3.pyc +0 -0
  187. package/skills/trtc-topic/tests/__pycache__/test_gates.cpython-313-pytest-9.0.2.pyc +0 -0
  188. package/skills/trtc-topic/tests/__pycache__/test_gates.cpython-313-pytest-9.0.3.pyc +0 -0
  189. package/skills/trtc-topic/tests/__pycache__/test_session_resolver.cpython-313-pytest-9.0.2.pyc +0 -0
  190. package/skills/trtc-topic/tests/__pycache__/test_session_resolver.cpython-313-pytest-9.0.3.pyc +0 -0
  191. package/skills/trtc-topic/tests/__pycache__/test_state_machine.cpython-313-pytest-9.0.2.pyc +0 -0
  192. package/skills/trtc-topic/tests/__pycache__/test_state_machine.cpython-313-pytest-9.0.3.pyc +0 -0
  193. package/skills/trtc-topic/tests/__pycache__/test_stop_require_apply.cpython-313-pytest-9.0.2.pyc +0 -0
  194. package/skills/trtc-topic/tests/__pycache__/test_stop_require_apply.cpython-313-pytest-9.0.3.pyc +0 -0
  195. package/skills/trtc-topic/tests/__pycache__/test_topic_skill_invariants.cpython-313-pytest-9.0.2.pyc +0 -0
  196. package/skills/trtc-topic/tests/__pycache__/test_topic_skill_invariants.cpython-313-pytest-9.0.3.pyc +0 -0
  197. package/skills/trtc-topic/tests/conftest.py +72 -0
  198. package/skills/trtc-topic/tests/test_apply_cli.py +480 -0
  199. package/skills/trtc-topic/tests/test_end_to_end.py +305 -0
  200. package/skills/trtc-topic/tests/test_finalize_session.py +51 -0
  201. package/skills/trtc-topic/tests/test_gates.py +316 -0
  202. package/skills/trtc-topic/tests/test_session_resolver.py +260 -0
  203. package/skills/trtc-topic/tests/test_state_machine.py +414 -0
  204. package/skills/trtc-topic/tests/test_stop_require_apply.py +99 -0
  205. package/skills/trtc-topic/tests/test_topic_skill_invariants.py +130 -0
package/bin/cli.js ADDED
@@ -0,0 +1,434 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ /**
6
+ * @tencent-rtc/trtc-agent-skills installer
7
+ *
8
+ * Installs the TRTC AI Integration skill suite (6 cross-referencing skills:
9
+ * trtc + trtc-onboarding/docs/topic/search/apply) plus the shared
10
+ * knowledge-base into your IDE's skills directory, and wires up the
11
+ * `tencent-rtc-skill-tool` MCP server (used for prompt / runtime telemetry).
12
+ *
13
+ * IMPORTANT — why skills are copied as SIBLING DIRECTORIES:
14
+ * The entry skill `trtc/SKILL.md` routes to the others via relative paths
15
+ * like `../trtc-onboarding/SKILL.md`. They MUST remain siblings under the
16
+ * same skills root, otherwise routing breaks. We therefore copy each
17
+ * skills/<name>/ dir verbatim — we never concatenate them.
18
+ *
19
+ * Usage:
20
+ * npx @tencent-rtc/trtc-agent-skills add
21
+ * npx @tencent-rtc/trtc-agent-skills add --ide cursor
22
+ * npx @tencent-rtc/trtc-agent-skills add --ide all
23
+ * npx @tencent-rtc/trtc-agent-skills add --clean
24
+ * npx @tencent-rtc/trtc-agent-skills add --no-report
25
+ * npx @tencent-rtc/trtc-agent-skills add --list
26
+ * npx @tencent-rtc/trtc-agent-skills add --help
27
+ */
28
+
29
+ const fs = require("fs");
30
+ const os = require("os");
31
+ const path = require("path");
32
+
33
+ // ── tiny color helpers (no deps) ───────────────────────────────────────────────
34
+ const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
35
+ const c = {
36
+ bold: (s) => (useColor ? `\x1b[1m${s}\x1b[0m` : s),
37
+ cyan: (s) => (useColor ? `\x1b[36m${s}\x1b[0m` : s),
38
+ green: (s) => (useColor ? `\x1b[32m${s}\x1b[0m` : s),
39
+ yellow: (s) => (useColor ? `\x1b[33m${s}\x1b[0m` : s),
40
+ red: (s) => (useColor ? `\x1b[31m${s}\x1b[0m` : s),
41
+ gray: (s) => (useColor ? `\x1b[90m${s}\x1b[0m` : s),
42
+ dim: (s) => (useColor ? `\x1b[2m${s}\x1b[0m` : s),
43
+ };
44
+
45
+ // ── paths ───────────────────────────────────────────────────────────────────────
46
+ const PKG_ROOT = path.resolve(__dirname, "..");
47
+ const PKG_JSON = require(path.join(PKG_ROOT, "package.json"));
48
+ const PKG_VERSION = PKG_JSON.version || "0.0.0";
49
+ const SKILLS_SRC = path.join(PKG_ROOT, "skills");
50
+ const KB_SRC = path.join(PKG_ROOT, "knowledge-base");
51
+
52
+ // The 6 skills that make up the suite. Order is cosmetic; `trtc` is the entry.
53
+ const SKILL_NAMES = [
54
+ "trtc",
55
+ "trtc-onboarding",
56
+ "trtc-docs",
57
+ "trtc-topic",
58
+ "trtc-search",
59
+ "trtc-apply",
60
+ ];
61
+
62
+ // IDE skill-install targets (project-level). Each IDE reads skills from a
63
+ // different directory, but the layout inside is identical: one dir per skill.
64
+ const IDE_TARGETS = {
65
+ claude: { skillsRoot: ".claude/skills", kind: "dir" },
66
+ cursor: { skillsRoot: ".cursor/skills", kind: "dir" },
67
+ codebuddy: { skillsRoot: ".codebuddy/skills", kind: "dir" },
68
+ // Codex reads project-root .agents/skills/. Same dir-per-skill layout works.
69
+ codex: { skillsRoot: ".agents/skills", kind: "dir" },
70
+ };
71
+
72
+ // MCP config locations per IDE.
73
+ // claude: project-level <root>/.mcp.json (JSON)
74
+ // cursor: user-level ~/.cursor/mcp.json (JSON)
75
+ // codebuddy: user-level ~/.codebuddy/mcp.json (JSON)
76
+ // codex: user-level ~/.codex/config.toml (TOML, [mcp_servers.xxx])
77
+ const MCP_TARGETS = {
78
+ claude: { configFile: ".mcp.json", format: "json" },
79
+ cursor: { configFile: path.join(os.homedir(), ".cursor", "mcp.json"), format: "json" },
80
+ codebuddy: { configFile: path.join(os.homedir(), ".codebuddy", "mcp.json"), format: "json" },
81
+ codex: { configFile: path.join(os.homedir(), ".codex", "config.toml"), format: "toml" },
82
+ };
83
+
84
+ const MCP_SERVER_NAME = "tencent-rtc-skill-tool";
85
+ const MCP_SERVER_ENTRY = "@tencent-rtc/skill-tool@latest";
86
+
87
+ // Knowledge-base lives next to the skills root (sibling), because skills
88
+ // reference it via ${CLAUDE_PLUGIN_ROOT}/knowledge-base — we mirror that by
89
+ // placing knowledge-base/ as a sibling of the skills dir's parent. To keep it
90
+ // simple and robust across IDEs, we copy KB into <skillsRoot>/../knowledge-base
91
+ // AND keep a project-root copy. See copyKnowledgeBase().
92
+
93
+ // ── fs helpers ──────────────────────────────────────────────────────────────────
94
+ function ensureDir(dir) {
95
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
96
+ }
97
+
98
+ function copyRecursive(src, dest) {
99
+ const stat = fs.statSync(src);
100
+ if (stat.isDirectory()) {
101
+ ensureDir(dest);
102
+ for (const entry of fs.readdirSync(src)) {
103
+ copyRecursive(path.join(src, entry), path.join(dest, entry));
104
+ }
105
+ } else {
106
+ ensureDir(path.dirname(dest));
107
+ fs.copyFileSync(src, dest);
108
+ }
109
+ }
110
+
111
+ function rmrf(target) {
112
+ if (fs.existsSync(target) || isSymlink(target)) {
113
+ fs.rmSync(target, { recursive: true, force: true });
114
+ }
115
+ }
116
+
117
+ function isSymlink(p) {
118
+ try { return fs.lstatSync(p).isSymbolicLink(); }
119
+ catch { return false; }
120
+ }
121
+
122
+ // ── project root resolution ───────────────────────────────────────────────────
123
+ // Walk UP from cwd for strong repo-root signals (P1 monorepo manifest,
124
+ // P2 package.json workspaces, P3 .git). Otherwise P4 cwd-local package.json,
125
+ // else P5 cwd. Same semantics as the reference installer.
126
+ function findProjectRoot(startCwd) {
127
+ const start = path.resolve(startCwd);
128
+ let dir = start;
129
+ while (true) {
130
+ if (
131
+ fs.existsSync(path.join(dir, "pnpm-workspace.yaml")) ||
132
+ fs.existsSync(path.join(dir, "lerna.json")) ||
133
+ fs.existsSync(path.join(dir, "turbo.json"))
134
+ ) return dir;
135
+
136
+ const pkgPath = path.join(dir, "package.json");
137
+ if (fs.existsSync(pkgPath)) {
138
+ try {
139
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
140
+ if (pkg && pkg.workspaces) return dir;
141
+ } catch { /* malformed — keep walking */ }
142
+ }
143
+
144
+ if (fs.existsSync(path.join(dir, ".git"))) return dir;
145
+
146
+ const parent = path.dirname(dir);
147
+ if (parent === dir) break;
148
+ dir = parent;
149
+ }
150
+ if (fs.existsSync(path.join(start, "package.json"))) return start;
151
+ return start;
152
+ }
153
+
154
+ // ── argv parsing ──────────────────────────────────────────────────────────────
155
+ function getFlag(args, name) {
156
+ const i = args.indexOf(name);
157
+ return i !== -1 ? args[i + 1] : undefined;
158
+ }
159
+
160
+ // ── help / list ───────────────────────────────────────────────────────────────
161
+ function printHelp() {
162
+ console.log(`
163
+ ${c.bold("@tencent-rtc/trtc-agent-skills")} — Install TRTC AI Integration skills + MCP
164
+
165
+ ${c.bold("Usage:")}
166
+ ${c.cyan("npx @tencent-rtc/trtc-agent-skills add")} Install (default IDE: claude)
167
+ ${c.cyan("npx @tencent-rtc/trtc-agent-skills add --ide <name>")} One of: claude / cursor / codebuddy / codex / all
168
+ ${c.cyan("npx @tencent-rtc/trtc-agent-skills add --clean")} Wipe existing trtc* skill dirs first
169
+ ${c.cyan("npx @tencent-rtc/trtc-agent-skills add --no-report")} Skip anonymous install reporting
170
+ ${c.cyan("npx @tencent-rtc/trtc-agent-skills add --list")} List skills shipped in this package
171
+ ${c.cyan("npx @tencent-rtc/trtc-agent-skills add --help")} Show this help
172
+
173
+ ${c.bold("Installs:")}
174
+ ${c.dim("Skills :")} ${c.gray("<projectRoot>/.claude/skills/ (or .cursor/, .codebuddy/, .agents/)")}
175
+ ${c.dim("KB :")} ${c.gray("alongside the skills root as knowledge-base/")}
176
+ ${c.dim("MCP :")} ${c.gray("tencent-rtc-skill-tool → IDE mcp config (npx @tencent-rtc/skill-tool@latest)")}
177
+
178
+ ${c.dim("Skills are copied as sibling dirs so relative routing (../trtc-onboarding) keeps working.")}
179
+ `);
180
+ }
181
+
182
+ function listSkills() {
183
+ console.log(`\n ${c.bold("Skills shipped in this package:")}\n`);
184
+ console.log(` ${c.cyan("trtc/")} ${c.dim("Entry router — detects product/platform, routes to sub-skills")}`);
185
+ console.log(` ${c.cyan("trtc-onboarding/")} ${c.dim("Get-started / integration / troubleshooting flow")}`);
186
+ console.log(` ${c.cyan("trtc-docs/")} ${c.dim("Docs & error-code lookup")}`);
187
+ console.log(` ${c.cyan("trtc-topic/")} ${c.dim("Step-by-step scenario walkthrough")}`);
188
+ console.log(` ${c.cyan("trtc-search/")} ${c.dim("Internal slice lookup (AI-facing)")}`);
189
+ console.log(` ${c.cyan("trtc-apply/")} ${c.dim("Internal compile/integration quality gate")}`);
190
+ console.log("");
191
+ }
192
+
193
+ // ── core: skill install ─────────────────────────────────────────────────────────
194
+ function cleanSkills(skillsRootAbs) {
195
+ if (!fs.existsSync(skillsRootAbs)) return 0;
196
+ let wiped = 0;
197
+ for (const name of SKILL_NAMES) {
198
+ const target = path.join(skillsRootAbs, name);
199
+ if (fs.existsSync(target)) { rmrf(target); wiped++; }
200
+ }
201
+ // also wipe a co-located knowledge-base copy if present
202
+ const kb = path.join(path.dirname(skillsRootAbs), "knowledge-base");
203
+ if (fs.existsSync(kb)) { rmrf(kb); }
204
+ return wiped;
205
+ }
206
+
207
+ function installSkills(skillsRootAbs) {
208
+ ensureDir(skillsRootAbs);
209
+ for (const name of SKILL_NAMES) {
210
+ const src = path.join(SKILLS_SRC, name);
211
+ if (fs.existsSync(src)) {
212
+ copyRecursive(src, path.join(skillsRootAbs, name));
213
+ }
214
+ }
215
+ }
216
+
217
+ // Copy knowledge-base so that skills can resolve it. Skills use
218
+ // ${CLAUDE_PLUGIN_ROOT}/knowledge-base; the practical robust choice is to put
219
+ // knowledge-base as a sibling of the skills root (e.g. .claude/knowledge-base),
220
+ // which is what plugin-style roots expect.
221
+ function copyKnowledgeBase(skillsRootAbs) {
222
+ const dest = path.join(path.dirname(skillsRootAbs), "knowledge-base");
223
+ rmrf(dest);
224
+ copyRecursive(KB_SRC, dest);
225
+ return dest;
226
+ }
227
+
228
+ // ── MCP installation ──────────────────────────────────────────────────────────
229
+ function installMcp(ideList, resolvedRoot) {
230
+ const serverEntry = {
231
+ type: "stdio",
232
+ command: "npx",
233
+ args: ["-y", MCP_SERVER_ENTRY],
234
+ };
235
+
236
+ for (const ide of ideList) {
237
+ const mcpTarget = MCP_TARGETS[ide];
238
+ if (!mcpTarget) continue;
239
+
240
+ const configPath = path.isAbsolute(mcpTarget.configFile)
241
+ ? mcpTarget.configFile
242
+ : path.join(resolvedRoot, mcpTarget.configFile);
243
+ ensureDir(path.dirname(configPath));
244
+
245
+ if (mcpTarget.format === "toml") {
246
+ installMcpToml(configPath, serverEntry);
247
+ } else {
248
+ let config = {};
249
+ if (fs.existsSync(configPath)) {
250
+ try { config = JSON.parse(fs.readFileSync(configPath, "utf8")); }
251
+ catch { config = {}; }
252
+ }
253
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
254
+ config.mcpServers = {};
255
+ }
256
+ config.mcpServers[MCP_SERVER_NAME] = serverEntry;
257
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
258
+ }
259
+ console.log(c.green(" ✓ ") + `${ide} MCP → ${configPath}`);
260
+ }
261
+ }
262
+
263
+ function installMcpToml(configPath, serverEntry) {
264
+ let content = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : "";
265
+
266
+ const sectionHeader = `[mcp_servers.${MCP_SERVER_NAME}]`;
267
+ const argsValue = JSON.stringify(serverEntry.args).replace(/,/g, ", ");
268
+ const newSection = [
269
+ sectionHeader,
270
+ `command = "${serverEntry.command}"`,
271
+ `args = ${argsValue}`,
272
+ ].join("\n") + "\n";
273
+
274
+ const escapedName = MCP_SERVER_NAME.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
275
+ const sectionRegex = new RegExp(
276
+ `\\[mcp_servers\\.${escapedName}\\]\\n(?:(?!\\[)[^\\n]*\\n)*`,
277
+ "g"
278
+ );
279
+ content = content.replace(sectionRegex, "");
280
+ content = content.trimEnd() + (content.trim() ? "\n\n" : "") + newSection;
281
+ fs.writeFileSync(configPath, content, "utf8");
282
+ }
283
+
284
+ // ── Claude Code permissions (pre-approve MCP tool) ──────────────────────────────
285
+ function installClaudePermissions(ideList, resolvedRoot) {
286
+ if (!ideList.includes("claude")) return;
287
+
288
+ const settingsDir = path.join(resolvedRoot, ".claude");
289
+ const settingsPath = path.join(settingsDir, "settings.json");
290
+ ensureDir(settingsDir);
291
+
292
+ let settings = {};
293
+ if (fs.existsSync(settingsPath)) {
294
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, "utf8")); }
295
+ catch { settings = {}; }
296
+ }
297
+ if (!settings.permissions || typeof settings.permissions !== "object") settings.permissions = {};
298
+ if (!Array.isArray(settings.permissions.allow)) settings.permissions.allow = [];
299
+
300
+ const rules = [`mcp__${MCP_SERVER_NAME}__*`];
301
+ const added = rules.filter(r => !settings.permissions.allow.includes(r));
302
+ if (added.length > 0) {
303
+ settings.permissions.allow.push(...added);
304
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
305
+ console.log(c.green(" ✓ ") + `claude permissions → ${settingsPath}`);
306
+ } else {
307
+ console.log(c.dim(` ✓ claude permissions already set, skipped`));
308
+ }
309
+ }
310
+
311
+ // ── Cursor permissions (allowlist MCP tool) ─────────────────────────────────────
312
+ function installCursorPermissions(ideList, resolvedRoot) {
313
+ if (!ideList.includes("cursor")) return;
314
+
315
+ const permDir = path.join(resolvedRoot, ".cursor");
316
+ const permPath = path.join(permDir, "permissions.json");
317
+ ensureDir(permDir);
318
+
319
+ let perms = {};
320
+ if (fs.existsSync(permPath)) {
321
+ try { perms = JSON.parse(fs.readFileSync(permPath, "utf8")); }
322
+ catch { perms = {}; }
323
+ }
324
+ if (!Array.isArray(perms.mcpAllowlist)) perms.mcpAllowlist = [];
325
+
326
+ const rule = `${MCP_SERVER_NAME}:skill_analysis`;
327
+ if (!perms.mcpAllowlist.includes(rule)) {
328
+ perms.mcpAllowlist.push(rule);
329
+ fs.writeFileSync(permPath, JSON.stringify(perms, null, 2) + "\n", "utf8");
330
+ console.log(c.green(" ✓ ") + `cursor permissions → ${permPath}`);
331
+ } else {
332
+ console.log(c.dim(` ✓ cursor permissions already set, skipped`));
333
+ }
334
+ }
335
+
336
+ // ── install reporting (fire-and-forget) ─────────────────────────────────────────
337
+ // Spawns the MCP server with --report. All reporting details (endpoint, etc.)
338
+ // live inside the MCP server; install.js only passes context fields.
339
+ function reportInstall({ ide }) {
340
+ const payload = JSON.stringify({
341
+ method: 2, // 2 = trtc-agent-skills install (1=chat-web-skill, 2=trtc-agent-skills)
342
+ version: PKG_VERSION,
343
+ framework: "all",
344
+ ide,
345
+ os: os.platform(),
346
+ });
347
+
348
+ try {
349
+ const { spawn } = require("child_process");
350
+ const child = spawn("npx", ["-y", MCP_SERVER_ENTRY, "--report", payload], {
351
+ detached: true,
352
+ stdio: "ignore",
353
+ });
354
+ child.unref();
355
+ } catch {
356
+ // never block install on reporting failure
357
+ }
358
+ }
359
+
360
+ // ── main ──────────────────────────────────────────────────────────────────────
361
+ function main() {
362
+ const args = process.argv.slice(2);
363
+ const cmd = args[0];
364
+
365
+ if (!cmd || cmd === "--help" || cmd === "-h") { printHelp(); process.exit(0); }
366
+ if (cmd === "--list" || cmd === "-l") { listSkills(); process.exit(0); }
367
+ if (cmd !== "add") {
368
+ console.error(c.red(`\n Unknown command: ${cmd}`));
369
+ printHelp();
370
+ process.exit(1);
371
+ }
372
+ if (args.includes("--list")) { listSkills(); process.exit(0); }
373
+
374
+ const isClean = args.includes("--clean");
375
+ const noReport = args.includes("--no-report");
376
+ const ideArg = getFlag(args, "--ide") || "claude";
377
+
378
+ const ideList = ideArg === "all" ? Object.keys(IDE_TARGETS) : [ideArg];
379
+ for (const ide of ideList) {
380
+ if (!IDE_TARGETS[ide]) {
381
+ console.error(c.red(`\n ✗ Unknown IDE: ${ide}. Valid: ${Object.keys(IDE_TARGETS).join(", ")}, all\n`));
382
+ process.exit(1);
383
+ }
384
+ }
385
+
386
+ const cwd = process.cwd();
387
+ let resolvedRoot = findProjectRoot(cwd);
388
+ // Guard: don't install into the package's own tree during local dev.
389
+ if (resolvedRoot === PKG_ROOT) resolvedRoot = cwd;
390
+
391
+ console.log(`\n ${c.bold(c.cyan("@tencent-rtc/trtc-agent-skills"))} ${c.dim("v" + PKG_VERSION)}`);
392
+ console.log(` ${c.gray("cwd : " + cwd)}`);
393
+ console.log(` ${c.gray("projectRoot : " + resolvedRoot)}`);
394
+ console.log(` ${c.gray("IDE(s) : " + ideList.join(", "))}`);
395
+ console.log("");
396
+
397
+ // 1. Install skill dirs (+ co-located knowledge-base) for each IDE.
398
+ for (const ide of ideList) {
399
+ const target = IDE_TARGETS[ide];
400
+ const skillsRootAbs = path.join(resolvedRoot, target.skillsRoot);
401
+ console.log(` ${c.bold(ide)} ${c.gray("→ " + skillsRootAbs + "/")}`);
402
+
403
+ if (isClean) {
404
+ const wiped = cleanSkills(skillsRootAbs);
405
+ if (wiped > 0) console.log(c.dim(` ✓ cleaned ${wiped} existing skill ${wiped === 1 ? "entry" : "entries"}`));
406
+ }
407
+
408
+ installSkills(skillsRootAbs);
409
+ for (const name of SKILL_NAMES) console.log(c.green(" ✓ ") + name + "/");
410
+
411
+ const kbDest = copyKnowledgeBase(skillsRootAbs);
412
+ console.log(c.green(" ✓ ") + "knowledge-base/ " + c.dim("→ " + kbDest));
413
+ }
414
+
415
+ // 2. Install MCP server config + permissions.
416
+ console.log(`\n ${c.bold("MCP")}`);
417
+ installMcp(ideList, resolvedRoot);
418
+ installClaudePermissions(ideList, resolvedRoot);
419
+ installCursorPermissions(ideList, resolvedRoot);
420
+
421
+ // 3. Anonymous install reporting (fire-and-forget; opt out via --no-report).
422
+ if (!noReport) reportInstall({ ide: ideArg });
423
+
424
+ // 4. Done.
425
+ console.log(`\n ${c.bold("Done.")} ${c.dim("Just describe what you want to build in your IDE — the skill activates automatically.")}\n`);
426
+ }
427
+
428
+ try {
429
+ main();
430
+ } catch (err) {
431
+ console.error(c.red(`\n Error: ${err.message || err}\n`));
432
+ if (err.stack && process.env.DEBUG) console.error(c.dim(err.stack) + "\n");
433
+ process.exit(1);
434
+ }