@mison/ag-kit-cn 2.0.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 (237) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  28. package/.agent/ARCHITECTURE.md +285 -0
  29. package/.agent/agents/backend-specialist.md +268 -0
  30. package/.agent/agents/code-archaeologist.md +106 -0
  31. package/.agent/agents/database-architect.md +225 -0
  32. package/.agent/agents/debugger.md +225 -0
  33. package/.agent/agents/devops-engineer.md +242 -0
  34. package/.agent/agents/documentation-writer.md +104 -0
  35. package/.agent/agents/explorer-agent.md +73 -0
  36. package/.agent/agents/frontend-specialist.md +618 -0
  37. package/.agent/agents/game-developer.md +162 -0
  38. package/.agent/agents/mobile-developer.md +382 -0
  39. package/.agent/agents/orchestrator.md +438 -0
  40. package/.agent/agents/penetration-tester.md +188 -0
  41. package/.agent/agents/performance-optimizer.md +187 -0
  42. package/.agent/agents/product-manager.md +112 -0
  43. package/.agent/agents/product-owner.md +95 -0
  44. package/.agent/agents/project-planner.md +405 -0
  45. package/.agent/agents/qa-automation-engineer.md +103 -0
  46. package/.agent/agents/security-auditor.md +170 -0
  47. package/.agent/agents/seo-specialist.md +111 -0
  48. package/.agent/agents/test-engineer.md +158 -0
  49. package/.agent/mcp_config.json +12 -0
  50. package/.agent/rules/GEMINI.md +273 -0
  51. package/.agent/scripts/auto_preview.py +148 -0
  52. package/.agent/scripts/checklist.py +217 -0
  53. package/.agent/scripts/session_manager.py +120 -0
  54. package/.agent/scripts/verify_all.py +327 -0
  55. package/.agent/skills/api-patterns/SKILL.md +84 -0
  56. package/.agent/skills/api-patterns/api-style.md +42 -0
  57. package/.agent/skills/api-patterns/auth.md +24 -0
  58. package/.agent/skills/api-patterns/documentation.md +26 -0
  59. package/.agent/skills/api-patterns/graphql.md +41 -0
  60. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  61. package/.agent/skills/api-patterns/response.md +37 -0
  62. package/.agent/skills/api-patterns/rest.md +40 -0
  63. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  64. package/.agent/skills/api-patterns/security-testing.md +122 -0
  65. package/.agent/skills/api-patterns/trpc.md +41 -0
  66. package/.agent/skills/api-patterns/versioning.md +22 -0
  67. package/.agent/skills/app-builder/SKILL.md +75 -0
  68. package/.agent/skills/app-builder/agent-coordination.md +74 -0
  69. package/.agent/skills/app-builder/feature-building.md +53 -0
  70. package/.agent/skills/app-builder/project-detection.md +34 -0
  71. package/.agent/skills/app-builder/scaffolding.md +118 -0
  72. package/.agent/skills/app-builder/tech-stack.md +40 -0
  73. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  74. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  75. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  76. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  77. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  78. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  79. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  80. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  81. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  82. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  83. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  84. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  85. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  86. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  87. package/.agent/skills/architecture/SKILL.md +57 -0
  88. package/.agent/skills/architecture/context-discovery.md +43 -0
  89. package/.agent/skills/architecture/examples.md +94 -0
  90. package/.agent/skills/architecture/pattern-selection.md +68 -0
  91. package/.agent/skills/architecture/patterns-reference.md +50 -0
  92. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  93. package/.agent/skills/bash-linux/SKILL.md +201 -0
  94. package/.agent/skills/behavioral-modes/SKILL.md +264 -0
  95. package/.agent/skills/brainstorming/SKILL.md +164 -0
  96. package/.agent/skills/brainstorming/dynamic-questioning.md +359 -0
  97. package/.agent/skills/clean-code/SKILL.md +200 -0
  98. package/.agent/skills/code-review-checklist/SKILL.md +125 -0
  99. package/.agent/skills/database-design/SKILL.md +54 -0
  100. package/.agent/skills/database-design/database-selection.md +43 -0
  101. package/.agent/skills/database-design/indexing.md +39 -0
  102. package/.agent/skills/database-design/migrations.md +50 -0
  103. package/.agent/skills/database-design/optimization.md +36 -0
  104. package/.agent/skills/database-design/orm-selection.md +30 -0
  105. package/.agent/skills/database-design/schema-design.md +56 -0
  106. package/.agent/skills/database-design/scripts/schema_validator.py +172 -0
  107. package/.agent/skills/deployment-procedures/SKILL.md +241 -0
  108. package/.agent/skills/doc.md +177 -0
  109. package/.agent/skills/documentation-templates/SKILL.md +194 -0
  110. package/.agent/skills/frontend-design/SKILL.md +418 -0
  111. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  112. package/.agent/skills/frontend-design/color-system.md +307 -0
  113. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  114. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  115. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  116. package/.agent/skills/frontend-design/scripts/ux_audit.py +727 -0
  117. package/.agent/skills/frontend-design/typography-system.md +345 -0
  118. package/.agent/skills/frontend-design/ux-psychology.md +1118 -0
  119. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  120. package/.agent/skills/game-development/2d-games/SKILL.md +119 -0
  121. package/.agent/skills/game-development/3d-games/SKILL.md +135 -0
  122. package/.agent/skills/game-development/SKILL.md +167 -0
  123. package/.agent/skills/game-development/game-art/SKILL.md +185 -0
  124. package/.agent/skills/game-development/game-audio/SKILL.md +190 -0
  125. package/.agent/skills/game-development/game-design/SKILL.md +129 -0
  126. package/.agent/skills/game-development/mobile-games/SKILL.md +108 -0
  127. package/.agent/skills/game-development/multiplayer/SKILL.md +132 -0
  128. package/.agent/skills/game-development/pc-games/SKILL.md +144 -0
  129. package/.agent/skills/game-development/vr-ar/SKILL.md +123 -0
  130. package/.agent/skills/game-development/web-games/SKILL.md +150 -0
  131. package/.agent/skills/geo-fundamentals/SKILL.md +155 -0
  132. package/.agent/skills/geo-fundamentals/scripts/geo_checker.py +289 -0
  133. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  134. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  135. package/.agent/skills/intelligent-routing/SKILL.md +335 -0
  136. package/.agent/skills/lint-and-validate/SKILL.md +44 -0
  137. package/.agent/skills/lint-and-validate/scripts/lint_runner.py +184 -0
  138. package/.agent/skills/lint-and-validate/scripts/type_coverage.py +173 -0
  139. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  140. package/.agent/skills/mobile-design/SKILL.md +394 -0
  141. package/.agent/skills/mobile-design/decision-trees.md +516 -0
  142. package/.agent/skills/mobile-design/mobile-backend.md +491 -0
  143. package/.agent/skills/mobile-design/mobile-color-system.md +420 -0
  144. package/.agent/skills/mobile-design/mobile-debugging.md +122 -0
  145. package/.agent/skills/mobile-design/mobile-design-thinking.md +355 -0
  146. package/.agent/skills/mobile-design/mobile-navigation.md +458 -0
  147. package/.agent/skills/mobile-design/mobile-performance.md +767 -0
  148. package/.agent/skills/mobile-design/mobile-testing.md +356 -0
  149. package/.agent/skills/mobile-design/mobile-typography.md +432 -0
  150. package/.agent/skills/mobile-design/platform-android.md +666 -0
  151. package/.agent/skills/mobile-design/platform-ios.md +561 -0
  152. package/.agent/skills/mobile-design/scripts/mobile_audit.py +670 -0
  153. package/.agent/skills/mobile-design/touch-psychology.md +537 -0
  154. package/.agent/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +311 -0
  155. package/.agent/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +241 -0
  156. package/.agent/skills/nextjs-react-expert/3-server-server-side-performance.md +489 -0
  157. package/.agent/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +263 -0
  158. package/.agent/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +581 -0
  159. package/.agent/skills/nextjs-react-expert/6-rendering-rendering-performance.md +431 -0
  160. package/.agent/skills/nextjs-react-expert/7-js-javascript-performance.md +683 -0
  161. package/.agent/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +149 -0
  162. package/.agent/skills/nextjs-react-expert/SKILL.md +286 -0
  163. package/.agent/skills/nextjs-react-expert/scripts/convert_rules.py +222 -0
  164. package/.agent/skills/nextjs-react-expert/scripts/react_performance_checker.py +252 -0
  165. package/.agent/skills/nodejs-best-practices/SKILL.md +333 -0
  166. package/.agent/skills/parallel-agents/SKILL.md +194 -0
  167. package/.agent/skills/performance-profiling/SKILL.md +149 -0
  168. package/.agent/skills/performance-profiling/scripts/lighthouse_audit.py +76 -0
  169. package/.agent/skills/plan-writing/SKILL.md +152 -0
  170. package/.agent/skills/powershell-windows/SKILL.md +166 -0
  171. package/.agent/skills/python-patterns/SKILL.md +441 -0
  172. package/.agent/skills/red-team-tactics/SKILL.md +203 -0
  173. package/.agent/skills/rust-pro/SKILL.md +190 -0
  174. package/.agent/skills/seo-fundamentals/SKILL.md +135 -0
  175. package/.agent/skills/seo-fundamentals/scripts/seo_checker.py +215 -0
  176. package/.agent/skills/server-management/SKILL.md +161 -0
  177. package/.agent/skills/systematic-debugging/SKILL.md +114 -0
  178. package/.agent/skills/tailwind-patterns/SKILL.md +269 -0
  179. package/.agent/skills/tdd-workflow/SKILL.md +149 -0
  180. package/.agent/skills/testing-patterns/SKILL.md +178 -0
  181. package/.agent/skills/testing-patterns/scripts/test_runner.py +219 -0
  182. package/.agent/skills/vulnerability-scanner/SKILL.md +276 -0
  183. package/.agent/skills/vulnerability-scanner/checklists.md +131 -0
  184. package/.agent/skills/vulnerability-scanner/scripts/security_scan.py +459 -0
  185. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  186. package/.agent/skills/webapp-testing/SKILL.md +187 -0
  187. package/.agent/skills/webapp-testing/scripts/playwright_runner.py +173 -0
  188. package/.agent/workflows/brainstorm.md +113 -0
  189. package/.agent/workflows/create.md +59 -0
  190. package/.agent/workflows/debug.md +103 -0
  191. package/.agent/workflows/deploy.md +176 -0
  192. package/.agent/workflows/enhance.md +63 -0
  193. package/.agent/workflows/orchestrate.md +242 -0
  194. package/.agent/workflows/plan.md +89 -0
  195. package/.agent/workflows/preview.md +80 -0
  196. package/.agent/workflows/restore-localize-compat.md +525 -0
  197. package/.agent/workflows/status.md +86 -0
  198. package/.agent/workflows/test.md +144 -0
  199. package/.agent/workflows/ui-ux-pro-max.md +295 -0
  200. package/AGENT_FLOW.md +609 -0
  201. package/CHANGELOG.md +68 -0
  202. package/LICENSE +21 -0
  203. package/README.md +260 -0
  204. package/bin/adapters/base.js +63 -0
  205. package/bin/adapters/codex.js +391 -0
  206. package/bin/adapters/gemini.js +137 -0
  207. package/bin/ag-kit.js +1336 -0
  208. package/bin/core/builder.js +80 -0
  209. package/bin/core/generator.js +59 -0
  210. package/bin/core/resource-loader.js +64 -0
  211. package/bin/core/transformer.js +208 -0
  212. package/bin/interactive.js +65 -0
  213. package/bin/utils/atomic-writer.js +97 -0
  214. package/bin/utils/git-helper.js +68 -0
  215. package/bin/utils/managed-block.js +65 -0
  216. package/bin/utils/manifest.js +241 -0
  217. package/bin/utils.js +82 -0
  218. package/docs/codex-rules-template.md +36 -0
  219. package/docs/mapping-spec.md +68 -0
  220. package/docs/multi-target-adapter.md +80 -0
  221. package/docs/official/README.md +53 -0
  222. package/docs/official/antigravity/agent-modes-settings.md +64 -0
  223. package/docs/official/antigravity/rules-workflows.md +96 -0
  224. package/docs/official/antigravity/skills.md +147 -0
  225. package/docs/official/codex/agents-md.md +119 -0
  226. package/docs/official/codex/config-advanced.md +358 -0
  227. package/docs/official/codex/config-basic.md +141 -0
  228. package/docs/official/codex/config-reference.md +223 -0
  229. package/docs/official/codex/config-sample.md +216 -0
  230. package/docs/official/codex/mcp.md +107 -0
  231. package/docs/official/codex/rules.md +79 -0
  232. package/docs/official/codex/skills.md +114 -0
  233. package/docs/official/sources-index.md +32 -0
  234. package/docs/operations.md +145 -0
  235. package/docs/terminology-style-guide.md +69 -0
  236. package/package.json +51 -0
  237. package/scripts/postinstall-check.js +112 -0
