@colin4k1024/tsp 2.4.5 → 2.4.6

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 (236) hide show
  1. package/README.md +16 -20
  2. package/bin/lib/install-surface.js +3 -3
  3. package/bin/lib/source-installer.js +2 -2
  4. package/commands/team-help.md +2 -2
  5. package/commands/team-plan.md +1 -1
  6. package/commands/update-codemaps.md +3 -3
  7. package/manifests/install-components.json +1 -1
  8. package/manifests/install-modules.json +17 -3
  9. package/manifests/install-profiles.json +2 -0
  10. package/package.json +6 -3
  11. package/schemas/ecc-install-config.schema.json +6 -1
  12. package/schemas/install-modules.schema.json +4 -1
  13. package/scripts/codegraph-preflight.js +179 -0
  14. package/scripts/gitnexus-preflight.js +8 -0
  15. package/scripts/install-apply.js +10 -8
  16. package/scripts/install-codegraph.js +158 -0
  17. package/scripts/install-plan.js +28 -11
  18. package/scripts/lib/install/apply.js +256 -5
  19. package/scripts/lib/install/request.js +3 -2
  20. package/scripts/lib/install-audit-manifest.js +3 -0
  21. package/scripts/lib/install-executor.js +14 -5
  22. package/scripts/lib/install-lifecycle.js +2 -2
  23. package/scripts/lib/install-manifests.js +23 -4
  24. package/scripts/lib/install-targets/codex-home.js +187 -1
  25. package/scripts/lib/install-targets/opencode-home.js +135 -2
  26. package/scripts/lib/install-targets/registry.js +23 -1
  27. package/scripts/lib/release-health.js +19 -4
  28. package/scripts/lib/team-skills-data.json +6 -6
  29. package/scripts/release-health-summary.js +1 -1
  30. package/scripts/workflow-help.js +3 -3
  31. package/skills/codegraph/SKILL.md +57 -0
  32. package/skills/codegraph/agents/openai.yaml +4 -0
  33. package/docs/.vitepress/config.mts +0 -199
  34. package/docs/adr/ADR-001-doc-architecture-integration.md +0 -33
  35. package/docs/guides/README.md +0 -5
  36. package/docs/guides/installation.md +0 -33
  37. package/docs/guides/user-guide.md +0 -36
  38. package/docs/index.md +0 -65
  39. package/docs/memory/backlog.md +0 -10
  40. package/docs/memory/decisions.md +0 -43
  41. package/docs/memory/lessons-learned.md +0 -87
  42. package/docs/plans/2026-04-03-python-remnants-audit.md +0 -265
  43. package/docs/plans/2026-04-03-scripts-python-to-js-migration.md +0 -372
  44. package/docs/plans/2026-04-03-solo-delivery-execution-checklist.md +0 -413
  45. package/docs/plans/2026-04-03-solo-delivery-gap-plan.md +0 -377
  46. package/docs/plans/2026-04-03-team-skills-workflow-gates.md +0 -548
  47. package/docs/plans/2026-04-21-open-source-readiness-gap-plan.md +0 -217
  48. package/docs/plans/llm-surface-reduction-audit.md +0 -147
  49. package/docs/plans/llm-surface-reduction-execution-checklist.md +0 -217
  50. package/docs/plans/llm-surface-reduction-execution-history.md +0 -124
  51. package/docs/plans/team-skills-platform-migration.md +0 -54
  52. package/docs/presentation/README.md +0 -42
  53. package/docs/presentation/audience-presentation-route-map.md +0 -84
  54. package/docs/presentation/executive-briefing-talk-track.md +0 -50
  55. package/docs/presentation/generate_capability_matrix.py +0 -396
  56. package/docs/presentation/generate_ppt.py +0 -354
  57. package/docs/presentation/implementation-onboarding-brief.md +0 -38
  58. package/docs/presentation/presentation-talk-track.md +0 -97
  59. package/docs/presentation/vertical-scenario-route-map.md +0 -99
  60. package/docs/presentation/workshop-facilitator-guide.md +0 -47
  61. package/docs/runbooks/actionlint-workflow-gates.md +0 -80
  62. package/docs/runbooks/agent-governance.md +0 -131
  63. package/docs/runbooks/ai-eval-platform-demo-execution-log.md +0 -147
  64. package/docs/runbooks/ai-eval-platform-demo-script.md +0 -136
  65. package/docs/runbooks/ai-eval-platform-walkthrough.md +0 -113
  66. package/docs/runbooks/ai-pr-review-automation.md +0 -56
  67. package/docs/runbooks/api-breaking-change-gates.md +0 -58
  68. package/docs/runbooks/api-design-evolution-walkthrough.md +0 -42
  69. package/docs/runbooks/api-lint-gates.md +0 -57
  70. package/docs/runbooks/api-mocking-strategy-and-lifecycle-guide.md +0 -47
  71. package/docs/runbooks/architect-daily-operations.md +0 -63
  72. package/docs/runbooks/architect-design-conversation-example.md +0 -83
  73. package/docs/runbooks/artifact-attestation-gates.md +0 -75
  74. package/docs/runbooks/artifact-persistence.md +0 -257
  75. package/docs/runbooks/backend-engineer-daily-operations.md +0 -63
  76. package/docs/runbooks/batch-optimization-completion-checklist.md +0 -104
  77. package/docs/runbooks/biz-service-designer-end-to-end-conversation-example.md +0 -5
  78. package/docs/runbooks/biz-service-designer-toolkit.md +0 -5
  79. package/docs/runbooks/bug-fix-complete-walkthrough.md +0 -60
  80. package/docs/runbooks/build-failure-recovery-walkthrough.md +0 -40
  81. package/docs/runbooks/canary-decision-matrix.md +0 -41
  82. package/docs/runbooks/canary-staging-release-walkthrough.md +0 -46
  83. package/docs/runbooks/checkov-iac-gates.md +0 -104
  84. package/docs/runbooks/claude-code-review-workflow.md +0 -72
  85. package/docs/runbooks/claude-conversation-prompt-recipes.md +0 -132
  86. package/docs/runbooks/claude-end-to-end-conversation-example.md +0 -198
  87. package/docs/runbooks/claude-feature-development-guide.md +0 -112
  88. package/docs/runbooks/claude-quick-start.md +0 -227
  89. package/docs/runbooks/claude-usage-scenarios.md +0 -176
  90. package/docs/runbooks/code-review-collaboration-walkthrough.md +0 -65
  91. package/docs/runbooks/codeql-pr-security-gates.md +0 -64
  92. package/docs/runbooks/codex-end-to-end-conversation-example.md +0 -166
  93. package/docs/runbooks/codex-multi-agent-orchestration.md +0 -65
  94. package/docs/runbooks/codex-parallel-prompt-recipes.md +0 -131
  95. package/docs/runbooks/codex-quick-start.md +0 -223
  96. package/docs/runbooks/codex-usage-scenarios.md +0 -168
  97. package/docs/runbooks/codex-workflow-essentials.md +0 -88
  98. package/docs/runbooks/command-and-capability-matrix.md +0 -162
  99. package/docs/runbooks/conftest-policy-gates.md +0 -84
  100. package/docs/runbooks/consumer-driven-contract-testing-with-mock-alignment.md +0 -45
  101. package/docs/runbooks/contract-testing-playbook.md +0 -78
  102. package/docs/runbooks/cosign-signing-gates.md +0 -71
  103. package/docs/runbooks/cross-role-issue-triage-walkthrough.md +0 -47
  104. package/docs/runbooks/cursor-quick-start.md +0 -123
  105. package/docs/runbooks/custom-overlay.md +0 -115
  106. package/docs/runbooks/data-ml-pipeline-demo-execution-log.md +0 -141
  107. package/docs/runbooks/data-ml-pipeline-demo-script.md +0 -102
  108. package/docs/runbooks/data-ml-pipeline-walkthrough.md +0 -119
  109. package/docs/runbooks/data-observability-quality-demo-execution-log.md +0 -36
  110. package/docs/runbooks/data-observability-quality-demo-script.md +0 -42
  111. package/docs/runbooks/data-observability-quality-walkthrough.md +0 -86
  112. package/docs/runbooks/demo-deliverables-overview.md +0 -278
  113. package/docs/runbooks/demo-execution-log.md +0 -530
  114. package/docs/runbooks/demo-scenario.md +0 -129
  115. package/docs/runbooks/dependency-review-gates.md +0 -63
  116. package/docs/runbooks/dependency-update-automation.md +0 -83
  117. package/docs/runbooks/design-md-workflow.md +0 -185
  118. package/docs/runbooks/devops-engineer-daily-operations.md +0 -60
  119. package/docs/runbooks/devops-release-conversation-example.md +0 -88
  120. package/docs/runbooks/doc-architecture-integration.md +0 -59
  121. package/docs/runbooks/doc-architecture-quick-start.md +0 -122
  122. package/docs/runbooks/document-execution-audit.md +0 -32
  123. package/docs/runbooks/documentation-update-walkthrough.md +0 -37
  124. package/docs/runbooks/ecc-harness-usage.md +0 -93
  125. package/docs/runbooks/error-experience-usage.md +0 -116
  126. package/docs/runbooks/evolution-usage.md +0 -162
  127. package/docs/runbooks/executive-value-one-page.md +0 -55
  128. package/docs/runbooks/external-capability-approval-and-enablement-workflow.md +0 -39
  129. package/docs/runbooks/external-capability-intake.md +0 -160
  130. package/docs/runbooks/first-team-command-60-seconds.md +0 -96
  131. package/docs/runbooks/first-team-workflow-walkthrough.md +0 -245
  132. package/docs/runbooks/frontend-backend-integration-acceptance-checklist.md +0 -46
  133. package/docs/runbooks/frontend-backend-parallel-integration-walkthrough.md +0 -48
  134. package/docs/runbooks/frontend-bugfix-one-page.md +0 -82
  135. package/docs/runbooks/frontend-engineer-daily-operations.md +0 -60
  136. package/docs/runbooks/frontend-enterprise-style-profile.md +0 -5
  137. package/docs/runbooks/frontend-governance.md +0 -47
  138. package/docs/runbooks/frontend-refactor-walkthrough.md +0 -42
  139. package/docs/runbooks/git-pr-workflow.md +0 -63
  140. package/docs/runbooks/github-actions-supply-chain-demo-execution-log.md +0 -158
  141. package/docs/runbooks/github-actions-supply-chain-demo-script.md +0 -150
  142. package/docs/runbooks/github-actions-supply-chain-walkthrough.md +0 -117
  143. package/docs/runbooks/github-token-permissions-baseline.md +0 -92
  144. package/docs/runbooks/gitlab-manual-pipeline-release.md +0 -5
  145. package/docs/runbooks/gitlab-release-integration-playbook.md +0 -5
  146. package/docs/runbooks/gitnexus-code-intelligence-usage.md +0 -133
  147. package/docs/runbooks/graphify-knowledge-graph-usage.md +0 -88
  148. package/docs/runbooks/handoff-filling-guide-with-examples.md +0 -70
  149. package/docs/runbooks/handoff-governance.md +0 -250
  150. package/docs/runbooks/helm-unittest-playbook.md +0 -101
  151. package/docs/runbooks/hotfix-emergency-release-walkthrough.md +0 -60
  152. package/docs/runbooks/iac-kubernetes-platform-demo-execution-log.md +0 -144
  153. package/docs/runbooks/iac-kubernetes-platform-demo-script.md +0 -130
  154. package/docs/runbooks/iac-kubernetes-platform-walkthrough.md +0 -120
  155. package/docs/runbooks/implementation-onboarding-reading-path.md +0 -67
  156. package/docs/runbooks/in-toto-attestation-framework.md +0 -94
  157. package/docs/runbooks/incident-severity-triage-tree.md +0 -43
  158. package/docs/runbooks/incident-triage-one-page.md +0 -65
  159. package/docs/runbooks/internal-developer-platform-demo-execution-log.md +0 -36
  160. package/docs/runbooks/internal-developer-platform-demo-script.md +0 -42
  161. package/docs/runbooks/internal-developer-platform-walkthrough.md +0 -91
  162. package/docs/runbooks/karpathy-guidelines-usage.md +0 -27
  163. package/docs/runbooks/kubeconform-schema-gates.md +0 -100
  164. package/docs/runbooks/kubectl-server-dry-run-gates.md +0 -103
  165. package/docs/runbooks/kyverno-policy-gates.md +0 -90
  166. package/docs/runbooks/langfuse-and-observability-integration-guide.md +0 -43
  167. package/docs/runbooks/langfuse-coding-trace.md +0 -44
  168. package/docs/runbooks/mobile-miniapp-delivery-walkthrough.md +0 -112
  169. package/docs/runbooks/mobile-miniapp-demo-execution-log.md +0 -139
  170. package/docs/runbooks/mobile-miniapp-demo-script.md +0 -129
  171. package/docs/runbooks/multi-service-backend-integration-walkthrough.md +0 -61
  172. package/docs/runbooks/open-design-integration.md +0 -163
  173. package/docs/runbooks/open-source-release-checklist.md +0 -90
  174. package/docs/runbooks/opencode-quick-start.md +0 -128
  175. package/docs/runbooks/parallel-development-coordination-walkthrough.md +0 -47
  176. package/docs/runbooks/parallel-execution-usage.md +0 -179
  177. package/docs/runbooks/platform-capability-demo-execution-log.md +0 -184
  178. package/docs/runbooks/platform-capability-demo-script.md +0 -192
  179. package/docs/runbooks/plugin-extension-platform-demo-execution-log.md +0 -136
  180. package/docs/runbooks/plugin-extension-platform-demo-script.md +0 -102
  181. package/docs/runbooks/plugin-extension-platform-walkthrough.md +0 -111
  182. package/docs/runbooks/policy-controller-gates.md +0 -75
  183. package/docs/runbooks/post-rollback-verification-checklist.md +0 -37
  184. package/docs/runbooks/pre-release-checklist.md +0 -50
  185. package/docs/runbooks/product-manager-clarification-conversation-example.md +0 -90
  186. package/docs/runbooks/product-manager-daily-operations.md +0 -60
  187. package/docs/runbooks/production-incident-response-walkthrough.md +0 -50
  188. package/docs/runbooks/project-claude-design-rationale.md +0 -188
  189. package/docs/runbooks/project-manager-daily-operations.md +0 -61
  190. package/docs/runbooks/project-manager-planning-conversation-example.md +0 -82
  191. package/docs/runbooks/project-onboarding.md +0 -452
  192. package/docs/runbooks/qa-engineer-daily-operations.md +0 -63
  193. package/docs/runbooks/qa-review-conversation-example.md +0 -87
  194. package/docs/runbooks/release-closure-one-page.md +0 -65
  195. package/docs/runbooks/release-governance-reading-path.md +0 -56
  196. package/docs/runbooks/release-notes-automation.md +0 -48
  197. package/docs/runbooks/release-rollback-recovery-walkthrough.md +0 -47
  198. package/docs/runbooks/requirement-clarity-and-scope-walkthrough.md +0 -46
  199. package/docs/runbooks/reviewdog-pr-gates.md +0 -49
  200. package/docs/runbooks/role-prompt-recipes.md +0 -130
  201. package/docs/runbooks/rtk-integration-intake.md +0 -45
  202. package/docs/runbooks/rtk-token-optimization-usage.md +0 -107
  203. package/docs/runbooks/runner-egress-hardening.md +0 -81
  204. package/docs/runbooks/runtime-capabilities-overview.md +0 -113
  205. package/docs/runbooks/sbom-generation-gates.md +0 -71
  206. package/docs/runbooks/scorecard-supply-chain-gates.md +0 -82
  207. package/docs/runbooks/secret-scanning-gates.md +0 -85
  208. package/docs/runbooks/security-compliance-platform-demo-execution-log.md +0 -36
  209. package/docs/runbooks/security-compliance-platform-demo-script.md +0 -49
  210. package/docs/runbooks/security-compliance-platform-walkthrough.md +0 -98
  211. package/docs/runbooks/slsa-generator-patterns.md +0 -73
  212. package/docs/runbooks/slsa-verification-gates.md +0 -75
  213. package/docs/runbooks/solo-delivery-mode.md +0 -142
  214. package/docs/runbooks/solo-delivery-one-page.md +0 -111
  215. package/docs/runbooks/specialist-commands-playbook.md +0 -85
  216. package/docs/runbooks/sub-agent-invocation-map.md +0 -144
  217. package/docs/runbooks/system-architecture-design-walkthrough.md +0 -49
  218. package/docs/runbooks/team-closeout-example.md +0 -73
  219. package/docs/runbooks/team-command-output-contracts.md +0 -358
  220. package/docs/runbooks/team-commands-quick-prompts.md +0 -125
  221. package/docs/runbooks/team-execute-example.md +0 -63
  222. package/docs/runbooks/team-handoff-example.md +0 -49
  223. package/docs/runbooks/team-intake-example.md +0 -70
  224. package/docs/runbooks/team-plan-example.md +0 -62
  225. package/docs/runbooks/team-release-example.md +0 -63
  226. package/docs/runbooks/team-review-example.md +0 -61
  227. package/docs/runbooks/team-skills-test-run.md +0 -184
  228. package/docs/runbooks/team-skills-usage.md +0 -336
  229. package/docs/runbooks/team-training-reading-path.md +0 -64
  230. package/docs/runbooks/tech-lead-closure-conversation-example.md +0 -78
  231. package/docs/runbooks/tech-lead-daily-operations.md +0 -67
  232. package/docs/runbooks/trivy-security-gates.md +0 -79
  233. package/docs/runbooks/troubleshooting.md +0 -234
  234. package/docs/runbooks/vertical-scenario-capability-matrix.md +0 -107
  235. package/docs/runbooks/witness-policy-gates.md +0 -78
  236. package/docs/runbooks/zizmor-workflow-audits.md +0 -81
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+
4
+ const path = require('path')
5
+ const { spawnSync } = require('child_process')
6
+
7
+ const SUPPORTED_TARGETS = Object.freeze({
8
+ claude: 'claude',
9
+ codex: 'codex',
10
+ cursor: 'cursor',
11
+ opencode: 'opencode',
12
+ })
13
+
14
+ function normalizeTarget(value) {
15
+ return String(value || '').trim().toLowerCase()
16
+ }
17
+
18
+ function mapTarget(value) {
19
+ return SUPPORTED_TARGETS[normalizeTarget(value)] || null
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const parsed = {
24
+ target: process.env.TSP_INSTALL_TARGET || '',
25
+ dryRun: process.env.CODEGRAPH_INSTALL_DRY_RUN === '1',
26
+ }
27
+
28
+ for (let index = 0; index < argv.length; index += 1) {
29
+ const arg = argv[index]
30
+ if (arg === '--target') {
31
+ parsed.target = argv[index + 1] || ''
32
+ index += 1
33
+ continue
34
+ }
35
+ if (arg.startsWith('--target=')) {
36
+ parsed.target = arg.slice('--target='.length)
37
+ continue
38
+ }
39
+ if (arg === '--dry-run') {
40
+ parsed.dryRun = true
41
+ continue
42
+ }
43
+ if (arg === '--help' || arg === '-h') {
44
+ parsed.help = true
45
+ continue
46
+ }
47
+ throw new Error(`Unknown argument: ${arg}`)
48
+ }
49
+
50
+ return parsed
51
+ }
52
+
53
+ function resolveCodeGraphBin() {
54
+ if (process.env.CODEGRAPH_INSTALL_BIN) {
55
+ return {
56
+ command: process.env.CODEGRAPH_INSTALL_BIN,
57
+ argsPrefix: [],
58
+ displayCommand: process.env.CODEGRAPH_INSTALL_BIN,
59
+ }
60
+ }
61
+
62
+ let packageJsonPath
63
+ try {
64
+ packageJsonPath = require.resolve('@colbymchenry/codegraph/package.json')
65
+ } catch (error) {
66
+ throw new Error(
67
+ 'Unable to resolve @colbymchenry/codegraph. Run npm install before applying the CodeGraph integration.'
68
+ )
69
+ }
70
+
71
+ const binPath = path.join(path.dirname(packageJsonPath), 'dist', 'bin', 'codegraph.js')
72
+ return {
73
+ command: process.execPath,
74
+ argsPrefix: [binPath],
75
+ displayCommand: `${process.execPath} ${binPath}`,
76
+ }
77
+ }
78
+
79
+ function buildInstallCommand(target) {
80
+ const mappedTarget = mapTarget(target)
81
+ if (!mappedTarget) {
82
+ return {
83
+ supported: false,
84
+ target: normalizeTarget(target),
85
+ reason: `CodeGraph upstream installer does not support TSP target: ${target || '(missing)'}`,
86
+ }
87
+ }
88
+
89
+ const resolved = resolveCodeGraphBin()
90
+ const args = [
91
+ ...resolved.argsPrefix,
92
+ 'install',
93
+ `--target=${mappedTarget}`,
94
+ '--location=global',
95
+ '--yes',
96
+ ]
97
+
98
+ return {
99
+ supported: true,
100
+ target: mappedTarget,
101
+ command: resolved.command,
102
+ args,
103
+ display: [resolved.displayCommand, ...args.slice(resolved.argsPrefix.length)].join(' '),
104
+ }
105
+ }
106
+
107
+ function printHelp() {
108
+ console.log(`Usage: node scripts/install-codegraph.js [--target <claude|codex|cursor|opencode>] [--dry-run]
109
+
110
+ Runs the upstream CodeGraph installer for the current TSP install target only.
111
+ The project index is not initialized here; run codegraph init -i inside a target project when needed.
112
+ `)
113
+ }
114
+
115
+ function run(argv = process.argv.slice(2)) {
116
+ const options = parseArgs(argv)
117
+ if (options.help) {
118
+ printHelp()
119
+ return 0
120
+ }
121
+
122
+ const install = buildInstallCommand(options.target)
123
+ if (!install.supported) {
124
+ console.error(`Skipping CodeGraph installer: ${install.reason}`)
125
+ return 0
126
+ }
127
+
128
+ if (options.dryRun) {
129
+ console.log(`CodeGraph install command: ${install.display}`)
130
+ return 0
131
+ }
132
+
133
+ console.error(`Running CodeGraph installer for ${install.target}`)
134
+ const result = spawnSync(install.command, install.args, {
135
+ cwd: process.cwd(),
136
+ env: process.env,
137
+ encoding: 'utf8',
138
+ stdio: ['inherit', process.stderr, process.stderr],
139
+ })
140
+
141
+ return typeof result.status === 'number' ? result.status : 1
142
+ }
143
+
144
+ if (require.main === module) {
145
+ try {
146
+ process.exit(run())
147
+ } catch (error) {
148
+ console.error(error.message || error)
149
+ process.exit(1)
150
+ }
151
+ }
152
+
153
+ module.exports = {
154
+ buildInstallCommand,
155
+ mapTarget,
156
+ parseArgs,
157
+ run,
158
+ }
@@ -137,6 +137,30 @@ function printComponents(components) {
137
137
  }
