@mison/ag-kit-cn 2.0.1 → 3.0.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.
- package/{.agent → .agents}/agents/frontend-specialist.md +2 -2
- package/{.agent → .agents}/agents/orchestrator.md +1 -3
- package/.agents/mcp_config.json +22 -0
- package/{.agent → .agents}/rules/GEMINI.md +2 -2
- package/{.agent → .agents}/skills/api-patterns/SKILL.md +2 -2
- package/{.agent → .agents}/skills/app-builder/project-detection.md +1 -1
- package/{.agent → .agents}/skills/nextjs-react-expert/SKILL.md +2 -2
- package/{.agent → .agents}/skills/parallel-agents/SKILL.md +0 -1
- package/.agents/skills/refactoring-patterns/SKILL.md +43 -0
- package/{.agent → .agents}/workflows/create.md +1 -1
- package/CHANGELOG.md +21 -0
- package/README.md +54 -8
- package/bin/adapters/codex.js +29 -6
- package/bin/adapters/gemini.js +23 -3
- package/bin/ag-kit.js +512 -17
- package/bin/core/builder.js +1 -1
- package/bin/core/resource-loader.js +2 -2
- package/bin/utils/manifest.js +3 -0
- package/bin/utils.js +10 -3
- package/docs/PLAN.md +39 -0
- package/docs/TECH.md +136 -0
- package/package.json +12 -10
- package/scripts/ci-verify.js +95 -0
- package/scripts/clean.js +123 -0
- package/scripts/health-check.js +132 -0
- package/scripts/health-check.sh +6 -0
- package/tests/atomic-writer.test.js +47 -0
- package/tests/clean-script.test.js +77 -0
- package/tests/cli-smoke.test.js +479 -0
- package/tests/codex-adapter.test.js +132 -0
- package/tests/doctor.test.js +94 -0
- package/tests/gemini-adapter.test.js +30 -0
- package/tests/generator.test.js +48 -0
- package/tests/git-helper.test.js +53 -0
- package/tests/global-sync.test.js +133 -0
- package/tests/health-check-script.test.js +30 -0
- package/tests/managed-block.test.js +41 -0
- package/tests/manifest.test.js +97 -0
- package/tests/package-tarball.test.js +27 -0
- package/tests/phase-c.test.js +107 -0
- package/tests/standards-compliance.test.js +266 -0
- package/tests/transformer.test.js +74 -0
- package/.agent/mcp_config.json +0 -12
- package/docs/codex-rules-template.md +0 -36
- package/docs/mapping-spec.md +0 -68
- package/docs/multi-target-adapter.md +0 -80
- package/docs/official/README.md +0 -53
- package/docs/official/antigravity/agent-modes-settings.md +0 -64
- package/docs/official/antigravity/rules-workflows.md +0 -96
- package/docs/official/antigravity/skills.md +0 -147
- package/docs/official/codex/agents-md.md +0 -119
- package/docs/official/codex/config-advanced.md +0 -358
- package/docs/official/codex/config-basic.md +0 -141
- package/docs/official/codex/config-reference.md +0 -223
- package/docs/official/codex/config-sample.md +0 -216
- package/docs/official/codex/mcp.md +0 -107
- package/docs/official/codex/rules.md +0 -79
- package/docs/official/codex/skills.md +0 -114
- package/docs/official/sources-index.md +0 -32
- package/docs/operations.md +0 -145
- package/docs/terminology-style-guide.md +0 -69
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/charts.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/colors.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/icons.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/landing.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/products.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/prompts.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/react-performance.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/styles.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/typography.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/data/web-interface.csv +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/scripts/core.py +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/scripts/design_system.py +0 -0
- /package/{.agent → .agents}/.shared/ui-ux-pro-max/scripts/search.py +0 -0
- /package/{.agent → .agents}/ARCHITECTURE.md +0 -0
- /package/{.agent → .agents}/agents/backend-specialist.md +0 -0
- /package/{.agent → .agents}/agents/code-archaeologist.md +0 -0
- /package/{.agent → .agents}/agents/database-architect.md +0 -0
- /package/{.agent → .agents}/agents/debugger.md +0 -0
- /package/{.agent → .agents}/agents/devops-engineer.md +0 -0
- /package/{.agent → .agents}/agents/documentation-writer.md +0 -0
- /package/{.agent → .agents}/agents/explorer-agent.md +0 -0
- /package/{.agent → .agents}/agents/game-developer.md +0 -0
- /package/{.agent → .agents}/agents/mobile-developer.md +0 -0
- /package/{.agent → .agents}/agents/penetration-tester.md +0 -0
- /package/{.agent → .agents}/agents/performance-optimizer.md +0 -0
- /package/{.agent → .agents}/agents/product-manager.md +0 -0
- /package/{.agent → .agents}/agents/product-owner.md +0 -0
- /package/{.agent → .agents}/agents/project-planner.md +0 -0
- /package/{.agent → .agents}/agents/qa-automation-engineer.md +0 -0
- /package/{.agent → .agents}/agents/security-auditor.md +0 -0
- /package/{.agent → .agents}/agents/seo-specialist.md +0 -0
- /package/{.agent → .agents}/agents/test-engineer.md +0 -0
- /package/{.agent → .agents}/scripts/auto_preview.py +0 -0
- /package/{.agent → .agents}/scripts/checklist.py +0 -0
- /package/{.agent → .agents}/scripts/session_manager.py +0 -0
- /package/{.agent → .agents}/scripts/verify_all.py +0 -0
- /package/{.agent → .agents}/skills/api-patterns/api-style.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/auth.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/documentation.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/graphql.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/rate-limiting.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/response.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/rest.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/scripts/api_validator.py +0 -0
- /package/{.agent → .agents}/skills/api-patterns/security-testing.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/trpc.md +0 -0
- /package/{.agent → .agents}/skills/api-patterns/versioning.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/agent-coordination.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/feature-building.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/scaffolding.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/tech-stack.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/express-api/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -0
- /package/{.agent → .agents}/skills/architecture/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/architecture/context-discovery.md +0 -0
- /package/{.agent → .agents}/skills/architecture/examples.md +0 -0
- /package/{.agent → .agents}/skills/architecture/pattern-selection.md +0 -0
- /package/{.agent → .agents}/skills/architecture/patterns-reference.md +0 -0
- /package/{.agent → .agents}/skills/architecture/trade-off-analysis.md +0 -0
- /package/{.agent → .agents}/skills/bash-linux/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/behavioral-modes/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/brainstorming/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/brainstorming/dynamic-questioning.md +0 -0
- /package/{.agent → .agents}/skills/clean-code/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/code-review-checklist/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/database-design/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/database-design/database-selection.md +0 -0
- /package/{.agent → .agents}/skills/database-design/indexing.md +0 -0
- /package/{.agent → .agents}/skills/database-design/migrations.md +0 -0
- /package/{.agent → .agents}/skills/database-design/optimization.md +0 -0
- /package/{.agent → .agents}/skills/database-design/orm-selection.md +0 -0
- /package/{.agent → .agents}/skills/database-design/schema-design.md +0 -0
- /package/{.agent → .agents}/skills/database-design/scripts/schema_validator.py +0 -0
- /package/{.agent → .agents}/skills/deployment-procedures/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/doc.md +0 -0
- /package/{.agent → .agents}/skills/documentation-templates/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/animation-guide.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/color-system.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/decision-trees.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/motion-graphics.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/scripts/accessibility_checker.py +0 -0
- /package/{.agent → .agents}/skills/frontend-design/scripts/ux_audit.py +0 -0
- /package/{.agent → .agents}/skills/frontend-design/typography-system.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/ux-psychology.md +0 -0
- /package/{.agent → .agents}/skills/frontend-design/visual-effects.md +0 -0
- /package/{.agent → .agents}/skills/game-development/2d-games/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/3d-games/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/game-art/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/game-audio/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/game-design/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/mobile-games/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/multiplayer/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/pc-games/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/vr-ar/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/game-development/web-games/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/geo-fundamentals/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/geo-fundamentals/scripts/geo_checker.py +0 -0
- /package/{.agent → .agents}/skills/i18n-localization/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/i18n-localization/scripts/i18n_checker.py +0 -0
- /package/{.agent → .agents}/skills/intelligent-routing/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/lint-and-validate/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/lint-and-validate/scripts/lint_runner.py +0 -0
- /package/{.agent → .agents}/skills/lint-and-validate/scripts/type_coverage.py +0 -0
- /package/{.agent → .agents}/skills/mcp-builder/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/decision-trees.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-backend.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-color-system.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-debugging.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-design-thinking.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-navigation.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-performance.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-testing.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/mobile-typography.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/platform-android.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/platform-ios.md +0 -0
- /package/{.agent → .agents}/skills/mobile-design/scripts/mobile_audit.py +0 -0
- /package/{.agent → .agents}/skills/mobile-design/touch-psychology.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/scripts/convert_rules.py +0 -0
- /package/{.agent → .agents}/skills/nextjs-react-expert/scripts/react_performance_checker.py +0 -0
- /package/{.agent → .agents}/skills/nodejs-best-practices/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/performance-profiling/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/performance-profiling/scripts/lighthouse_audit.py +0 -0
- /package/{.agent → .agents}/skills/plan-writing/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/powershell-windows/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/python-patterns/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/red-team-tactics/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/rust-pro/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/seo-fundamentals/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/seo-fundamentals/scripts/seo_checker.py +0 -0
- /package/{.agent → .agents}/skills/server-management/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/systematic-debugging/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/tailwind-patterns/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/tdd-workflow/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/testing-patterns/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/testing-patterns/scripts/test_runner.py +0 -0
- /package/{.agent → .agents}/skills/vulnerability-scanner/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/vulnerability-scanner/checklists.md +0 -0
- /package/{.agent → .agents}/skills/vulnerability-scanner/scripts/security_scan.py +0 -0
- /package/{.agent → .agents}/skills/web-design-guidelines/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/webapp-testing/SKILL.md +0 -0
- /package/{.agent → .agents}/skills/webapp-testing/scripts/playwright_runner.py +0 -0
- /package/{.agent → .agents}/workflows/brainstorm.md +0 -0
- /package/{.agent → .agents}/workflows/debug.md +0 -0
- /package/{.agent → .agents}/workflows/deploy.md +0 -0
- /package/{.agent → .agents}/workflows/enhance.md +0 -0
- /package/{.agent → .agents}/workflows/orchestrate.md +0 -0
- /package/{.agent → .agents}/workflows/plan.md +0 -0
- /package/{.agent → .agents}/workflows/preview.md +0 -0
- /package/{.agent → .agents}/workflows/restore-localize-compat.md +0 -0
- /package/{.agent → .agents}/workflows/status.md +0 -0
- /package/{.agent → .agents}/workflows/test.md +0 -0
- /package/{.agent → .agents}/workflows/ui-ux-pro-max.md +0 -0
|
@@ -4,8 +4,8 @@ const path = require("path");
|
|
|
4
4
|
class ResourceLoader {
|
|
5
5
|
constructor(rootDir) {
|
|
6
6
|
this.rootDir = rootDir;
|
|
7
|
-
this.skillsDir = path.join(rootDir, ".
|
|
8
|
-
this.workflowsDir = path.join(rootDir, ".
|
|
7
|
+
this.skillsDir = path.join(rootDir, ".agents", "skills");
|
|
8
|
+
this.workflowsDir = path.join(rootDir, ".agents", "workflows");
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
package/bin/utils/manifest.js
CHANGED
|
@@ -13,6 +13,7 @@ class ManifestManager {
|
|
|
13
13
|
updatedAt: "",
|
|
14
14
|
files: {},
|
|
15
15
|
};
|
|
16
|
+
this.lastLoadError = null;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -77,11 +78,13 @@ class ManifestManager {
|
|
|
77
78
|
* Load manifest from disk
|
|
78
79
|
*/
|
|
79
80
|
load() {
|
|
81
|
+
this.lastLoadError = null;
|
|
80
82
|
if (fs.existsSync(this.manifestPath)) {
|
|
81
83
|
try {
|
|
82
84
|
const raw = fs.readFileSync(this.manifestPath, "utf8");
|
|
83
85
|
this.manifest = ManifestManager.normalizeManifestShape(JSON.parse(raw));
|
|
84
86
|
} catch (err) {
|
|
87
|
+
this.lastLoadError = err;
|
|
85
88
|
this.manifest = {
|
|
86
89
|
version: 2,
|
|
87
90
|
target: typeof this.options.target === "string" ? this.options.target : "",
|
package/bin/utils.js
CHANGED
|
@@ -63,14 +63,21 @@ function cloneBranchAgentDir(branch, options) {
|
|
|
63
63
|
throw new Error(`无法拉取分支 ${safeBranch},请确认分支存在且网络可用`);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
const clonedAgentsDir = path.join(tempDir, ".agents");
|
|
66
67
|
const clonedAgentDir = path.join(tempDir, ".agent");
|
|
67
|
-
|
|
68
|
+
let templateDir = "";
|
|
69
|
+
|
|
70
|
+
if (fs.existsSync(clonedAgentsDir)) {
|
|
71
|
+
templateDir = clonedAgentsDir;
|
|
72
|
+
} else if (fs.existsSync(clonedAgentDir)) {
|
|
73
|
+
templateDir = clonedAgentDir;
|
|
74
|
+
} else {
|
|
68
75
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
69
|
-
throw new Error(`分支 ${safeBranch} 中未找到 .agent 目录`);
|
|
76
|
+
throw new Error(`分支 ${safeBranch} 中未找到 .agents 或 .agent 目录`);
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
return {
|
|
73
|
-
agentDir:
|
|
80
|
+
agentDir: templateDir,
|
|
74
81
|
cleanup: () => fs.rmSync(tempDir, { recursive: true, force: true }),
|
|
75
82
|
};
|
|
76
83
|
}
|
package/docs/PLAN.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Ag-Kit 规划(PLAN)
|
|
2
|
+
|
|
3
|
+
## 一句话
|
|
4
|
+
Ag-Kit 只做一件事:把仓库内统一的 `.agents/` 模板,优雅地投影到不同平台(Gemini/Antigravity 与 Codex),并提供安全、可回滚的更新机制。
|
|
5
|
+
|
|
6
|
+
## 设计原则
|
|
7
|
+
- 命令面少而强:用 `sync` 统一“首次安装 + 更新”,避免双心智。
|
|
8
|
+
- 默认安全:不做全局清理、不自动写入高风险全局规则。
|
|
9
|
+
- 模板源单一:仓库 Canonical 为 `.agents/`;旧 `.agent/` 只作为输入兼容,不作为主路径。
|
|
10
|
+
|
|
11
|
+
## 能力边界(项目 vs 全局)
|
|
12
|
+
### 项目安装(功能最完整)
|
|
13
|
+
- 命令:`ag-kit init` / `ag-kit update` / `ag-kit status` / `ag-kit doctor`
|
|
14
|
+
- 目标输出:
|
|
15
|
+
- `gemini` -> 项目内 `.agent/`(兼容 Gemini/Antigravity 工作区规范)
|
|
16
|
+
- `codex` -> 项目内 `.agents/`(受管目录)+ 注入工作区 `AGENTS.md` / `antigravity.rules` 托管区块
|
|
17
|
+
|
|
18
|
+
### 全局安装(跨项目复用 Skills)
|
|
19
|
+
- 命令:`ag-kit global sync` / `ag-kit global status`
|
|
20
|
+
- 默认行为:`ag-kit global sync` 未指定 `--target/--targets` 时,同步 `codex + gemini`
|
|
21
|
+
- 目标路径:
|
|
22
|
+
- `codex` -> `$HOME/.codex/skills/`
|
|
23
|
+
- `gemini` -> 同时写入 `$HOME/.gemini/skills/` 与 `$HOME/.gemini/antigravity/skills/`
|
|
24
|
+
- 安全边界:全局只同步 Skills,不写入全局 Rules/Agents/Workflows。
|
|
25
|
+
|
|
26
|
+
## 覆盖与回滚(全局同步)
|
|
27
|
+
- 覆盖单位:每个 Skill 目录。
|
|
28
|
+
- 覆盖策略:只覆盖同名 Skill;不清理用户已有的其他 Skill。
|
|
29
|
+
- 覆盖前备份:每次覆盖同名 Skill 前备份到 `$HOME/.ag-kit/backups/global/<timestamp>/...`。
|
|
30
|
+
|
|
31
|
+
## 兼容策略
|
|
32
|
+
- Gemini/Antigravity:输出 `.agent/`,保持与官方工作区机制一致。
|
|
33
|
+
- Codex:受管目录为 `.agents/`,并使用 `manifest.json` 做完整性与漂移检测;识别并迁移遗留 `.codex/`。
|
|
34
|
+
- 全局同步遵循真实消费端目录,而不是仓库模板源目录;仓库内仍以 `.agents/` 作为唯一 Canonical。
|
|
35
|
+
|
|
36
|
+
## 成功标准
|
|
37
|
+
- `ag-kit global sync` 一条命令即可完成全局 Skills 安装/更新(默认 codex + gemini,其中 gemini 同步到 gemini-cli 与 antigravity)。
|
|
38
|
+
- 覆盖可回滚:每次覆盖同名 Skill 都有可用备份。
|
|
39
|
+
- 跨平台 CI(Linux/macOS/Windows)验证主链路通过。
|
package/docs/TECH.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Ag-Kit 技术说明(TECH)
|
|
2
|
+
|
|
3
|
+
## 快速验证(维护者)
|
|
4
|
+
```bash
|
|
5
|
+
bun install
|
|
6
|
+
bun run test
|
|
7
|
+
bun run ci:verify
|
|
8
|
+
bun run health-check
|
|
9
|
+
cd web && bun install && bun run lint
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 核心目录与职责
|
|
13
|
+
- `.agents/`:仓库模板源(Canonical)
|
|
14
|
+
- `bin/ag-kit.js`:CLI 入口与命令分发
|
|
15
|
+
- `bin/adapters/`:目标差异(`gemini` / `codex`)
|
|
16
|
+
- `bin/core/`:构建/转换(将 Workflows 投影为 Codex Skills 等)
|
|
17
|
+
- `bin/utils/`:原子写入、manifest、托管区块等通用能力
|
|
18
|
+
|
|
19
|
+
## 路径映射(最重要)
|
|
20
|
+
### 项目级(功能最完整)
|
|
21
|
+
- `gemini`:项目根目录 `.agent/`
|
|
22
|
+
- `codex`:项目根目录 `.agents/`(受管)+ `.agents-backup/`(漂移覆盖备份)
|
|
23
|
+
|
|
24
|
+
### 全局级(仅同步 Skills)
|
|
25
|
+
- `codex`:`$HOME/.codex/skills/`
|
|
26
|
+
- `gemini-cli`:`$HOME/.gemini/skills/`
|
|
27
|
+
- `antigravity`:`$HOME/.gemini/antigravity/skills/`
|
|
28
|
+
|
|
29
|
+
> 说明:仓库内 Skills 源路径为 `.agents/skills/`,全局同步会将其投影到真实工具读取的全局目录;仓库 Canonical 仍是 `.agents/`。
|
|
30
|
+
|
|
31
|
+
## 端到端链路(简述)
|
|
32
|
+
### 项目安装 / 更新
|
|
33
|
+
- `init`:选择目标 -> 适配器 `install()` -> 落盘目标目录(Gemini: `.agent/`;Codex: `.agents/`)->(Codex)注入托管区块到工作区 `AGENTS.md` 与 `antigravity.rules`
|
|
34
|
+
- `update`:自动检测已安装目标(或通过 `--target/--targets` 指定)-> 适配器 `update()` ->(Codex)漂移检测与备份 -> 原子替换
|
|
35
|
+
- `doctor`:检查完整性;`--fix` 尝试修复(Codex 支持迁移 `.codex/` 与重写托管区块)
|
|
36
|
+
|
|
37
|
+
### Codex 构建(Workflow -> Skill)
|
|
38
|
+
- 输入:`.agents/skills/` 与 `.agents/workflows/`
|
|
39
|
+
- 规则:每个 Workflow `<name>.md` 会转换为一个 Skill:`workflow-<name>/SKILL.md`
|
|
40
|
+
- 输出(受管目录 `.agents/` 内):`skills/`、`codex.json`、`AGENTS.md`、`antigravity.rules`、`manifest.json`
|
|
41
|
+
|
|
42
|
+
## 全局同步:`ag-kit global sync/status`
|
|
43
|
+
### 默认目标
|
|
44
|
+
- 未指定 `--target/--targets`:默认同步 `codex + gemini`
|
|
45
|
+
- `--target gemini` / `--targets codex,gemini` 中的 `gemini` 会同时写入 gemini-cli 与 antigravity 两个消费端目录
|
|
46
|
+
|
|
47
|
+
### 来源与覆盖策略
|
|
48
|
+
- 来源:默认使用本包内置 `.agents/`;也可用 `--branch <name>` 从远端分支拉取模板源
|
|
49
|
+
- 覆盖单位:每个 Skill 目录
|
|
50
|
+
- 覆盖策略:只覆盖同名 Skill,不清理其他 Skill
|
|
51
|
+
- 原子替换:按 Skill 目录原子替换,避免半写状态
|
|
52
|
+
- 覆盖前备份:覆盖同名 Skill 前备份到 `$HOME/.ag-kit/backups/global/<timestamp>/<consumer>/<skill>/...`
|
|
53
|
+
- `consumer` 可能是 `codex`、`gemini-cli`、`antigravity`
|
|
54
|
+
|
|
55
|
+
### 测试隔离
|
|
56
|
+
- `AG_KIT_GLOBAL_ROOT`:替代 `$HOME`(用于测试与 CI,避免污染真实用户目录)
|
|
57
|
+
|
|
58
|
+
## 状态契约(自动化)
|
|
59
|
+
- `ag-kit status --quiet` / `ag-kit global status --quiet` 只输出三态:
|
|
60
|
+
- `installed`:检测到目标且完整性正常
|
|
61
|
+
- `broken`:检测到目标但存在残缺、漂移或结构异常
|
|
62
|
+
- `missing`:未检测到任何已安装目标
|
|
63
|
+
- 退出码固定为:
|
|
64
|
+
- `0` = `installed`
|
|
65
|
+
- `1` = `broken`
|
|
66
|
+
- `2` = `missing`
|
|
67
|
+
- 若需要问题明细,使用 `ag-kit doctor`;`status` 负责健康状态,`doctor` 负责诊断细节。
|
|
68
|
+
|
|
69
|
+
## 手动回滚(全局 Skills)
|
|
70
|
+
1. 找到备份目录:`$HOME/.ag-kit/backups/global/<timestamp>/...`
|
|
71
|
+
2. 按 Skill 回滚(推荐一次只处理一个 Skill 目录):
|
|
72
|
+
- Codex 目标:恢复到 `$HOME/.codex/skills/<skill>/`
|
|
73
|
+
- Gemini CLI:恢复到 `$HOME/.gemini/skills/<skill>/`
|
|
74
|
+
- Antigravity:恢复到 `$HOME/.gemini/antigravity/skills/<skill>/`
|
|
75
|
+
|
|
76
|
+
macOS / Linux 示例(把某个 Skill 回滚为备份版本):
|
|
77
|
+
```bash
|
|
78
|
+
ts="2026-03-12T12-00-00-000Z"
|
|
79
|
+
skill="clean-code"
|
|
80
|
+
rm -rf "$HOME/.codex/skills/$skill"
|
|
81
|
+
cp -a "$HOME/.ag-kit/backups/global/$ts/codex/$skill" "$HOME/.codex/skills/$skill"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Windows PowerShell 示例:
|
|
85
|
+
```powershell
|
|
86
|
+
$ts = "2026-03-12T12-00-00-000Z"
|
|
87
|
+
$skill = "clean-code"
|
|
88
|
+
Remove-Item "$HOME\\.codex\\skills\\$skill" -Recurse -Force -ErrorAction SilentlyContinue
|
|
89
|
+
Copy-Item "$HOME\\.ag-kit\\backups\\global\\$ts\\codex\\$skill" "$HOME\\.codex\\skills\\$skill" -Recurse -Force
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Gemini CLI 回滚示例:
|
|
93
|
+
```bash
|
|
94
|
+
ts="2026-03-12T12-00-00-000Z"
|
|
95
|
+
skill="clean-code"
|
|
96
|
+
rm -rf "$HOME/.gemini/skills/$skill"
|
|
97
|
+
cp -a "$HOME/.ag-kit/backups/global/$ts/gemini-cli/$skill" "$HOME/.gemini/skills/$skill"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Antigravity 回滚示例:
|
|
101
|
+
```bash
|
|
102
|
+
ts="2026-03-12T12-00-00-000Z"
|
|
103
|
+
skill="clean-code"
|
|
104
|
+
rm -rf "$HOME/.gemini/antigravity/skills/$skill"
|
|
105
|
+
cp -a "$HOME/.ag-kit/backups/global/$ts/antigravity/$skill" "$HOME/.gemini/antigravity/skills/$skill"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 环境变量
|
|
109
|
+
- `AG_KIT_INDEX_PATH`:工作区索引文件路径(默认 `~/.ag-kit/workspaces.json`)
|
|
110
|
+
- `AG_KIT_GLOBAL_ROOT`:全局目录根(替代 `$HOME`)
|
|
111
|
+
- `AG_KIT_SKIP_UPSTREAM_CHECK`:跳过上游同名包安装提示(测试用)
|
|
112
|
+
|
|
113
|
+
## 安装提示机制
|
|
114
|
+
- npm 全局安装:`postinstall` 会尽力检测并提示上游英文版 `@vudovn/ag-kit` 冲突。
|
|
115
|
+
- Bun 全局安装:Bun 默认会阻止本包 `postinstall`;因此冲突提示以内置 CLI 运行期检查为准,会在 `init` / `update` / `update-all` / `global sync` 时提示。
|
|
116
|
+
- 冲突提示只负责提醒,不会自动修改当前安装状态;如需清理可执行 `npm uninstall -g @vudovn/ag-kit`。
|
|
117
|
+
|
|
118
|
+
## 常见故障
|
|
119
|
+
- 更新中断:原子替换保证不会出现半写状态;重新运行 `update`/`global sync` 即可。
|
|
120
|
+
- Windows `EPERM/EBUSY`:通常是目录被占用;关闭占用 `.agents/` 或目标 Skill 目录的进程后重试。
|
|
121
|
+
- 漂移覆盖:Codex 若检测到用户修改受管文件,会在覆盖前写入 `.agents-backup/<timestamp>/`。
|
|
122
|
+
|
|
123
|
+
## Codex 官方 `.rules`(手动配置)
|
|
124
|
+
Ag-Kit 不会自动写入全局 `~/.codex/rules/default.rules`,避免引入不可预期的全局副作用。若你需要启用 Codex 官方命令审批策略(如 `prefix_rule()`),可按需手动创建:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# default.rules
|
|
128
|
+
load("builtin://rules/rules.star", "prefix_rule")
|
|
129
|
+
|
|
130
|
+
rules = [
|
|
131
|
+
prefix_rule(["ls"], action="allow"),
|
|
132
|
+
prefix_rule(["cat"], action="allow"),
|
|
133
|
+
prefix_rule(["rg"], action="allow"),
|
|
134
|
+
prefix_rule(["git", "status"], action="allow"),
|
|
135
|
+
]
|
|
136
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mison/ag-kit-cn",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "AI Agent templates - Skills, Agents, and Workflows for enhanced coding assistance",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,27 +23,29 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"clean": "node scripts/clean.js",
|
|
25
25
|
"clean:dry-run": "node scripts/clean.js --dry-run",
|
|
26
|
-
"health-check": "
|
|
26
|
+
"health-check": "node scripts/health-check.js",
|
|
27
27
|
"postinstall": "node scripts/postinstall-check.js",
|
|
28
|
-
"test": "node --test tests"
|
|
28
|
+
"test": "node --test \"tests/**/*.test.js\"",
|
|
29
|
+
"ci:verify": "node scripts/ci-verify.js"
|
|
29
30
|
},
|
|
30
31
|
"publishConfig": {
|
|
31
32
|
"access": "public"
|
|
32
33
|
},
|
|
33
34
|
"files": [
|
|
34
|
-
".
|
|
35
|
+
".agents/**",
|
|
35
36
|
"bin/**",
|
|
37
|
+
"scripts/clean.js",
|
|
38
|
+
"scripts/ci-verify.js",
|
|
39
|
+
"scripts/health-check.js",
|
|
40
|
+
"scripts/health-check.sh",
|
|
36
41
|
"scripts/postinstall-check.js",
|
|
42
|
+
"tests/**/*.test.js",
|
|
37
43
|
"README.md",
|
|
38
44
|
"LICENSE",
|
|
39
45
|
"CHANGELOG.md",
|
|
40
46
|
"AGENT_FLOW.md",
|
|
41
|
-
"docs/
|
|
42
|
-
"docs/
|
|
43
|
-
"docs/multi-target-adapter.md",
|
|
44
|
-
"docs/operations.md",
|
|
45
|
-
"docs/terminology-style-guide.md",
|
|
46
|
-
"docs/official/**"
|
|
47
|
+
"docs/PLAN.md",
|
|
48
|
+
"docs/TECH.md"
|
|
47
49
|
],
|
|
48
50
|
"bin": {
|
|
49
51
|
"ag-kit": "./bin/ag-kit.js"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { spawnSync } = require("node:child_process");
|
|
7
|
+
|
|
8
|
+
const REPO_ROOT = path.resolve(__dirname, "..");
|
|
9
|
+
const CLI_PATH = path.join(REPO_ROOT, "bin", "ag-kit.js");
|
|
10
|
+
|
|
11
|
+
function runCli(args, options = {}) {
|
|
12
|
+
const env = {
|
|
13
|
+
...process.env,
|
|
14
|
+
AG_KIT_SKIP_UPSTREAM_CHECK: "1",
|
|
15
|
+
...options.env,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const result = spawnSync(process.execPath, [CLI_PATH, ...args], {
|
|
19
|
+
cwd: REPO_ROOT,
|
|
20
|
+
env,
|
|
21
|
+
encoding: "utf8",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (result.status !== 0) {
|
|
25
|
+
const message = result.stderr || result.stdout || "";
|
|
26
|
+
throw new Error(`命令失败: ag-kit ${args.join(" ")}\n${message}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return result.stdout || "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function ensureExists(targetPath, label) {
|
|
33
|
+
if (!fs.existsSync(targetPath)) {
|
|
34
|
+
throw new Error(`缺少 ${label}: ${targetPath}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function main() {
|
|
39
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-ci-"));
|
|
40
|
+
const workspaceDir = path.join(tempRoot, "workspace");
|
|
41
|
+
const indexPath = path.join(tempRoot, "workspaces.json");
|
|
42
|
+
const globalRoot = path.join(tempRoot, "global-root");
|
|
43
|
+
|
|
44
|
+
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
45
|
+
|
|
46
|
+
const env = {
|
|
47
|
+
AG_KIT_INDEX_PATH: indexPath,
|
|
48
|
+
AG_KIT_GLOBAL_ROOT: globalRoot,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
runCli(["init", "--targets", "gemini,codex", "--path", workspaceDir, "--quiet"], { env });
|
|
52
|
+
|
|
53
|
+
const status = runCli(["status", "--path", workspaceDir, "--quiet"], { env }).trim();
|
|
54
|
+
if (status !== "installed") {
|
|
55
|
+
throw new Error(`status 结果异常: ${status}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
runCli(["doctor", "--path", workspaceDir, "--quiet"], { env });
|
|
59
|
+
runCli(["update", "--path", workspaceDir, "--quiet"], { env });
|
|
60
|
+
runCli(["update-all", "--dry-run", "--quiet"], { env });
|
|
61
|
+
|
|
62
|
+
runCli(["exclude", "add", "--path", workspaceDir, "--quiet"], { env });
|
|
63
|
+
const excluded = runCli(["exclude", "list", "--quiet"], { env });
|
|
64
|
+
if (!excluded.split(/\r?\n/).includes(workspaceDir)) {
|
|
65
|
+
throw new Error("exclude add 未生效");
|
|
66
|
+
}
|
|
67
|
+
runCli(["exclude", "remove", "--path", workspaceDir, "--quiet"], { env });
|
|
68
|
+
const excludedAfter = runCli(["exclude", "list", "--quiet"], { env });
|
|
69
|
+
if (excludedAfter.split(/\r?\n/).includes(workspaceDir)) {
|
|
70
|
+
throw new Error("exclude remove 未生效");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
runCli(["global", "sync", "--quiet"], { env });
|
|
74
|
+
const globalStatus = runCli(["global", "status", "--quiet"], { env }).trim();
|
|
75
|
+
if (globalStatus !== "installed") {
|
|
76
|
+
throw new Error(`global status 结果异常: ${globalStatus}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const codexSkill = path.join(globalRoot, ".codex", "skills", "workflow-plan", "SKILL.md");
|
|
80
|
+
const geminiCliSkill = path.join(globalRoot, ".gemini", "skills", "clean-code", "SKILL.md");
|
|
81
|
+
const antigravitySkill = path.join(globalRoot, ".gemini", "antigravity", "skills", "clean-code", "SKILL.md");
|
|
82
|
+
ensureExists(codexSkill, "全局 Codex workflow-plan Skill");
|
|
83
|
+
ensureExists(geminiCliSkill, "全局 Gemini CLI clean-code Skill");
|
|
84
|
+
ensureExists(antigravitySkill, "全局 Antigravity clean-code Skill");
|
|
85
|
+
|
|
86
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
main();
|
|
91
|
+
console.log("✅ CI 全链路演练通过");
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error(`❌ ${err.message}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
package/scripts/clean.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const DEFAULT_RELATIVE_TARGETS = [
|
|
7
|
+
".temp_ag_kit",
|
|
8
|
+
"coverage",
|
|
9
|
+
"web/.next",
|
|
10
|
+
"web/node_modules",
|
|
11
|
+
"web/out",
|
|
12
|
+
"web/.turbo",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
function parseArgs(argv) {
|
|
16
|
+
const options = {
|
|
17
|
+
dryRun: false,
|
|
18
|
+
quiet: false,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
for (const arg of argv) {
|
|
22
|
+
if (arg === "--dry-run") {
|
|
23
|
+
options.dryRun = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === "--quiet") {
|
|
27
|
+
options.quiet = true;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (arg === "--help" || arg === "-h") {
|
|
31
|
+
options.help = true;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`未知参数: ${arg}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return options;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function removeTarget(rootDir, relativePath, options) {
|
|
41
|
+
const absolutePath = path.join(rootDir, relativePath);
|
|
42
|
+
const exists = fs.existsSync(absolutePath);
|
|
43
|
+
const result = {
|
|
44
|
+
path: relativePath,
|
|
45
|
+
absolutePath,
|
|
46
|
+
action: "skipped",
|
|
47
|
+
reason: "",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (!exists) {
|
|
51
|
+
result.reason = "not_found";
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.dryRun) {
|
|
56
|
+
result.action = "would_remove";
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fs.rmSync(absolutePath, { recursive: true, force: true });
|
|
61
|
+
result.action = "removed";
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function runClean(options = {}) {
|
|
66
|
+
const rootDir = path.resolve(options.rootDir || path.join(__dirname, ".."));
|
|
67
|
+
const targets = Array.isArray(options.targets) && options.targets.length > 0
|
|
68
|
+
? options.targets
|
|
69
|
+
: DEFAULT_RELATIVE_TARGETS;
|
|
70
|
+
|
|
71
|
+
const normalizedOptions = {
|
|
72
|
+
dryRun: Boolean(options.dryRun),
|
|
73
|
+
quiet: Boolean(options.quiet),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const results = targets.map((targetPath) => removeTarget(rootDir, targetPath, normalizedOptions));
|
|
77
|
+
const removedCount = results.filter((item) => item.action === "removed").length;
|
|
78
|
+
const wouldRemoveCount = results.filter((item) => item.action === "would_remove").length;
|
|
79
|
+
const skippedCount = results.filter((item) => item.action === "skipped").length;
|
|
80
|
+
|
|
81
|
+
if (!normalizedOptions.quiet) {
|
|
82
|
+
for (const item of results) {
|
|
83
|
+
if (item.action === "removed") {
|
|
84
|
+
console.log(`🧹 已清理: ${item.path}`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (item.action === "would_remove") {
|
|
88
|
+
console.log(`[dry-run] 将清理: ${item.path}`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
console.log(`⏭️ 已跳过: ${item.path} (${item.reason})`);
|
|
92
|
+
}
|
|
93
|
+
console.log(`📊 清理完成: removed=${removedCount}, dryRun=${wouldRemoveCount}, skipped=${skippedCount}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
rootDir,
|
|
98
|
+
removedCount,
|
|
99
|
+
wouldRemoveCount,
|
|
100
|
+
skippedCount,
|
|
101
|
+
results,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (require.main === module) {
|
|
106
|
+
try {
|
|
107
|
+
const options = parseArgs(process.argv.slice(2));
|
|
108
|
+
if (options.help) {
|
|
109
|
+
console.log("用法: node scripts/clean.js [--dry-run] [--quiet]");
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
runClean(options);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error(`❌ ${err.message}`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
DEFAULT_RELATIVE_TARGETS,
|
|
121
|
+
parseArgs,
|
|
122
|
+
runClean,
|
|
123
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { spawnSync } = require("node:child_process");
|
|
7
|
+
|
|
8
|
+
const ROOT_DIR = path.resolve(__dirname, "..");
|
|
9
|
+
|
|
10
|
+
function logStep(message) {
|
|
11
|
+
console.log(`[health-check] ${message}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function runCommand(command, options = {}) {
|
|
15
|
+
const result = spawnSync(command, {
|
|
16
|
+
cwd: options.cwd || ROOT_DIR,
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
...options.env,
|
|
20
|
+
},
|
|
21
|
+
encoding: "utf8",
|
|
22
|
+
shell: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (result.status !== 0) {
|
|
26
|
+
const detail = result.stderr || result.stdout || "";
|
|
27
|
+
throw new Error(`${command}\n${detail}`.trim());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result.stdout || "";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function commandExists(command) {
|
|
34
|
+
const probe = spawnSync(command, {
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
shell: true,
|
|
37
|
+
stdio: "ignore",
|
|
38
|
+
});
|
|
39
|
+
return probe.status === 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function main() {
|
|
43
|
+
logStep("检查运行环境");
|
|
44
|
+
if (!commandExists("node --version")) {
|
|
45
|
+
throw new Error("缺少命令: node");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const packageRunner = commandExists("bun --version") ? "bun" : "npm";
|
|
49
|
+
if (!commandExists(`${packageRunner} --version`)) {
|
|
50
|
+
throw new Error(`缺少命令: ${packageRunner}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
logStep("执行测试套件");
|
|
54
|
+
if (packageRunner === "bun") {
|
|
55
|
+
runCommand("bun run test");
|
|
56
|
+
} else {
|
|
57
|
+
runCommand("npm test --silent");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
logStep("验证 CLI 核心链路");
|
|
61
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-health-check-"));
|
|
62
|
+
try {
|
|
63
|
+
const workspaceDir = path.join(tempRoot, "workspace");
|
|
64
|
+
const indexPath = path.join(tempRoot, "workspaces.json");
|
|
65
|
+
const globalRoot = path.join(tempRoot, "global-root");
|
|
66
|
+
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
67
|
+
|
|
68
|
+
const env = {
|
|
69
|
+
AG_KIT_INDEX_PATH: indexPath,
|
|
70
|
+
AG_KIT_GLOBAL_ROOT: globalRoot,
|
|
71
|
+
AG_KIT_SKIP_UPSTREAM_CHECK: "1",
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
runCommand(`node bin/ag-kit.js init --targets gemini,codex --path "${workspaceDir}" --quiet`, { env });
|
|
75
|
+
|
|
76
|
+
const status = runCommand(`node bin/ag-kit.js status --path "${workspaceDir}" --quiet`, { env }).trim();
|
|
77
|
+
if (status !== "installed") {
|
|
78
|
+
throw new Error(`status 结果异常: ${status}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
runCommand(`node bin/ag-kit.js doctor --path "${workspaceDir}" --quiet`, { env });
|
|
82
|
+
runCommand(`node bin/ag-kit.js update --path "${workspaceDir}" --quiet`, { env });
|
|
83
|
+
runCommand("node bin/ag-kit.js update-all --dry-run --quiet", { env });
|
|
84
|
+
runCommand(`node bin/ag-kit.js exclude add --path "${workspaceDir}" --quiet`, { env });
|
|
85
|
+
|
|
86
|
+
const excluded = runCommand("node bin/ag-kit.js exclude list --quiet", { env });
|
|
87
|
+
if (!excluded.split(/\r?\n/).includes(workspaceDir)) {
|
|
88
|
+
throw new Error("exclude add 未生效");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
runCommand(`node bin/ag-kit.js exclude remove --path "${workspaceDir}" --quiet`, { env });
|
|
92
|
+
const excludedAfter = runCommand("node bin/ag-kit.js exclude list --quiet", { env });
|
|
93
|
+
if (excludedAfter.split(/\r?\n/).includes(workspaceDir)) {
|
|
94
|
+
throw new Error("exclude remove 未生效");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
runCommand("node bin/ag-kit.js global sync --quiet", { env });
|
|
98
|
+
const globalStatus = runCommand("node bin/ag-kit.js global status --quiet", { env }).trim();
|
|
99
|
+
if (globalStatus !== "installed") {
|
|
100
|
+
throw new Error(`global status 结果异常: ${globalStatus}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const globalChecks = [
|
|
104
|
+
path.join(globalRoot, ".codex", "skills", "workflow-plan", "SKILL.md"),
|
|
105
|
+
path.join(globalRoot, ".gemini", "skills", "clean-code", "SKILL.md"),
|
|
106
|
+
path.join(globalRoot, ".gemini", "antigravity", "skills", "clean-code", "SKILL.md"),
|
|
107
|
+
];
|
|
108
|
+
for (const targetPath of globalChecks) {
|
|
109
|
+
if (!fs.existsSync(targetPath)) {
|
|
110
|
+
throw new Error(`global sync 未生成预期文件: ${targetPath}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} finally {
|
|
114
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
logStep("执行清理预检");
|
|
118
|
+
if (packageRunner === "bun") {
|
|
119
|
+
runCommand("bun run clean:dry-run");
|
|
120
|
+
} else {
|
|
121
|
+
runCommand("npm run clean:dry-run --silent");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log("✅ 健康检查通过");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
main();
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error(`❌ ${err.message}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|