@weotro/dx 0.1.21 → 0.2.1

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 (75) hide show
  1. package/README.md +78 -766
  2. package/bin/dx.js +100 -182
  3. package/example/.env.development +1 -0
  4. package/example/README.md +24 -0
  5. package/example/dx/scripts/build +2 -0
  6. package/example/dx/scripts/db +2 -0
  7. package/example/dx/scripts/deploy +2 -0
  8. package/example/dx/scripts/setup +2 -0
  9. package/example/dx/scripts/start +12 -0
  10. package/example/dx/scripts/test +2 -0
  11. package/lib/env.js +40 -257
  12. package/lib/logger.js +5 -238
  13. package/lib/setup.js +72 -0
  14. package/package.json +27 -13
  15. package/skills/ask_3th/SKILL.md +2 -0
  16. package/skills/delegate_3th/SKILL.md +4 -2
  17. package/skills/delegate_3th/scripts/delegate_3th.py +37 -41
  18. package/skills/delegate_3th/scripts/test_delegate_3th.py +43 -17
  19. package/skills/dx-adopt/SKILL.md +88 -0
  20. package/skills/dx-adopt/agents/openai.yaml +2 -0
  21. package/skills/dx-adopt/references/dx-0.2-contract.md +95 -0
  22. package/skills/dx-adopt/references/migrate-0.1.md +48 -0
  23. package/bin/dx-with-version-env.js +0 -8
  24. package/lib/artifact-deploy/artifact-builder.js +0 -144
  25. package/lib/artifact-deploy/config.js +0 -180
  26. package/lib/artifact-deploy/remote-script.js +0 -301
  27. package/lib/artifact-deploy/remote-transport.js +0 -86
  28. package/lib/artifact-deploy.js +0 -70
  29. package/lib/backend-artifact-deploy/artifact-builder.js +0 -267
  30. package/lib/backend-artifact-deploy/config.js +0 -218
  31. package/lib/backend-artifact-deploy/path-utils.js +0 -18
  32. package/lib/backend-artifact-deploy/remote-phases.js +0 -14
  33. package/lib/backend-artifact-deploy/remote-result.js +0 -44
  34. package/lib/backend-artifact-deploy/remote-script.js +0 -507
  35. package/lib/backend-artifact-deploy/remote-transport.js +0 -123
  36. package/lib/backend-artifact-deploy/rollback.js +0 -5
  37. package/lib/backend-artifact-deploy/runtime-package.js +0 -46
  38. package/lib/backend-artifact-deploy.js +0 -91
  39. package/lib/backend-package.js +0 -674
  40. package/lib/cli/args.js +0 -38
  41. package/lib/cli/command-result.js +0 -1
  42. package/lib/cli/commands/contracts.js +0 -60
  43. package/lib/cli/commands/core.js +0 -533
  44. package/lib/cli/commands/db.js +0 -231
  45. package/lib/cli/commands/deploy.js +0 -175
  46. package/lib/cli/commands/env.js +0 -120
  47. package/lib/cli/commands/export.js +0 -39
  48. package/lib/cli/commands/package.js +0 -22
  49. package/lib/cli/commands/release.js +0 -55
  50. package/lib/cli/commands/stack.js +0 -427
  51. package/lib/cli/commands/start.js +0 -58
  52. package/lib/cli/commands/worktree.js +0 -145
  53. package/lib/cli/dx-cli.js +0 -1098
  54. package/lib/cli/flags.js +0 -123
  55. package/lib/cli/help-model.js +0 -234
  56. package/lib/cli/help-renderer.js +0 -137
  57. package/lib/cli/help-schema.js +0 -552
  58. package/lib/cli/help.js +0 -141
  59. package/lib/cli/index.js +0 -4
  60. package/lib/cli/nx-command.js +0 -13
  61. package/lib/confirm.js +0 -213
  62. package/lib/env-policy.js +0 -134
  63. package/lib/env-profile.js +0 -531
  64. package/lib/exec.js +0 -698
  65. package/lib/nx-ignore.js +0 -45
  66. package/lib/run-with-version-env.js +0 -163
  67. package/lib/sdk-build.js +0 -424
  68. package/lib/start-dev.js +0 -401
  69. package/lib/telegram-webhook.js +0 -431
  70. package/lib/validate-env.js +0 -317
  71. package/lib/vercel-deploy.js +0 -549
  72. package/lib/worktree.js +0 -1052
  73. package/skills/delegate_3th/scripts/__pycache__/delegate_3th.cpython-314.pyc +0 -0
  74. package/skills/delegate_3th/scripts/__pycache__/delegate_cc.cpython-314.pyc +0 -0
  75. package/skills/delegate_3th/scripts/__pycache__/test_delegate_cc.cpython-314.pyc +0 -0