138
138
  }
139
139
 
140
+ function resolvePlanExternalInstalls(plan) {
141
+ return plan.selectedModules
142
+ .map(module => ({ module, externalInstall: module.externalInstall }))
143
+ .filter(({ externalInstall }) => externalInstall && typeof externalInstall === 'object' && !Array.isArray(externalInstall))
144
+ .filter(({ externalInstall }) => {
145
+ const profiles = Array.isArray(externalInstall.profiles)
146
+ ? externalInstall.profiles.map(value => String(value).trim()).filter(Boolean)
147
+ : [];
148
+ return profiles.length === 0 || profiles.includes(plan.profileId);
149
+ })
150
+ .map(({ module, externalInstall }) => ({
151
+ id: externalInstall.id || module.id,
152
+ moduleId: module.id,
153
+ description: externalInstall.description || '',
154
+ command: externalInstall.command || 'node',
155
+ script: externalInstall.script || null,
156
+ args: Array.isArray(externalInstall.args)
157
+ ? externalInstall.args.map(value => String(value))
158
+ : [],
159
+ target: plan.target || null,
160
+ profileId: plan.profileId || null,
161
+ }));
162
+ }
163
+
140
164
  function printPlan(plan) {
141
165
  console.log('Install plan:\n');
142
166
  console.log(
@@ -184,20 +208,12 @@ function printPlan(plan) {
184
208
  }
185
209
  }
186
210
 
187
- const externalInstalls = plan.selectedModules
188
- .map(module => ({ module, externalInstall: module.externalInstall }))
189
- .filter(({ externalInstall }) => externalInstall && typeof externalInstall === 'object' && !Array.isArray(externalInstall))
190
- .filter(({ externalInstall }) => {
191
- const profiles = Array.isArray(externalInstall.profiles)
192
- ? externalInstall.profiles.map(value => String(value).trim()).filter(Boolean)
193
- : [];
194
- return profiles.length === 0 || profiles.includes(plan.profileId);
195
- });
211
+ const externalInstalls = resolvePlanExternalInstalls(plan);
196
212
  if (externalInstalls.length > 0) {
197
213
  console.log('');
198
214
  console.log(`External install plan (${externalInstalls.length}):`);
199
- for (const { module, externalInstall } of externalInstalls) {
200
- console.log(`- ${externalInstall.id || module.id}: ${externalInstall.description || externalInstall.script}`);
215
+ for (const externalInstall of externalInstalls) {
216
+ console.log(`- ${externalInstall.id}: ${externalInstall.description || externalInstall.script}`);
201
217
  }
202
218
  }
203
219
  }
@@ -268,6 +284,7 @@ function main() {
268
284
  excludeComponentIds: request.excludeComponentIds,
269
285
  target: request.target,
270
286
  });