@@ -0,0 +1,80 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const os = require("os");
4
+ const ResourceLoader = require("./resource-loader");
5
+ const ResourceTransformer = require("./transformer");
6
+ const RuleGenerator = require("./generator");
7
+ const pkg = require("../../package.json");
8
+
9
+ class CodexBuilder {
10
+ /**
11
+ * Build a Codex structure from a legacy/source repository
12
+ * @param {string} sourceRoot Root of the repo (containing .agent/)
13
+ * @param {string} outputDir Directory to output the built .agents-compatible structure
14
+ */
15
+ static build(sourceRoot, outputDir) {
16
+ if (fs.existsSync(outputDir)) {
17
+ fs.rmSync(outputDir, { recursive: true, force: true });
18
+ }
19
+ fs.mkdirSync(outputDir, { recursive: true });
20
+
21
+ // 1. Load Resources
22
+ const loader = new ResourceLoader(sourceRoot);
23
+ const resources = loader.loadAll();
24
+
25
+ // 2. Transform
26
+ const transformResult = ResourceTransformer.transform(resources);
27
+
28
+ // 3. Execute File/Dir Copying based on Transform Map
29
+ for (const map of transformResult.mappedFiles) {
30
+ const dest = path.join(outputDir, map.destPath);
31
+ const destParent = path.dirname(dest);
32
+
33
+ if (!fs.existsSync(destParent)) {
34
+ fs.mkdirSync(destParent, { recursive: true });
35
+ }
36
+
37
+ if (map.isDir) {
38
+ // Recursive copy
39
+ CodexBuilder._copyDir(map.src, dest);
40
+ } else if (typeof map.content === "string") {
41
+ fs.writeFileSync(dest, map.content);
42
+ } else {
43
+ if (fs.existsSync(map.src)) {
44
+ fs.copyFileSync(map.src, dest);
45
+ }
46
+ }
47
+ }
48
+
49
+ // 4. Generate & Write Metadata
50
+ const { agentsMd, antigravityRules, codexJson } = RuleGenerator.generate(transformResult, pkg.version);
51
+
52
+ fs.writeFileSync(path.join(outputDir, "codex.json"), `${JSON.stringify(codexJson, null, 2)}\n`);
53
+ fs.writeFileSync(path.join(outputDir, "AGENTS.md"), `${agentsMd}\n`);
54
+ fs.writeFileSync(path.join(outputDir, "antigravity.rules"), `${antigravityRules}\n`);
55
+
56
+ return {
57
+ outputDir,
58
+ stats: {
59
+ skills: resources.skills.length,
60
+ workflows: resources.workflows.length
61
+ }
62
+ };
63
+ }
64
+
65
+ static _copyDir(src, dest) {
66
+ fs.mkdirSync(dest, { recursive: true });
67
+ const entries = fs.readdirSync(src, { withFileTypes: true });
68
+ for (const entry of entries) {
69
+ const srcPath = path.join(src, entry.name);
70
+ const destPath = path.join(dest, entry.name);
71
+ if (entry.isDirectory()) {
72
+ CodexBuilder._copyDir(srcPath, destPath);
73
+ } else {
74
+ fs.copyFileSync(srcPath, destPath);
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ module.exports = CodexBuilder;
@@ -0,0 +1,59 @@
1
+ class RuleGenerator {
2
+ /**
3
+ * Generate content for AGENTS.md, antigravity.rules and codex.json
4
+ * @param {object} transformResult Result from Transformer
5
+ * @returns {object} { agentsMd: string, antigravityRules: string, codexJson: object }
6
+ */
7
+ static generate(transformResult, version) {
8
+ if (typeof version !== "string" || version.trim() === "") {
9
+ throw new Error("RuleGenerator.generate 需要显式传入版本号");
10
+ }
11
+ const { metadata } = transformResult;
12
+
13
+ // 1. Generate codex.json
14
+ const codexJson = {
15
+ version: version,
16
+ updatedAt: new Date().toISOString(),
17
+ skills: metadata.map(m => ({
18
+ id: m.id,
19
+ originalName: m.originalName,
20
+ path: m.path
21
+ }))
22
+ };
23
+
24
+ // 2. Generate AGENTS.md managed section content
25
+ let agentsMd = `# AI Agent Capabilities (Codex Managed)\n\n`;
26
+ agentsMd += `> **Auto-generated by Antigravity Kit (Codex)**\n`;
27
+ agentsMd += `> Version: ${version}\n\n`;
28
+
29
+ agentsMd += `## Available Skills\n\n`;
30
+
31
+ for (const meta of metadata) {
32
+ agentsMd += `- **${meta.id}** (${meta.type})\n`;
33
+ agentsMd += ` - Path: \`${meta.path}\`\n`;
34
+ }
35
+
36
+ agentsMd += `\n## Usage Rules\n\n`;
37
+ agentsMd += `1. Managed resources are synchronized under \`.agents/skills\`.\n`;
38
+ agentsMd += `2. Do not rename managed skill folders manually.\n`;
39
+ agentsMd += `3. Use \`ag-kit doctor --target codex --fix\` to recover missing managed artifacts.\n`;
40
+
41
+ // 3. Generate risk controls
42
+ let antigravityRules = `# Antigravity Risk Controls (Codex Managed)\n\n`;
43
+ antigravityRules += `version: ${version}\n`;
44
+ antigravityRules += `generated_at: ${new Date().toISOString()}\n\n`;
45
+ antigravityRules += `## Controls\n`;
46
+ antigravityRules += `- Managed skills are stored under \`.agents/skills\`.\n`;
47
+ antigravityRules += `- Keep generated skill IDs stable to avoid selector drift.\n`;
48
+ antigravityRules += `- If integrity checks fail, run \`ag-kit doctor --target codex --fix\`.\n`;
49
+ antigravityRules += `- Before destructive updates, preserve manual edits in source control.\n`;
50
+
51
+ return {
52
+ agentsMd,
53
+ antigravityRules,
54
+ codexJson
55
+ };
56
+ }
57
+ }
58
+
59
+ module.exports = RuleGenerator;
@@ -0,0 +1,64 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ class ResourceLoader {
5
+ constructor(rootDir) {
6
+ this.rootDir = rootDir;
7
+ this.skillsDir = path.join(rootDir, ".agent", "skills");
8
+ this.workflowsDir = path.join(rootDir, ".agent", "workflows");
9
+ }
10
+
11
+ /**
12
+ * Load all skills and workflows
13
+ */
14
+ loadAll() {
15
+ return {
16
+ skills: this.loadSkills(),
17
+ workflows: this.loadWorkflows()
18
+ };
19
+ }
20
+
21
+ loadSkills() {
22
+ if (!fs.existsSync(this.skillsDir)) return [];
23
+
24
+ const skills = [];
25
+ const entries = fs.readdirSync(this.skillsDir, { withFileTypes: true });
26
+
27
+ for (const entry of entries) {
28
+ if (entry.isDirectory()) {
29
+ const skillPath = path.join(this.skillsDir, entry.name);
30
+ const skillFile = path.join(skillPath, "SKILL.md");
31
+
32
+ if (fs.existsSync(skillFile)) {
33
+ skills.push({
34
+ name: entry.name,
35
+ path: skillPath,
36
+ entryFile: "SKILL.md", // Relative to skillPath
37
+ type: "skill"
38
+ });
39
+ }
40
+ }
41
+ }
42
+ return skills;
43
+ }
44
+
45
+ loadWorkflows() {
46
+ if (!fs.existsSync(this.workflowsDir)) return [];
47
+
48
+ const workflows = [];
49
+ const entries = fs.readdirSync(this.workflowsDir, { withFileTypes: true });
50
+
51
+ for (const entry of entries) {
52
+ if (entry.isFile() && entry.name.endsWith(".md")) {
53
+ workflows.push({
54
+ name: path.basename(entry.name, ".md"),
55
+ path: path.join(this.workflowsDir, entry.name),
56
+ type: "workflow"
57
+ });
58
+ }
59
+ }
60
+ return workflows;
61
+ }
62
+ }
63
+
64
+ module.exports = ResourceLoader;
@@ -0,0 +1,208 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ class ResourceTransformer {
5
+ /**
6
+ * Transform raw resources into Codex-compatible structure
7
+ * @param {object} resources { skills: [], workflows: [] }
8
+ * @returns {object} { mappedFiles: [], metadata: [] }
9
+ */
10
+ static transform(resources) {
11
+ const result = {
12
+ mappedFiles: [], // List of { src, destPath }
13
+ metadata: [] // List of desc for rules
14
+ };
15
+ const usedIds = new Set();
16
+
17
+ function allocateUniqueId(baseId) {
18
+ let candidate = baseId;
19
+ let suffix = 2;
20
+ while (usedIds.has(candidate)) {
21
+ candidate = `${baseId}-${suffix}`;
22
+ suffix += 1;
23
+ }
24
+ usedIds.add(candidate);
25
+ return candidate;
26
+ }
27
+
28
+ function stripWrappingQuotes(value) {
29
+ const trimmed = String(value || "").trim();
30
+ if ((trimmed.startsWith("\"") && trimmed.endsWith("\"")) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
31
+ return trimmed.slice(1, -1);
32
+ }
33
+ return trimmed;
34
+ }
35
+
36
+ function foldYamlBlock(lines) {
37
+ const paragraphs = [];
38
+ let current = [];
39
+
40
+ for (const line of lines) {
41
+ const trimmed = line.trim();
42
+ if (!trimmed) {
43
+ if (current.length > 0) {
44
+ paragraphs.push(current.join(" "));
45
+ current = [];
46
+ }
47
+ continue;
48
+ }
49
+ current.push(trimmed);
50
+ }
51
+
52
+ if (current.length > 0) {
53
+ paragraphs.push(current.join(" "));
54
+ }
55
+
56
+ return paragraphs.join("\n");
57
+ }
58
+
59
+ function collectIndentedLines(lines, startIndex) {
60
+ const collected = [];
61
+ let idx = startIndex;
62
+ let baseIndent = -1;
63
+
64
+ while (idx < lines.length) {
65
+ const line = lines[idx];
66
+ if (line.trim() === "") {
67
+ if (collected.length > 0) {
68
+ collected.push("");
69
+ }
70
+ idx += 1;
71
+ continue;
72
+ }
73
+
74
+ const indentMatch = line.match(/^(\s+)/);
75
+ if (!indentMatch) {
76
+ break;
77
+ }
78
+
79
+ const indentLength = indentMatch[1].length;
80
+ if (baseIndent < 0) {
81
+ baseIndent = indentLength;
82
+ }
83
+ if (indentLength < baseIndent) {
84
+ break;
85
+ }
86
+
87
+ collected.push(line.slice(baseIndent));
88
+ idx += 1;
89
+ }
90
+
91
+ return { lines: collected, nextIndex: idx - 1 };
92
+ }
93
+
94
+ function parseFrontmatter(content) {
95
+ const normalized = String(content || "").replace(/\r\n?/g, "\n");
96
+ if (!normalized.startsWith("---\n")) {
97
+ return { frontmatter: {}, body: normalized };
98
+ }
99
+
100
+ const match = normalized.match(/^---\n([\s\S]*?)\n---(?:\n|$)/);
101
+ if (!match) {
102
+ return { frontmatter: {}, body: normalized };
103
+ }
104
+
105
+ const fmRaw = match[1];
106
+ const frontmatter = {};
107
+ const lines = fmRaw.split("\n");
108
+
109
+ for (let i = 0; i < lines.length; i++) {
110
+ const line = lines[i];
111
+ const keyMatch = line.match(/^([A-Za-z0-9_-]+)\s*:\s*(.*)$/);
112
+ if (!keyMatch) continue;
113
+
114
+ const key = keyMatch[1];
115
+ const inlineValue = keyMatch[2];
116
+ if (!key) continue;
117
+
118
+ if (inlineValue === "|" || inlineValue === ">") {
119
+ const block = collectIndentedLines(lines, i + 1);
120
+ i = Math.max(i, block.nextIndex);
121
+ frontmatter[key] = inlineValue === ">"
122
+ ? foldYamlBlock(block.lines)
123
+ : block.lines.join("\n").trim();
124
+ continue;
125
+ }
126
+
127
+ if (inlineValue.trim() === "") {
128
+ const block = collectIndentedLines(lines, i + 1);
129
+ if (block.lines.length > 0) {
130
+ i = Math.max(i, block.nextIndex);
131
+ frontmatter[key] = block.lines.join("\n").trim();
132
+ } else {
133
+ frontmatter[key] = "";
134
+ }
135
+ continue;
136
+ }
137
+
138
+ frontmatter[key] = stripWrappingQuotes(inlineValue);
139
+ }
140
+
141
+ const body = normalized.slice(match[0].length);
142
+ return { frontmatter, body };
143
+ }
144
+
145
+ // 1. Process Skills
146
+ // Strategy: Skill folder -> skills/<name>/SKILL.md
147
+ for (const skill of resources.skills) {
148
+ const codexName = allocateUniqueId(skill.name);
149
+ const destDir = `skills/${codexName}`;
150
+
151
+ // Keep the full skill folder to preserve resources/scripts exactly.
152
+ result.mappedFiles.push({
153
+ src: skill.path, // The folder
154
+ destPath: destDir,
155
+ isDir: true
156
+ });
157
+
158
+ result.metadata.push({
159
+ id: codexName,
160
+ originalName: skill.name,
161
+ type: "skill",
162
+ path: `${destDir}/SKILL.md`
163
+ });
164
+ }
165
+
166
+ // 2. Process Workflows
167
+ // Codex only understands skills. Convert each workflow markdown to a valid SKILL.md.
168
+ for (const workflow of resources.workflows) {
169
+ const codexName = allocateUniqueId(`workflow-${workflow.name}`);
170
+ const destDir = `skills/${codexName}`;
171
+
172
+ const rawWorkflow = fs.existsSync(workflow.path)
173
+ ? fs.readFileSync(workflow.path, "utf8")
174
+ : "";
175
+ const parsed = parseFrontmatter(rawWorkflow);
176
+ const descriptionRaw = parsed.frontmatter.description
177
+ || `Antigravity workflow bridge for /${workflow.name}`;
178
+ const description = JSON.stringify(String(descriptionRaw).replace(/\s+/g, " ").trim());
179
+
180
+ const generatedSkill = [
181
+ "---",
182
+ `name: ${codexName}`,
183
+ `description: ${description}`,
184
+ "---",
185
+ "",
186
+ parsed.body.trimStart(),
187
+ "",
188
+ ].join("\n");
189
+
190
+ result.mappedFiles.push({
191
+ content: generatedSkill,
192
+ destPath: `${destDir}/SKILL.md`,
193
+ isDir: false
194
+ });
195
+
196
+ result.metadata.push({
197
+ id: codexName,
198
+ originalName: workflow.name,
199
+ type: "workflow-as-skill",
200
+ path: `${destDir}/SKILL.md`
201
+ });
202
+ }
203
+
204
+ return result;
205
+ }
206
+ }
207
+
208
+ module.exports = ResourceTransformer;
@@ -0,0 +1,65 @@
1
+ const readline = require("readline");
2
+
3
+ function createInterface() {
4
+ return readline.createInterface({
5
+ input: process.stdin,
6
+ output: process.stdout,
7
+ });
8
+ }
9
+
10
+ function askQuestion(rl, query) {
11
+ return new Promise((resolve) => {
12
+ rl.question(query, (answer) => {
13
+ resolve(answer);
14
+ });
15
+ });
16
+ }
17
+
18
+ /**
19
+ * Prompt user to select targets from a list.
20
+ * Supports multiple selection by comma separated numbers or names.
21
+ * Currently simplified for 'gemini' and 'codex'.
22
+ * @param {object} options CLI options
23
+ * @returns {Promise<string[]>} List of selected targets
24
+ */
25
+ async function selectTargets(options) {
26
+ if (options.nonInteractive) {
27
+ throw new Error("非交互模式下必须通过 --target 或 --targets 指定目标");
28
+ }
29
+
30
+ const rl = createInterface();
31
+
32
+ try {
33
+ console.log("\n🎯 请选择要安装的目标 (多选请用逗号分隔):");
34
+ console.log(" 1. Gemini (适用于 Cursor/VSCode)");
35
+ console.log(" 2. Codex (兼容性增强版)");
36
+
37
+ const answer = await askQuestion(rl, "\n请输入序号或名称(必填): ");
38
+ const input = answer.trim();
39
+
40
+ if (!input) {
41
+ throw new Error("必须选择至少一个目标");
42
+ }
43
+
44
+ const selection = [];
45
+ const parts = input.split(/[,,\s]+/);
46
+
47
+ for (const part of parts) {
48
+ const p = part.toLowerCase();
49
+ if (p === "1" || p === "gemini") selection.push("gemini");
50
+ else if (p === "2" || p === "codex") selection.push("codex");
51
+ }
52
+
53
+ if (selection.length === 0) {
54
+ throw new Error("无效的目标选择,请输入 1 / 2 / gemini / codex(可多选)");
55
+ }
56
+
57
+ return [...new Set(selection)];
58
+ } finally {
59
+ rl.close();
60
+ }
61
+ }
62
+
63
+ module.exports = {
64
+ selectTargets
65
+ };
@@ -0,0 +1,97 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const os = require("os");
4
+
5
+ class AtomicWriter {
6
+ /**
7
+ * Atomically copy a directory structure.
8
+ * 1. Copies source to a temp directory.
9
+ * 2. Renames temp directory to target directory (atomic on POSIX, nearly atomic win32 move).
10
+ *
11
+ * @param {string} sourceDir Source directory path
12
+ * @param {string} targetDir Target directory path
13
+ * @param {object} options { logger: function, force: boolean }
14
+ */
15
+ static atomicCopyDir(sourceDir, targetDir, options = {}) {
16
+ const log = options.logger || console.log;
17
+ const tempName = `.tmp-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
18
+ const tempTarget = path.join(path.dirname(targetDir), tempName);
19
+
20
+ try {
21
+ // 1. Prepare temp dir
22
+ // Use copy logic (recursive)
23
+ AtomicWriter._copyDirRecursive(sourceDir, tempTarget);
24
+
25
+ // 2. Backup if exists (optional strategy, but standard atomic replace usually implies overwrite)
26
+ // If target exists, we need to remove it OR rename it away before renaming temp in?
27
+ // fs.rename overwrite behavior:
28
+ // - Linux/Mac: Atomic replacement if target exists (directory replacement rules apply).
29
+ // - Windows: rename fails if target exists.
30
+
31
+ // 2. Atomic replacement logic:
32
+ // To be cross-platform safe and minimize the "missing target" window:
33
+ // 1. Rename existing targetDir to a temporary backup name.
34
+ // 2. Rename tempTarget to targetDir.
35
+ // 3. Delete the backup if 1 & 2 succeed.
36
+ if (fs.existsSync(targetDir)) {
37
+ const backupPath = `${targetDir}.bak-${Date.now()}-${Math.random().toString(36).substring(2, 5)}`;
38
+ try {
39
+ fs.renameSync(targetDir, backupPath);
40
+ } catch (err) {
41
+ // In some cases (e.g. Windows EPERM/EBUSY), rename might fail.
42
+ // If we can't rename, the only fallback is direct deletion, but we prefer failing
43
+ // and asking user to stop processes than being non-atomic.
44
+ throw new Error(`无法先行重命名旧目标目录 (${targetDir}): ${err.message}`);
45
+ }
46
+
47
+ try {
48
+ fs.renameSync(tempTarget, targetDir);
49
+ } catch (err) {
50
+ // Failed to move new content into place after moving old one out.
51
+ // Attempt to restore the backup.
52
+ try {
53
+ fs.renameSync(backupPath, targetDir);
54
+ } catch (restoreErr) {
55
+ throw new Error(`临界失败: 无法将新版本移入目标且无法恢复旧版本。旧版本位于 ${backupPath}。错误: ${err.message}`);
56
+ }
57
+ throw err;
58
+ }
59
+
60
+ // Step 3: Success! Cleanup backup.
61
+ try {
62
+ fs.rmSync(backupPath, { recursive: true, force: true });
63
+ } catch (cleanupErr) {
64
+ // Not a critical failure for the operation itself, just messy.
65
+ if (options.logger) options.logger(`[warn] 无法清理备份目录 ${backupPath}: ${cleanupErr.message}`);
66
+ }
67
+ return;
68
+ }
69
+
70
+ // If target didn't exist or was removed (Win32 path)
71
+ fs.renameSync(tempTarget, targetDir);
72
+
73
+ } catch (err) {
74
+ // Cleanup temp
75
+ if (fs.existsSync(tempTarget)) {
76
+ fs.rmSync(tempTarget, { recursive: true, force: true });
77
+ }
78
+ throw new Error(`原子写入失败: ${err.message}`);
79
+ }
80
+ }
81
+
82
+ static _copyDirRecursive(src, dest) {
83
+ fs.mkdirSync(dest, { recursive: true });
84
+ const entries = fs.readdirSync(src, { withFileTypes: true });
85
+ for (const entry of entries) {
86
+ const srcPath = path.join(src, entry.name);
87
+ const destPath = path.join(dest, entry.name);
88
+ if (entry.isDirectory()) {
89
+ AtomicWriter._copyDirRecursive(srcPath, destPath);
90
+ } else {
91
+ fs.copyFileSync(srcPath, destPath);
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ module.exports = AtomicWriter;
@@ -0,0 +1,68 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ class GitHelper {
5
+ /**
6
+ * Remove ignore rules matching specific patterns from .gitignore
7
+ * @param {string} workspaceRoot Directory containing .gitignore
8
+ * @param {string[]} targetPatterns List of patterns to remove (e.g. ['.agent', '.codex'])
9
+ * @param {object} options { dryRun: boolean }
10
+ * @returns {object} { fileExists, removedCount, dryRun }
11
+ */
12
+ static removeIgnoreRules(workspaceRoot, targetPatterns, options) {
13
+ const gitIgnorePath = path.join(workspaceRoot, ".gitignore");
14
+ if (!fs.existsSync(gitIgnorePath)) {
15
+ return { fileExists: false, removedCount: 0, dryRun: options.dryRun };
16
+ }
17
+
18
+ const original = fs.readFileSync(gitIgnorePath, "utf8");
19
+ const lineEnding = original.includes("\r\n") ? "\r\n" : "\n";
20
+ const hadTrailingNewline = /\r?\n$/.test(original);
21
+ const lines = original.split(/\r?\n/);
22
+
23
+ const kept = [];
24
+ let removedCount = 0;
25
+
26
+ function isTargetRule(line) {
27
+ const trimmed = line.trim();
28
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("!")) return false;
29
+ let pattern = trimmed;
30
+ // Remove leading/trailing patterns
31
+ while (pattern.startsWith("**/")) pattern = pattern.slice(3);
32
+ while (pattern.startsWith("/")) pattern = pattern.slice(1);
33
+ while (pattern.endsWith("/")) pattern = pattern.slice(0, -1);
34
+ while (pattern.endsWith("/**")) pattern = pattern.slice(0, -3);
35
+
36
+ if (!pattern) return false;
37
+ const segments = pattern.split("/");
38
+
39
+ // Check if any segment matches our target patterns
40
+ return segments.some((segment) => targetPatterns.includes(segment));
41
+ }
42
+
43
+ for (const line of lines) {
44
+ if (isTargetRule(line)) {
45
+ removedCount += 1;
46
+ continue;
47
+ }
48
+ kept.push(line);
49
+ }
50
+
51
+ if (removedCount === 0) {
52
+ return { fileExists: true, removedCount: 0, dryRun: options.dryRun };
53
+ }
54
+
55
+ let updated = kept.join(lineEnding);
56
+ if (hadTrailingNewline) {
57
+ updated += lineEnding;
58
+ }
59
+
60
+ if (!options.dryRun) {
61
+ fs.writeFileSync(gitIgnorePath, updated, "utf8");
62
+ }
63
+
64
+ return { fileExists: true, removedCount, dryRun: options.dryRun };
65
+ }
66
+ }
67
+
68
+ module.exports = GitHelper;