package/lib/confirm.js DELETED
@@ -1,213 +0,0 @@
1
- import { createInterface } from 'node:readline'
2
- import { logger } from './logger.js'
3
-
4
- export class ConfirmManager {
5
- constructor() {
6
- this.rl = null
7
- }
8
-
9
- // 判断是否启用自动确认(CI 或显式环境变量)
10
- isAutoYes(skipFlag = false) {
11
- if (skipFlag) return true
12
- const ci = String(process.env.CI || '').toLowerCase()
13
- const autoYes = String(process.env.AI_CLI_YES || process.env.YES || '').toLowerCase()
14
- // 常见 CI 环境会设置 CI=true;也支持自定义 AI_CLI_YES/YES 变量
15
- return ci === 'true' || ci === '1' || autoYes === 'true' || autoYes === '1'
16
- }
17
-
18
- // 基础确认
19
- async confirm(message, defaultValue = false, skipFlag = false) {
20
- if (this.isAutoYes(skipFlag)) {
21
- logger.info(`跳过确认: ${message}`)
22
- return true
23
- }
24
-
25
- const prompt = defaultValue ? `${message} [Y/n]: ` : `${message} [y/N]: `
26
-
27
- return new Promise(resolve => {
28
- this.rl = createInterface({
29
- input: process.stdin,
30
- output: process.stdout,
31
- })
32
-
33
- this.rl.question(prompt, answer => {
34
- this.rl.close()
35
-
36
- const normalized = answer.toLowerCase().trim()
37
- if (normalized === '') {
38
- resolve(defaultValue)
39
- } else {
40
- resolve(['y', 'yes', '是', 'true', '1'].includes(normalized))
41
- }
42
- })
43
- })
44
- }
45
-
46
- // 危险操作确认
47
- async confirmDangerous(operation, environment = 'unknown', skipFlag = false) {
48
- if (this.isAutoYes(skipFlag)) {
49
- logger.warn(`跳过危险操作确认: ${operation}`)
50
- return true
51
- }
52
-
53
- logger.separator()
54
- logger.warn('警告: 即将执行危险操作')
55
- console.log(`操作: ${operation}`)
56
- console.log(`环境: ${environment}`)
57
-
58
- if (environment === 'production' || environment === '生产环境') {
59
- console.log(`🔥 此操作将在生产环境执行,可能导致数据丢失或服务中断`)
60
- console.log(`🔥 请确保您已经:`)
61
- console.log(` 1. 备份了重要数据`)
62
- console.log(` 2. 通知了相关团队成员`)
63
- console.log(` 3. 确认了操作的必要性`)
64
- } else {
65
- console.log(`此操作可能导致数据丢失,请谨慎操作`)
66
- }
67
-
68
- logger.separator()
69
-
70
- // 对于生产环境,需要两次确认
71
- if (environment === 'production' || environment === '生产环境') {
72
- const firstConfirm = await this.confirm('您确定要在生产环境执行此危险操作吗?', false, false)
73
- if (!firstConfirm) {
74
- return false
75
- }
76
-
77
- console.log(`\n请再次确认,输入操作名称以继续: ${operation}`)
78
- return new Promise(resolve => {
79
- this.rl = createInterface({
80
- input: process.stdin,
81
- output: process.stdout,
82
- })
83
-
84
- this.rl.question('请输入操作名称: ', answer => {
85
- this.rl.close()
86
- resolve(answer.trim() === operation)
87
- })
88
- })
89
- } else {
90
- return this.confirm('确定要继续吗?', false, false)
91
- }
92
- }
93
-
94
- // 批量操作确认
95
- async confirmBatch(operations, skipFlag = false) {
96
- if (this.isAutoYes(skipFlag)) {
97
- logger.info('跳过批量操作确认')
98
- return true
99
- }
100
-
101
- logger.separator()
102
- console.log('即将执行以下操作:')
103
- operations.forEach((op, index) => {
104
- console.log(`${index + 1}. ${op}`)
105
- })
106
- logger.separator()
107
-
108
- return this.confirm('确认执行所有操作?', false, false)
109
- }
110
-
111
- // 端口冲突确认
112
- async confirmPortCleanup(port, processes, skipFlag = false) {
113
- if (this.isAutoYes(skipFlag)) {
114
- logger.info(`跳过端口清理确认: 端口 ${port}`)
115
- return true
116
- }
117
-
118
- logger.warn(`端口 ${port} 被以下进程占用:`)
119
- processes.forEach(pid => {
120
- console.log(` 进程 ID: ${pid}`)
121
- })
122
-
123
- return this.confirm(`是否杀死这些进程以释放端口 ${port}?`, true, false)
124
- }
125
-
126
- // 环境切换确认
127
- async confirmEnvironmentSwitch(from, to, skipFlag = false) {
128
- if (this.isAutoYes(skipFlag)) {
129
- logger.info(`跳过环境切换确认: ${from} -> ${to}`)
130
- return true
131
- }
132
-
133
- if (to === 'production' || to === '生产环境') {
134
- logger.warn(`即将从 ${from} 切换到 ${to}`)
135
- logger.warn('生产环境操作需要额外谨慎')
136
- return this.confirm('确定要切换到生产环境吗?', false, false)
137
- }
138
-
139
- return this.confirm(`确定要从 ${from} 切换到 ${to} 吗?`, true, false)
140
- }
141
-
142
- // 文件覆盖确认
143
- async confirmOverwrite(filePath, skipFlag = false) {
144
- if (this.isAutoYes(skipFlag)) {
145
- logger.info(`跳过文件覆盖确认: ${filePath}`)
146
- return true
147
- }
148
-
149
- logger.warn(`文件已存在: ${filePath}`)
150
- return this.confirm('是否覆盖现有文件?', false, false)
151
- }
152
-
153
- // 清理操作确认
154
- async confirmCleanup(targets, skipFlag = false) {
155
- if (this.isAutoYes(skipFlag)) {
156
- logger.info('跳过清理操作确认')
157
- return true
158
- }
159
-
160
- logger.warn('即将清理以下内容:')
161
- targets.forEach(target => {
162
- console.log(` - ${target}`)
163
- })
164
-
165
- return this.confirm('确定要执行清理操作吗?', false, false)
166
- }
167
-
168
- // 服务启动确认(用于可能有端口冲突的情况)
169
- async confirmServiceStart(service, port, skipFlag = false) {
170
- if (this.isAutoYes(skipFlag)) {
171
- return true
172
- }
173
-
174
- return this.confirm(`确定要启动 ${service} 服务 (端口 ${port}) 吗?`, true, false)
175
- }
176
-
177
- // 版本发布确认
178
- async confirmRelease(version, isProduction = false, skipFlag = false) {
179
- if (this.isAutoYes(skipFlag)) {
180
- logger.info(`跳过版本发布确认: ${version}`)
181
- return true
182
- }
183
-
184
- if (isProduction) {
185
- logger.warn(`即将发布生产版本: ${version}`)
186
- logger.warn('此操作将创建正式发布标签')
187
- return this.confirmDangerous(`发布版本 ${version}`, '生产环境', false)
188
- } else {
189
- return this.confirm(`确定要发布开发版本 ${version} 吗?`, true, false)
190
- }
191
- }
192
-
193
- // 数据库操作确认
194
- async confirmDatabaseOperation(operation, environment, skipFlag = false) {
195
- const dangerousOps = ['reset', 'drop', 'migrate:reset', 'db:reset']
196
- const isDangerous = dangerousOps.some(op => operation.includes(op))
197
-
198
- if (isDangerous) {
199
- return this.confirmDangerous(
200
- `数据库操作: ${operation}`,
201
- environment,
202
- this.isAutoYes(skipFlag),
203
- )
204
- } else {
205
- if (this.isAutoYes(skipFlag)) {
206
- return true
207
- }
208
- return this.confirm(`确定要执行数据库操作: ${operation} (${environment}) 吗?`, true, false)
209
- }
210
- }
211
- }
212
-
213
- export const confirmManager = new ConfirmManager()
package/lib/env-policy.js DELETED
@@ -1,134 +0,0 @@
1
- import { existsSync, readFileSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import stripJsonComments from 'strip-json-comments'
4
-
5
- const DEFAULT_POLICY_PATH = 'env-policy.jsonc'
6
-
7
- let cachedPolicy = null
8
- let cachedPolicyDir = null
9
-
10
- function assertStringArray(value, fieldPath) {
11
- if (!Array.isArray(value)) {
12
- throw new Error(`${fieldPath} 必须是数组`)
13
- }
14
- const invalid = value.filter(v => typeof v !== 'string' || v.trim().length === 0)
15
- if (invalid.length > 0) {
16
- throw new Error(`${fieldPath} 中存在非法值,请使用非空字符串`)
17
- }
18
- }
19
-
20
- function assertRecord(value, fieldPath) {
21
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
22
- throw new Error(`${fieldPath} 必须是对象`)
23
- }
24
- }
25
-
26
- export function loadEnvPolicy(configDir) {
27
- if (cachedPolicy && cachedPolicyDir === configDir) return cachedPolicy
28
-
29
- const policyPath = join(configDir, DEFAULT_POLICY_PATH)
30
- if (!existsSync(policyPath)) {
31
- throw new Error(
32
- `缺少配置文件 ${DEFAULT_POLICY_PATH}。
33
- 请在目标工程根目录创建 dx/config/${DEFAULT_POLICY_PATH}(或用 DX_CONFIG_DIR / --config-dir 指定配置目录)。
34
- 当前配置目录: ${configDir}`,
35
- )
36
- }
37
-
38
- let parsed
39
- try {
40
- const raw = readFileSync(policyPath, 'utf8')
41
- parsed = JSON.parse(stripJsonComments(raw) || '{}')
42
- } catch (error) {
43
- throw new Error(`无法解析 ${DEFAULT_POLICY_PATH}: ${error.message}`)
44
- }
45
-
46
- validateEnvPolicy(parsed)
47
- cachedPolicy = parsed
48
- cachedPolicyDir = configDir
49
- return cachedPolicy
50
- }
51
-
52
- export function validateEnvPolicy(policy) {
53
- assertRecord(policy, 'env-policy')
54
-
55
- if (policy.version !== 1) {
56
- throw new Error('env-policy.jsonc.version 必须为 1')
57
- }
58
-
59
- assertStringArray(policy.environments, 'env-policy.jsonc.environments')
60
-
61
- if (typeof policy.secretPlaceholder !== 'string' || policy.secretPlaceholder.trim().length === 0) {
62
- throw new Error('env-policy.jsonc.secretPlaceholder 必须为非空字符串')
63
- }
64
-
65
- assertRecord(policy.keys, 'env-policy.jsonc.keys')
66
- assertStringArray(policy.keys.secret || [], 'env-policy.jsonc.keys.secret')
67
- assertStringArray(policy.keys.localOnly || [], 'env-policy.jsonc.keys.localOnly')
68
- assertStringArray(policy.keys.localOverride || [], 'env-policy.jsonc.keys.localOverride')
69
-
70
- assertRecord(policy.layout, 'env-policy.jsonc.layout')
71
- assertStringArray(policy.layout.forbidExact || [], 'env-policy.jsonc.layout.forbidExact')
72
- assertStringArray(policy.layout.allowRoot || [], 'env-policy.jsonc.layout.allowRoot')
73
- assertStringArray(policy.layout.allowSubdirGlobs || [], 'env-policy.jsonc.layout.allowSubdirGlobs')
74
-
75
- assertRecord(policy.appToTarget || {}, 'env-policy.jsonc.appToTarget')
76
- for (const [app, target] of Object.entries(policy.appToTarget || {})) {
77
- if (typeof app !== 'string' || app.trim().length === 0) {
78
- throw new Error('env-policy.jsonc.appToTarget 中存在非法 app key')
79
- }
80
- if (typeof target !== 'string' || target.trim().length === 0) {
81
- throw new Error('env-policy.jsonc.appToTarget 中存在非法 target value')
82
- }
83
- }
84
-
85
- assertRecord(policy.targets, 'env-policy.jsonc.targets')
86
- const targetIds = Object.keys(policy.targets)
87
- if (targetIds.length === 0) {
88
- throw new Error('env-policy.jsonc.targets 不能为空')
89
- }
90
-
91
- for (const [targetId, target] of Object.entries(policy.targets)) {
92
- if (typeof targetId !== 'string' || targetId.trim().length === 0) {
93
- throw new Error('env-policy.jsonc.targets 中存在非法 targetId')
94
- }
95
- assertRecord(target, `env-policy.jsonc.targets.${targetId}`)
96
- assertRecord(target.files, `env-policy.jsonc.targets.${targetId}.files`)
97
- if (typeof target.files.committed !== 'string' || target.files.committed.trim().length === 0) {
98
- throw new Error(`env-policy.jsonc.targets.${targetId}.files.committed 必须为非空字符串`)
99
- }
100
- if (typeof target.files.local !== 'string' || target.files.local.trim().length === 0) {
101
- throw new Error(`env-policy.jsonc.targets.${targetId}.files.local 必须为非空字符串`)
102
- }
103
- assertRecord(target.required || {}, `env-policy.jsonc.targets.${targetId}.required`)
104
-
105
- for (const [group, keys] of Object.entries(target.required || {})) {
106
- assertStringArray(keys, `env-policy.jsonc.targets.${targetId}.required.${group}`)
107
- }
108
- }
109
-
110
- // Ensure appToTarget does not point to missing targets.
111
- for (const [app, target] of Object.entries(policy.appToTarget || {})) {
112
- if (!policy.targets[target]) {
113
- throw new Error(
114
- `env-policy.jsonc.appToTarget.${app} 指向不存在的 target: ${target}(请在 env-policy.jsonc.targets 中定义)`,
115
- )
116
- }
117
- }
118
- }
119
-
120
- export function resolvePolicyTargetId(policy, app) {
121
- if (!policy || !app) return null
122
- const mapped = policy.appToTarget?.[app]
123
- return mapped || null
124
- }
125
-
126
- export function resolveTargetRequiredVars(policy, targetId, environment) {
127
- if (!policy || !targetId) return []
128
- const target = policy.targets?.[targetId]
129
- if (!target) return []
130
- const required = target.required || {}
131
- const common = Array.isArray(required._common) ? required._common : []
132
- const envSpecific = Array.isArray(required[environment]) ? required[environment] : []
133
- return Array.from(new Set([...common, ...envSpecific]))
134
- }