287
+ plan.externalInstalls = resolvePlanExternalInstalls(plan);
271
288
 
272
289
  if (options.json) {
273
290
  console.log(JSON.stringify(plan, null, 2));
@@ -1,12 +1,16 @@
1
1
  'use strict';
2
2
 
3
3
  const fs = require('fs');
4
+ const os = require('os');
4
5
  const path = require('path');
5
6
  const { spawnSync } = require('child_process');
6
7
 
7
8
  const { writeInstallState } = require('../install-state');
8
9
  const { writeInstallAuditManifest } = require('../install-audit-manifest');
9
10
 
11
+ const PLUGIN_NAME = require('../team-skills-data.json').plugin.name;
12
+ const OPENCODE_AGENTS_MD_MARKER = '<!-- team-skills-platform -->';
13
+
10
14
  function readJsonObject(filePath, label) {
11
15
  let parsed;
12
16
  try {
@@ -177,6 +181,16 @@ function buildMergedSettings(plan) {
177
181
  };
178
182
  }
179
183
 
184
+ function buildExternalInstallEnv(externalInstall) {
185
+ return {
186
+ ...process.env,
187
+ ...(externalInstall.env || {}),
188
+ TSP_INSTALL_TARGET: externalInstall.target || '',
189
+ TSP_INSTALL_PROFILE: externalInstall.profileId || '',
190
+ TSP_INSTALL_MODULE_ID: externalInstall.moduleId || '',
191
+ };
192
+ }
193
+
180
194
  function runExternalInstall(externalInstall) {
181
195
  const args = [];
182
196
  if (externalInstall.scriptPath) {
@@ -190,12 +204,18 @@ function runExternalInstall(externalInstall) {
190
204
 
191
205
  const command = externalInstall.command || 'node';
192
206
  const label = externalInstall.id || externalInstall.moduleId || command;
193
- console.log(`Running external install: ${label}`);
207
+ if (process.env.TSP_SKIP_EXTERNAL_INSTALLS === '1') {
208
+ console.error(`Skipping external install: ${label}`);
209
+ return;
210
+ }
211
+
212
+ console.error(`Running external install: ${label}`);
194
213
 
195
214
  const result = spawnSync(command, args, {
196
215
  cwd: externalInstall.cwd || process.cwd(),
216
+ env: buildExternalInstallEnv(externalInstall),
197
217
  encoding: 'utf8',
198
- stdio: 'inherit',
218
+ stdio: ['inherit', process.stderr, process.stderr],
199
219
  });
200
220
 
201
221
  if (result.status !== 0) {
@@ -203,6 +223,232 @@ function runExternalInstall(externalInstall) {
203
223
  }
204
224
  }
205
225
 
226
+ function mergePluginMarketplace(sourceMarketplace, targetMarketplace) {
227
+ if (!fs.existsSync(sourceMarketplace)) {
228
+ return;
229
+ }
230
+
231
+ const source = readJsonObject(sourceMarketplace, 'source marketplace');
232
+ let target = {
233
+ name: source.name || 'marketplace',
234
+ interface: source.interface || {},
235
+ plugins: [],
236
+ };
237
+
238
+ if (fs.existsSync(targetMarketplace)) {
239
+ target = readJsonObject(targetMarketplace, 'target marketplace');
240
+ if (!Array.isArray(target.plugins)) {
241
+ target.plugins = [];
242
+ }
243
+ }
244
+
245
+ const targetPlugins = target.plugins || [];
246
+ const nextPluginsByName = new Map();
247
+ for (const plugin of targetPlugins) {
248
+ if (plugin && typeof plugin.name === 'string') {
249
+ nextPluginsByName.set(plugin.name, plugin);
250
+ }
251
+ }
252
+ for (const plugin of source.plugins || []) {
253
+ if (plugin && typeof plugin.name === 'string') {
254
+ nextPluginsByName.set(plugin.name, plugin);
255
+ }
256
+ }
257
+
258
+ target.plugins = [...nextPluginsByName.values()];
259
+ fs.mkdirSync(path.dirname(targetMarketplace), { recursive: true });
260
+ fs.writeFileSync(targetMarketplace, JSON.stringify(target, null, 2) + '\n', 'utf8');
261
+ }
262
+
263
+ function registerCodexPlugin(plan) {
264
+ const configPath = path.join(plan.targetRoot, 'config.toml');
265
+ const marker = `[plugins."${PLUGIN_NAME}"]`;
266
+ const content = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf8') : '';
267
+ if (!content.includes(marker)) {
268
+ const entry = `\n${marker}\nenabled = true\n`;
269
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
270
+ fs.writeFileSync(configPath, `${content.replace(/\n+$/, '')}${entry}`, 'utf8');
271
+ }
272
+
273
+ const homeDir = path.basename(plan.targetRoot) === '.codex'
274
+ ? path.dirname(plan.targetRoot)
275
+ : (process.env.HOME || os.homedir());
276
+ const agentsHome = process.env.AGENTS_HOME_DIR || path.join(homeDir, '.agents');
277
+ mergePluginMarketplace(
278
+ path.join(plan.targetRoot, 'plugins', PLUGIN_NAME, '.agents', 'plugins', 'marketplace.json'),
279
+ path.join(agentsHome, 'plugins', 'marketplace.json')
280
+ );
281
+ }
282
+
283
+ function buildOpenCodeAgentsMd(pluginRoot) {
284
+ const agentsDir = path.join(pluginRoot, 'agents', 'roles');
285
+ const roleNames = fs.existsSync(agentsDir)
286
+ ? fs
287
+ .readdirSync(agentsDir)
288
+ .filter((name) => name.endsWith('.md'))
289
+ .map((name) => path.parse(name).name)
290
+ .sort()
291
+ : [];
292
+ const roleDisplay = {
293
+ 'tech-lead': 'Tech Lead(技术负责人)',
294
+ 'product-manager': 'Product Manager(产品经理)',
295
+ 'project-manager': 'Project Manager(项目管理)',
296
+ architect: 'Architect(架构师)',
297
+ 'frontend-engineer': 'Frontend Engineer(前端开发)',
298
+ 'backend-engineer': 'Backend Engineer(后端开发)',
299
+ 'qa-engineer': 'QA Engineer(测试工程师)',
300
+ 'devops-engineer': 'DevOps Engineer(运维工程师)',
301
+ };
302
+ const lines = [
303
+ OPENCODE_AGENTS_MD_MARKER,
304
+ '# Team Skills Platform — OpenCode Agent Index',
305
+ '',
306
+ '本文件由安装脚本自动生成。在 OpenCode 中与任何角色交互时,可直接引用下列角色和命令。',
307
+ '',
308
+ '## 可用角色',
309
+ '',
310
+ ];
311
+ for (const role of roleNames) {
312
+ lines.push(`- **${roleDisplay[role] || role}**: \`plugins/${PLUGIN_NAME}/agents/roles/${role}.md\``);
313
+ }
314
+ lines.push(
315
+ '',
316
+ '## 核心团队命令',
317
+ '',
318
+ '| 命令 | 用途 |',
319
+ '|------|------|',
320
+ '| `/team-help` | 根据当前阶段、artifacts 与阻塞项推荐下一步主链命令 |',
321
+ '| `/team-intake` | 接收需求并锁定目标、范围、约束 |',
322
+ '| `/team-plan` | 拆解任务、角色分工、依赖与里程碑 |',
323
+ '| `/team-execute` | 驱动研发角色在边界内实施 |',
324
+ '| `/team-review` | 做方案、质量、测试和放行评审 |',
325
+ '| `/team-release` | 做发布准备、上线检查与回滚保障 |',
326
+ '| `/team-closeout` | 在观察窗口结束后做最终收口与 backlog 回写 |',
327
+ '| `/handoff` | 在角色间做结构化交接 |',
328
+ '',
329
+ '## 插件根路径',
330
+ '',
331
+ '`~/.config/opencode/plugins/team-skills-platform/`',
332
+ '',
333
+ `<!-- end ${PLUGIN_NAME} -->`
334
+ );
335
+ return `${lines.join('\n')}\n`;
336
+ }
337
+
338
+ function mergeOpenCodeAgentsMd(targetPath, newContent) {
339
+ const markerEnd = `<!-- end ${PLUGIN_NAME} -->`;
340
+ if (!fs.existsSync(targetPath)) {
341
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
342
+ fs.writeFileSync(targetPath, newContent, 'utf8');
343
+ return;
344
+ }
345
+ const existing = fs.readFileSync(targetPath, 'utf8');
346
+ if (existing.includes(OPENCODE_AGENTS_MD_MARKER)) {
347
+ const startIdx = existing.indexOf(OPENCODE_AGENTS_MD_MARKER);
348
+ let endIdx = existing.indexOf(markerEnd, startIdx);
349
+ if (endIdx !== -1) {
350
+ endIdx += markerEnd.length;
351
+ if (existing[endIdx] === '\n') {
352
+ endIdx += 1;
353
+ }
354
+ fs.writeFileSync(targetPath, `${existing.slice(0, startIdx)}${newContent}`, 'utf8');
355
+ return;
356
+ }
357
+ }
358
+ const separator = existing.endsWith('\n') ? '\n' : '\n\n';
359
+ fs.writeFileSync(targetPath, `${existing}${separator}${newContent}`, 'utf8');
360
+ }
361
+
362
+ function mergeOpenCodeAgentsIndex(plan) {
363
+ const pluginRoot = path.join(plan.targetRoot, 'plugins', PLUGIN_NAME);
364
+ mergeOpenCodeAgentsMd(
365
+ path.join(plan.targetRoot, 'AGENTS.md'),
366
+ buildOpenCodeAgentsMd(pluginRoot)
367
+ );
368
+ }
369
+
370
+ function applyTargetPostInstall(plan) {
371
+ if (plan.adapter && plan.adapter.target === 'codex') {
372
+ registerCodexPlugin(plan);
373
+ }
374
+ if (plan.adapter && plan.adapter.target === 'opencode') {
375
+ mergeOpenCodeAgentsIndex(plan);
376
+ }
377
+ }
378
+
379
+ function replaceOperationByDestination(operations, replacement) {
380
+ let replaced = false;
381
+ const nextOperations = operations.map((operation) => {
382
+ if (operation.destinationPath !== replacement.destinationPath) {
383
+ return { ...operation };
384
+ }
385
+ replaced = true;
386
+ return {
387
+ ...operation,
388
+ ...replacement,
389
+ };
390
+ });
391
+
392
+ if (!replaced) {
393
+ nextOperations.push(replacement);
394
+ }
395
+
396
+ return nextOperations;
397
+ }
398
+
399
+ function appendOperationIfMissing(operations, operation) {
400
+ if (operations.some((item) => item.destinationPath === operation.destinationPath)) {
401
+ return operations.map((item) => ({ ...item }));
402
+ }
403
+ return [...operations.map((item) => ({ ...item })), operation];
404
+ }
405
+
406
+ function buildPlanWithRuntimeManagedOperations(plan, mergedSettingsPlan) {
407
+ if (!mergedSettingsPlan) {
408
+ return plan;
409
+ }
410
+
411
+ const renderedHooksConfig = JSON.stringify(mergedSettingsPlan.resolvedHooksConfig, null, 2) + '\n';
412
+ const hooksOperation = {
413
+ kind: 'render-template',
414
+ moduleId: 'hooks-runtime',
415
+ sourceRelativePath: path.join('hooks', 'hooks.json'),
416
+ destinationPath: mergedSettingsPlan.hooksDestinationPath,
417
+ strategy: 'rendered-hooks-config',
418
+ ownership: 'managed',
419
+ scaffoldOnly: false,
420
+ renderedContent: renderedHooksConfig,
421
+ };
422
+ const settingsOperation = {
423
+ kind: 'merge-json',
424
+ moduleId: 'hooks-runtime',
425
+ sourceRelativePath: 'settings.json',
426
+ destinationPath: mergedSettingsPlan.settingsPath,
427
+ strategy: 'merge-claude-settings',
428
+ ownership: 'managed',
429
+ scaffoldOnly: false,
430
+ payload: {
431
+ hooks: mergedSettingsPlan.mergedSettings.hooks || {},
432
+ },
433
+ };
434
+
435
+ const rewriteOperations = (operations = []) => appendOperationIfMissing(
436
+ replaceOperationByDestination(operations, hooksOperation),
437
+ settingsOperation
438
+ );
439
+
440
+ return {
441
+ ...plan,
442
+ operations: rewriteOperations(plan.operations),
443
+ statePreview: plan.statePreview
444
+ ? {
445
+ ...plan.statePreview,
446
+ operations: rewriteOperations(plan.statePreview.operations),
447
+ }
448
+ : plan.statePreview,
449
+ };
450
+ }
451
+
206
452
  function applyInstallPlan(plan) {
207
453
  const mergedSettingsPlan = buildMergedSettings(plan);
208
454
 
@@ -230,11 +476,14 @@ function applyInstallPlan(plan) {
230
476
  runExternalInstall(externalInstall);
231
477
  }
232
478
 
233
- writeInstallState(plan.installStatePath, plan.statePreview);
234
- const { installManifestPath } = writeInstallAuditManifest(plan);
479
+ applyTargetPostInstall(plan);
480
+
481
+ const statefulPlan = buildPlanWithRuntimeManagedOperations(plan, mergedSettingsPlan);
482
+ writeInstallState(statefulPlan.installStatePath, statefulPlan.statePreview);
483
+ const { installManifestPath } = writeInstallAuditManifest(statefulPlan);
235
484
 
236
485
  return {
237
- ...plan,
486
+ ...statefulPlan,
238
487
  applied: true,
239
488
  installManifestPath,
240
489
  };
@@ -242,4 +491,6 @@ function applyInstallPlan(plan) {
242
491
 
243
492
  module.exports = {
244
493
  applyInstallPlan,
494
+ buildExternalInstallEnv,
495
+ runExternalInstall,
245
496
  };
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  const { validateInstallModuleIds } = require('../install-manifests');
4
+ const { normalizeInstallTarget } = require('../install-targets/registry');
4
5
 
5
- const LEGACY_INSTALL_TARGETS = ['claude', 'cursor', 'antigravity'];
6
+ const LEGACY_INSTALL_TARGETS = ['claude', 'cursor', 'antigravity', 'codex', 'opencode'];
6
7
 
7
8
  function dedupeStrings(values) {
8
9
  return [...new Set((Array.isArray(values) ? values : []).map(value => String(value).trim()).filter(Boolean))];
@@ -104,7 +105,7 @@ function normalizeInstallRequest(options = {}) {
104
105
  ...(Array.isArray(options.legacyLanguages) ? options.legacyLanguages : []),
105
106
  ...(Array.isArray(options.languages) ? options.languages : []),
106
107
  ]).map(language => language.toLowerCase()));
107
- const target = options.target || config?.target || 'claude';
108
+ const target = normalizeInstallTarget(options.target || config?.target || 'claude');
108
109
  const hasManifestBaseSelection = Boolean(profileId) || moduleIds.length > 0 || includeComponentIds.length > 0;
109
110
  const usingManifestMode = hasManifestBaseSelection || excludeComponentIds.length > 0;
110
111
 
@@ -40,6 +40,9 @@ function normalizeOperations(operations) {
40
40
  if (operation.ownership && operation.ownership !== 'managed') {
41
41
  return false;
42
42
  }
43
+ if (operation.kind === 'merge-json') {
44
+ return false;
45
+ }
43
46
  return typeof operation.destinationPath === 'string' && operation.destinationPath.length > 0;
44
47
  });
45
48
  }
@@ -10,7 +10,7 @@ const {
10
10
  resolveLegacyCompatibilitySelection,
11
11
  resolveInstallPlan,
12
12
  } = require('./install-manifests');
13
- const { getInstallTargetAdapter } = require('./install-targets/registry');
13
+ const { getInstallTargetAdapter, normalizeInstallTarget } = require('./install-targets/registry');
14
14
 
15
15
  const LANGUAGE_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
16
16
  const EXCLUDED_GENERATED_SOURCE_SUFFIXES = [
@@ -85,7 +85,8 @@ function listAvailableLanguages(sourceRoot = getSourceRoot()) {
85
85
  }
86
86
 
87
87
  function validateLegacyTarget(target) {
88
- if (!LEGACY_INSTALL_TARGETS.includes(target)) {
88
+ const normalizedTarget = normalizeInstallTarget(target);
89
+ if (!LEGACY_INSTALL_TARGETS.includes(normalizedTarget)) {
89
90
  throw new Error(
90
91
  `Unknown install target: ${target}. Expected one of ${LEGACY_INSTALL_TARGETS.join(', ')}`
91
92
  );
@@ -502,10 +503,18 @@ function createLegacyInstallPlan(options = {}) {
502
503
  const sourceRoot = options.sourceRoot || getSourceRoot();
503
504
  const projectRoot = options.projectRoot || process.cwd();
504
505
  const homeDir = options.homeDir || process.env.HOME || os.homedir();
505
- const target = options.target || 'claude';
506
+ const target = normalizeInstallTarget(options.target || 'claude');
506
507
 
507
508
  validateLegacyTarget(target);
508
509
 
510
+ if (target === 'codex' || target === 'opencode') {
511
+ return createLegacyCompatInstallPlan({
512
+ ...options,
513
+ target,
514
+ legacyLanguages: options.languages || options.legacyLanguages || [],
515
+ });
516
+ }
517
+
509
518
  const context = {
510
519
  sourceRoot,
511
520
  projectRoot,
@@ -568,7 +577,7 @@ function createLegacyInstallPlan(options = {}) {
568
577
  function createLegacyCompatInstallPlan(options = {}) {
569
578
  const sourceRoot = options.sourceRoot || getSourceRoot();
570
579
  const projectRoot = options.projectRoot || process.cwd();
571
- const target = options.target || 'claude';
580
+ const target = normalizeInstallTarget(options.target || 'claude');
572
581
 
573
582
  validateLegacyTarget(target);
574
583
 
@@ -637,7 +646,7 @@ function materializeScaffoldOperation(sourceRoot, operation) {
637
646
  function createManifestInstallPlan(options = {}) {
638
647
  const sourceRoot = options.sourceRoot || getSourceRoot();
639
648
  const projectRoot = options.projectRoot || process.cwd();
640
- const target = options.target || 'claude';
649
+ const target = normalizeInstallTarget(options.target || 'claude');
641
650
  const legacyLanguages = Array.isArray(options.legacyLanguages)
642
651
  ? [...options.legacyLanguages]
643
652
  : [];
@@ -14,7 +14,7 @@ const {
14
14
  } = require('./install-executor');
15
15
  const {
16
16
  getInstallTargetAdapter,
17
- listInstallTargetAdapters,
17
+ listPublicInstallTargetAdapters,
18
18
  } = require('./install-targets/registry');
19
19
 
20
20
  const DEFAULT_REPO_ROOT = path.join(__dirname, '../..');
@@ -30,7 +30,7 @@ function readPackageVersion(repoRoot) {
30
30
 
31
31
  function normalizeTargets(targets) {
32
32
  if (!Array.isArray(targets) || targets.length === 0) {
33
- return listInstallTargetAdapters().map(adapter => adapter.target);
33
+ return listPublicInstallTargetAdapters().map(adapter => adapter.target);
34
34
  }
35
35
 
36
36
  const normalizedTargets = [];
@@ -1,7 +1,11 @@
1
1
  const fs = require('fs');
2
2
  const os = require('os');
3
3
  const path = require('path');
4
- const { getInstallTargetAdapter, planInstallTargetScaffold } = require('./install-targets/registry');
4
+ const {
5
+ getInstallTargetAdapter,
6
+ normalizeInstallTarget,
7
+ planInstallTargetScaffold,
8
+ } = require('./install-targets/registry');
5
9
 
6
10
  const DEFAULT_REPO_ROOT = path.join(__dirname, '../..');
7
11
  const SUPPORTED_INSTALL_TARGETS = ['claude', 'cursor', 'antigravity', 'codex', 'gemini', 'opencode', 'codebuddy', 'copilot', 'windsurf', 'augment'];
@@ -35,6 +39,21 @@ const LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET = Object.freeze({
35
39
  'agents-core',
36
40
  'commands-core',
37
41
  ],
42
+ codex: [
43
+ 'rules-core',
44
+ 'agents-core',
45
+ 'commands-core',
46
+ 'platform-configs',
47
+ 'workflow-quality',
48
+ ],
49
+ opencode: [
50
+ 'rules-core',
51
+ 'agents-core',
52
+ 'commands-core',
53
+ 'hooks-runtime',
54
+ 'platform-configs',
55
+ 'workflow-quality',
56
+ ],
38
57
  });
39
58
  const LEGACY_LANGUAGE_ALIAS_TO_CANONICAL = Object.freeze({
40
59
  cpp: 'cpp',
@@ -334,7 +353,7 @@ function validateInstallModuleIds(moduleIds, options = {}) {
334
353
  function listInstallComponents(options = {}) {
335
354
  const manifests = loadInstallManifests(options);
336
355
  const family = options.family || null;
337
- const target = options.target || null;
356
+ const target = options.target ? normalizeInstallTarget(options.target) : null;
338
357
 
339
358
  if (family && !Object.hasOwn(COMPONENT_FAMILY_PREFIXES, family)) {
340
359
  throw new Error(
@@ -424,7 +443,7 @@ function expandComponentIdsToModuleIds(componentIds, manifests) {
424
443
 
425
444
  function resolveLegacyCompatibilitySelection(options = {}) {
426
445
  const manifests = loadInstallManifests(options);
427
- const target = options.target || null;
446
+ const target = options.target ? normalizeInstallTarget(options.target) : null;
428
447
 
429
448
  if (target && !SUPPORTED_INSTALL_TARGETS.includes(target)) {
430
449
  throw new Error(
@@ -508,7 +527,7 @@ function resolveInstallPlan(options = {}) {
508
527
  }
509
528
  }
510
529
 
511
- const target = options.target || null;
530
+ const target = options.target ? normalizeInstallTarget(options.target) : null;
512
531
  if (target && !SUPPORTED_INSTALL_TARGETS.includes(target)) {
513
532
  throw new Error(
514
533
  `Unknown install target: ${target}. Expected one of ${SUPPORTED_INSTALL_TARGETS.join(', ')}`