@liangjie559567/ultrapower 5.5.25 → 5.5.26
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.
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
{
|
|
9
9
|
"name": "ultrapower",
|
|
10
10
|
"description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution",
|
|
11
|
-
"version": "5.5.
|
|
11
|
+
"version": "5.5.26",
|
|
12
12
|
"source": {
|
|
13
13
|
"source": "npm",
|
|
14
14
|
"package": "@liangjie559567/ultrapower",
|
|
15
|
-
"version": "5.5.
|
|
15
|
+
"version": "5.5.26"
|
|
16
16
|
},
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "liangjie559567"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Release Process
|
|
2
|
+
|
|
3
|
+
## 版本同步检查清单
|
|
4
|
+
|
|
5
|
+
发布前必须确保以下文件版本一致:
|
|
6
|
+
|
|
7
|
+
1. `package.json` - npm 包版本
|
|
8
|
+
2. `.claude-plugin/plugin.json` - 用户看到的插件版本
|
|
9
|
+
3. `.claude-plugin/marketplace.json` - 插件市场版本
|
|
10
|
+
|
|
11
|
+
## 自动化验证
|
|
12
|
+
|
|
13
|
+
### 本地验证
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run validate:versions
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### CI 验证
|
|
20
|
+
|
|
21
|
+
版本验证已集成到 GitHub Actions release 工作流的 preflight 步骤中。
|
|
22
|
+
|
|
23
|
+
## 发布流程
|
|
24
|
+
|
|
25
|
+
### 标准发布(推荐)
|
|
26
|
+
|
|
27
|
+
1. 更新版本号:
|
|
28
|
+
```bash
|
|
29
|
+
npm run bump -- 5.5.26
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2. 验证版本同步:
|
|
33
|
+
```bash
|
|
34
|
+
npm run validate:versions
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. 提交并打标签:
|
|
38
|
+
```bash
|
|
39
|
+
git add -A
|
|
40
|
+
git commit -m "chore: bump version to 5.5.26"
|
|
41
|
+
git tag v5.5.26
|
|
42
|
+
git push origin main
|
|
43
|
+
git push origin v5.5.26
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
4. GitHub Actions 自动执行:
|
|
47
|
+
- 构建和测试
|
|
48
|
+
- 发布到 npm
|
|
49
|
+
- 创建 GitHub Release
|
|
50
|
+
- 同步 marketplace.json 和 plugin.json
|
|
51
|
+
|
|
52
|
+
### 手动发布(仅用于调试)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm run release:dry-run # 预览
|
|
56
|
+
npm run release:local # 执行
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 故障排查
|
|
60
|
+
|
|
61
|
+
### 版本不一致
|
|
62
|
+
|
|
63
|
+
如果 `validate:versions` 失败:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 查看差异
|
|
67
|
+
git diff package.json .claude-plugin/plugin.json .claude-plugin/marketplace.json
|
|
68
|
+
|
|
69
|
+
# 手动修复后重新验证
|
|
70
|
+
npm run validate:versions
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### CI 失败
|
|
74
|
+
|
|
75
|
+
1. 检查 GitHub Actions 日志
|
|
76
|
+
2. 本地重现问题:
|
|
77
|
+
```bash
|
|
78
|
+
npm run test:run
|
|
79
|
+
npm run build
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 相关知识
|
|
83
|
+
|
|
84
|
+
- [k-077: Multi-File Version Sync in Release Pipeline](../../.omc/axiom/evolution/knowledge_base.md#k-077)
|
|
85
|
+
- [k-074: Version Number Sync Checklist](../../.omc/axiom/evolution/knowledge_base.md#k-074)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Testing Guide
|
|
2
|
+
|
|
3
|
+
## 测试环境隔离模式
|
|
4
|
+
|
|
5
|
+
### 标准模式(推荐)
|
|
6
|
+
|
|
7
|
+
所有需要文件系统操作或 git 环境的测试必须使用隔离的测试目录:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
import { mkdirSync, rmSync, existsSync } from 'fs';
|
|
13
|
+
|
|
14
|
+
describe('test suite', () => {
|
|
15
|
+
const testDir = join(homedir(), '.omc', 'test-unique-name');
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
mkdirSync(testDir, { recursive: true });
|
|
19
|
+
try {
|
|
20
|
+
require('child_process').execSync('git init', { cwd: testDir, stdio: 'ignore' });
|
|
21
|
+
} catch (e) {
|
|
22
|
+
// Ignore if git init fails
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
if (existsSync(testDir)) {
|
|
28
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should use testDir instead of process.cwd()', () => {
|
|
33
|
+
const config = {
|
|
34
|
+
workingDirectory: testDir // ✅ 正确
|
|
35
|
+
// workingDirectory: process.cwd() // ❌ 错误
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 关键要素
|
|
42
|
+
|
|
43
|
+
1. **使用 `homedir()`**:确保路径在用户目录下
|
|
44
|
+
2. **唯一测试目录名**:避免并发测试冲突
|
|
45
|
+
3. **`beforeEach` 中初始化 git**:满足 worktree 检查
|
|
46
|
+
4. **`afterEach` 中清理**:避免测试污染
|
|
47
|
+
5. **使用 `testDir` 而非 `process.cwd()`**:CI 环境兼容
|
|
48
|
+
|
|
49
|
+
### 反模式
|
|
50
|
+
|
|
51
|
+
❌ **错误**:使用 `process.cwd()`
|
|
52
|
+
```typescript
|
|
53
|
+
const config = {
|
|
54
|
+
workingDirectory: process.cwd() // CI 中路径不可控
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
✅ **正确**:使用隔离的 `testDir`
|
|
59
|
+
```typescript
|
|
60
|
+
const testDir = join(homedir(), '.omc', 'test-my-feature');
|
|
61
|
+
const config = {
|
|
62
|
+
workingDirectory: testDir
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 跨平台注意事项
|
|
67
|
+
|
|
68
|
+
### Windows vs Linux
|
|
69
|
+
|
|
70
|
+
- **路径分隔符**:使用 `path.join()` 而非手动拼接
|
|
71
|
+
- **`process.cwd()` 行为**:
|
|
72
|
+
- Linux CI: `/home/runner/work/repo/repo`
|
|
73
|
+
- Windows CI: `D:/a/repo/repo`
|
|
74
|
+
- 两者都可能在 home 目录外部
|
|
75
|
+
|
|
76
|
+
### Git 环境
|
|
77
|
+
|
|
78
|
+
测试目录默认不是 git 仓库,需要显式初始化:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
mkdirSync(testDir, { recursive: true });
|
|
83
|
+
try {
|
|
84
|
+
execSync('git init', { cwd: testDir, stdio: 'ignore' });
|
|
85
|
+
} catch (e) {
|
|
86
|
+
// Ignore if git not available
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 相关知识
|
|
92
|
+
|
|
93
|
+
- [k-078: CI Test Environment Isolation Pattern](../../.omc/axiom/evolution/knowledge_base.md#k-078)
|
|
94
|
+
- [k-079: Batch Fix Same-Pattern Issues](../../.omc/axiom/evolution/knowledge_base.md#k-079)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liangjie559567/ultrapower",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.26",
|
|
4
4
|
"description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -61,7 +61,8 @@
|
|
|
61
61
|
"postinstall": "node scripts/plugin-setup.mjs",
|
|
62
62
|
"release:local": "node scripts/release-local.mjs",
|
|
63
63
|
"release:dry-run": "node scripts/release-local.mjs --dry-run",
|
|
64
|
-
"bump": "node scripts/bump-version.mjs"
|
|
64
|
+
"bump": "node scripts/bump-version.mjs",
|
|
65
|
+
"validate:versions": "node scripts/validate-versions.mjs"
|
|
65
66
|
},
|
|
66
67
|
"dependencies": {
|
|
67
68
|
"@anthropic-ai/claude-agent-sdk": "^0.1.0",
|
package/scripts/plugin-setup.mjs
CHANGED
|
@@ -280,6 +280,57 @@ function fixNpmCache() {
|
|
|
280
280
|
|
|
281
281
|
fixNpmCache();
|
|
282
282
|
|
|
283
|
+
// Fix: npm-cache marketplace.json also needs repair
|
|
284
|
+
function fixNpmCacheMarketplace() {
|
|
285
|
+
try {
|
|
286
|
+
const npmCacheDir = join(CLAUDE_DIR, 'plugins', 'cache', 'npm-cache', 'node_modules', '@liangjie559567', 'ultrapower');
|
|
287
|
+
if (!existsSync(npmCacheDir)) return;
|
|
288
|
+
|
|
289
|
+
const npmMarketplaceDir = join(npmCacheDir, '.claude-plugin');
|
|
290
|
+
const npmMarketplacePath = join(npmMarketplaceDir, 'marketplace.json');
|
|
291
|
+
|
|
292
|
+
let cacheVersion = '0.0.0';
|
|
293
|
+
try {
|
|
294
|
+
const cachePkg = JSON.parse(readFileSync(join(npmCacheDir, 'package.json'), 'utf-8'));
|
|
295
|
+
cacheVersion = cachePkg.version || cacheVersion;
|
|
296
|
+
} catch { /* use default */ }
|
|
297
|
+
|
|
298
|
+
function marketplaceNeedsRepair() {
|
|
299
|
+
try {
|
|
300
|
+
const content = JSON.parse(readFileSync(npmMarketplacePath, 'utf-8'));
|
|
301
|
+
if (content.name !== 'omc') return true;
|
|
302
|
+
if (!Array.isArray(content.plugins) || content.plugins.length === 0) return true;
|
|
303
|
+
return false;
|
|
304
|
+
} catch (e) {
|
|
305
|
+
if (e.code === 'ENOENT') return true;
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (!marketplaceNeedsRepair()) return;
|
|
311
|
+
|
|
312
|
+
const cleanMarketplaceJson = {
|
|
313
|
+
name: 'omc',
|
|
314
|
+
description: 'Disciplined multi-agent orchestration for Claude Code: workflow enforcement + parallel execution',
|
|
315
|
+
owner: { name: 'liangjie559567' },
|
|
316
|
+
plugins: [{
|
|
317
|
+
name: 'ultrapower',
|
|
318
|
+
description: 'Disciplined multi-agent orchestration: workflow enforcement + parallel execution',
|
|
319
|
+
version: cacheVersion,
|
|
320
|
+
source: { source: 'npm', package: '@liangjie559567/ultrapower', version: cacheVersion },
|
|
321
|
+
author: { name: 'liangjie559567' }
|
|
322
|
+
}]
|
|
323
|
+
};
|
|
324
|
+
mkdirSync(npmMarketplaceDir, { recursive: true });
|
|
325
|
+
writeFileSync(npmMarketplacePath, JSON.stringify(cleanMarketplaceJson, null, 2));
|
|
326
|
+
console.log(`[OMC] Repaired npm-cache marketplace.json (v${cacheVersion})`);
|
|
327
|
+
} catch (e) {
|
|
328
|
+
console.log('[OMC] Warning: Could not repair npm-cache marketplace.json:', e.message);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
fixNpmCacheMarketplace();
|
|
333
|
+
|
|
283
334
|
// Fix: Claude Code's npm-cache/package.json stores a semver range (e.g. "^5.2.3") after first install.
|
|
284
335
|
// On subsequent "Update now" clicks, the installer sees the range is satisfied by the cached version
|
|
285
336
|
// and skips re-downloading — so users stay on the old version forever.
|
|
@@ -390,6 +441,54 @@ function fixMissingPluginJson() {
|
|
|
390
441
|
|
|
391
442
|
fixMissingPluginJson();
|
|
392
443
|
|
|
444
|
+
// Fix: npm install strips .claude-plugin/marketplace.json, recreate it in plugin cache
|
|
445
|
+
function fixMissingMarketplaceJson() {
|
|
446
|
+
try {
|
|
447
|
+
const pluginRoot = dirname(__dirname);
|
|
448
|
+
const pkgPath = join(pluginRoot, 'package.json');
|
|
449
|
+
if (!existsSync(pkgPath)) return;
|
|
450
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
451
|
+
const version = pkg.version || '0.0.0';
|
|
452
|
+
|
|
453
|
+
const marketplaceJson = {
|
|
454
|
+
name: 'omc',
|
|
455
|
+
description: 'Disciplined multi-agent orchestration for Claude Code: workflow enforcement + parallel execution',
|
|
456
|
+
owner: { name: 'liangjie559567' },
|
|
457
|
+
plugins: [{
|
|
458
|
+
name: 'ultrapower',
|
|
459
|
+
description: pkg.description || '',
|
|
460
|
+
version,
|
|
461
|
+
source: { source: 'npm', package: '@liangjie559567/ultrapower', version },
|
|
462
|
+
author: { name: 'liangjie559567' }
|
|
463
|
+
}]
|
|
464
|
+
};
|
|
465
|
+
const marketplaceJsonStr = JSON.stringify(marketplaceJson, null, 2);
|
|
466
|
+
|
|
467
|
+
// 1. Write to install dir
|
|
468
|
+
const localDir = join(pluginRoot, '.claude-plugin');
|
|
469
|
+
mkdirSync(localDir, { recursive: true });
|
|
470
|
+
writeFileSync(join(localDir, 'marketplace.json'), marketplaceJsonStr);
|
|
471
|
+
console.log('[OMC] Wrote .claude-plugin/marketplace.json in install dir');
|
|
472
|
+
|
|
473
|
+
// 2. Write to plugin cache
|
|
474
|
+
const pluginCacheBase = join(CLAUDE_DIR, 'plugins/cache/omc/ultrapower');
|
|
475
|
+
if (existsSync(pluginCacheBase)) {
|
|
476
|
+
const versions = readdirSync(pluginCacheBase);
|
|
477
|
+
for (const v of versions) {
|
|
478
|
+
const cacheDir = join(pluginCacheBase, v, '.claude-plugin');
|
|
479
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
480
|
+
const versionedMkt = { ...marketplaceJson, plugins: [{ ...marketplaceJson.plugins[0], version: v, source: { ...marketplaceJson.plugins[0].source, version: v } }] };
|
|
481
|
+
writeFileSync(join(cacheDir, 'marketplace.json'), JSON.stringify(versionedMkt, null, 2));
|
|
482
|
+
console.log(`[OMC] Wrote .claude-plugin/marketplace.json in plugin cache v${v}`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
} catch (e) {
|
|
486
|
+
console.log('[OMC] Warning: Could not create .claude-plugin/marketplace.json:', e.message);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
fixMissingMarketplaceJson();
|
|
491
|
+
|
|
393
492
|
// 1. Create HUD directory
|
|
394
493
|
if (!existsSync(HUD_DIR)) {
|
|
395
494
|
mkdirSync(HUD_DIR, { recursive: true });
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/validate-versions.mjs
|
|
3
|
+
// Validates version consistency across all version-bearing files
|
|
4
|
+
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
|
|
8
|
+
const files = [
|
|
9
|
+
{ path: 'package.json', extract: (c) => JSON.parse(c).version },
|
|
10
|
+
{ path: '.claude-plugin/plugin.json', extract: (c) => JSON.parse(c).version },
|
|
11
|
+
{ path: '.claude-plugin/marketplace.json', extract: (c) => JSON.parse(c).plugins?.[0]?.version },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function validateVersions() {
|
|
15
|
+
const versions = new Map();
|
|
16
|
+
const errors = [];
|
|
17
|
+
|
|
18
|
+
for (const { path, extract } of files) {
|
|
19
|
+
try {
|
|
20
|
+
const content = readFileSync(resolve(path), 'utf-8');
|
|
21
|
+
const version = extract(content);
|
|
22
|
+
if (!version) {
|
|
23
|
+
errors.push(`${path}: version not found`);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
versions.set(path, version);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
errors.push(`${path}: ${err.message}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (errors.length > 0) {
|
|
33
|
+
console.error('Version validation failed:');
|
|
34
|
+
errors.forEach(e => console.error(` - ${e}`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const uniqueVersions = new Set(versions.values());
|
|
39
|
+
if (uniqueVersions.size > 1) {
|
|
40
|
+
console.error('Version mismatch detected:');
|
|
41
|
+
versions.forEach((v, p) => console.error(` ${p}: ${v}`));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const version = Array.from(uniqueVersions)[0];
|
|
46
|
+
console.log(`✓ All versions in sync: ${version}`);
|
|
47
|
+
return version;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (import.meta.url.startsWith('file:') && process.argv[1]) {
|
|
51
|
+
validateVersions();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { validateVersions };
|