@mison/ling 1.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.
Files changed (268) hide show
  1. package/.agents/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agents/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agents/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agents/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agents/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agents/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agents/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agents/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agents/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agents/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agents/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agents/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agents/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agents/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agents/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agents/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agents/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agents/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agents/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agents/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agents/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agents/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agents/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agents/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agents/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  26. package/.agents/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  27. package/.agents/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  28. package/.agents/ARCHITECTURE.md +285 -0
  29. package/.agents/agents/backend-specialist.md +268 -0
  30. package/.agents/agents/code-archaeologist.md +106 -0
  31. package/.agents/agents/database-architect.md +225 -0
  32. package/.agents/agents/debugger.md +225 -0
  33. package/.agents/agents/devops-engineer.md +242 -0
  34. package/.agents/agents/documentation-writer.md +104 -0
  35. package/.agents/agents/explorer-agent.md +73 -0
  36. package/.agents/agents/frontend-specialist.md +618 -0
  37. package/.agents/agents/game-developer.md +162 -0
  38. package/.agents/agents/mobile-developer.md +382 -0
  39. package/.agents/agents/orchestrator.md +436 -0
  40. package/.agents/agents/penetration-tester.md +188 -0
  41. package/.agents/agents/performance-optimizer.md +187 -0
  42. package/.agents/agents/product-manager.md +112 -0
  43. package/.agents/agents/product-owner.md +95 -0
  44. package/.agents/agents/project-planner.md +405 -0
  45. package/.agents/agents/qa-automation-engineer.md +103 -0
  46. package/.agents/agents/security-auditor.md +170 -0
  47. package/.agents/agents/seo-specialist.md +111 -0
  48. package/.agents/agents/test-engineer.md +158 -0
  49. package/.agents/mcp_config.json +22 -0
  50. package/.agents/rules/GEMINI.md +273 -0
  51. package/.agents/scripts/auto_preview.py +148 -0
  52. package/.agents/scripts/checklist.py +217 -0
  53. package/.agents/scripts/session_manager.py +120 -0
  54. package/.agents/scripts/verify_all.py +327 -0
  55. package/.agents/skills/api-patterns/SKILL.md +84 -0
  56. package/.agents/skills/api-patterns/api-style.md +42 -0
  57. package/.agents/skills/api-patterns/auth.md +24 -0
  58. package/.agents/skills/api-patterns/documentation.md +26 -0
  59. package/.agents/skills/api-patterns/graphql.md +41 -0
  60. package/.agents/skills/api-patterns/rate-limiting.md +31 -0
  61. package/.agents/skills/api-patterns/response.md +37 -0
  62. package/.agents/skills/api-patterns/rest.md +40 -0
  63. package/.agents/skills/api-patterns/scripts/api_validator.py +211 -0
  64. package/.agents/skills/api-patterns/security-testing.md +122 -0
  65. package/.agents/skills/api-patterns/trpc.md +41 -0
  66. package/.agents/skills/api-patterns/versioning.md +22 -0
  67. package/.agents/skills/app-builder/SKILL.md +75 -0
  68. package/.agents/skills/app-builder/agent-coordination.md +74 -0
  69. package/.agents/skills/app-builder/feature-building.md +53 -0
  70. package/.agents/skills/app-builder/project-detection.md +34 -0
  71. package/.agents/skills/app-builder/scaffolding.md +118 -0
  72. package/.agents/skills/app-builder/tech-stack.md +40 -0
  73. package/.agents/skills/app-builder/templates/SKILL.md +39 -0
  74. package/.agents/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  75. package/.agents/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  76. package/.agents/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  77. package/.agents/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  78. package/.agents/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  79. package/.agents/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  80. package/.agents/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  81. package/.agents/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  82. package/.agents/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  83. package/.agents/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  84. package/.agents/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  85. package/.agents/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  86. package/.agents/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  87. package/.agents/skills/architecture/SKILL.md +57 -0
  88. package/.agents/skills/architecture/context-discovery.md +43 -0
  89. package/.agents/skills/architecture/examples.md +94 -0
  90. package/.agents/skills/architecture/pattern-selection.md +68 -0
  91. package/.agents/skills/architecture/patterns-reference.md +50 -0
  92. package/.agents/skills/architecture/trade-off-analysis.md +77 -0
  93. package/.agents/skills/bash-linux/SKILL.md +201 -0
  94. package/.agents/skills/behavioral-modes/SKILL.md +264 -0
  95. package/.agents/skills/brainstorming/SKILL.md +164 -0
  96. package/.agents/skills/brainstorming/dynamic-questioning.md +359 -0
  97. package/.agents/skills/clean-code/SKILL.md +200 -0
  98. package/.agents/skills/code-review-checklist/SKILL.md +125 -0
  99. package/.agents/skills/database-design/SKILL.md +54 -0
  100. package/.agents/skills/database-design/database-selection.md +43 -0
  101. package/.agents/skills/database-design/indexing.md +39 -0
  102. package/.agents/skills/database-design/migrations.md +50 -0
  103. package/.agents/skills/database-design/optimization.md +36 -0
  104. package/.agents/skills/database-design/orm-selection.md +30 -0
  105. package/.agents/skills/database-design/schema-design.md +56 -0
  106. package/.agents/skills/database-design/scripts/schema_validator.py +172 -0
  107. package/.agents/skills/deployment-procedures/SKILL.md +241 -0
  108. package/.agents/skills/doc.md +177 -0
  109. package/.agents/skills/documentation-templates/SKILL.md +194 -0
  110. package/.agents/skills/frontend-design/SKILL.md +418 -0
  111. package/.agents/skills/frontend-design/animation-guide.md +331 -0
  112. package/.agents/skills/frontend-design/color-system.md +307 -0
  113. package/.agents/skills/frontend-design/decision-trees.md +418 -0
  114. package/.agents/skills/frontend-design/motion-graphics.md +306 -0
  115. package/.agents/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  116. package/.agents/skills/frontend-design/scripts/ux_audit.py +727 -0
  117. package/.agents/skills/frontend-design/typography-system.md +345 -0
  118. package/.agents/skills/frontend-design/ux-psychology.md +1118 -0
  119. package/.agents/skills/frontend-design/visual-effects.md +383 -0
  120. package/.agents/skills/game-development/2d-games/SKILL.md +119 -0
  121. package/.agents/skills/game-development/3d-games/SKILL.md +135 -0
  122. package/.agents/skills/game-development/SKILL.md +167 -0
  123. package/.agents/skills/game-development/game-art/SKILL.md +185 -0
  124. package/.agents/skills/game-development/game-audio/SKILL.md +190 -0
  125. package/.agents/skills/game-development/game-design/SKILL.md +129 -0
  126. package/.agents/skills/game-development/mobile-games/SKILL.md +108 -0
  127. package/.agents/skills/game-development/multiplayer/SKILL.md +132 -0
  128. package/.agents/skills/game-development/pc-games/SKILL.md +144 -0
  129. package/.agents/skills/game-development/vr-ar/SKILL.md +123 -0
  130. package/.agents/skills/game-development/web-games/SKILL.md +150 -0
  131. package/.agents/skills/geo-fundamentals/SKILL.md +155 -0
  132. package/.agents/skills/geo-fundamentals/scripts/geo_checker.py +289 -0
  133. package/.agents/skills/i18n-localization/SKILL.md +154 -0
  134. package/.agents/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  135. package/.agents/skills/intelligent-routing/SKILL.md +335 -0
  136. package/.agents/skills/lint-and-validate/SKILL.md +44 -0
  137. package/.agents/skills/lint-and-validate/scripts/lint_runner.py +184 -0
  138. package/.agents/skills/lint-and-validate/scripts/type_coverage.py +173 -0
  139. package/.agents/skills/mcp-builder/SKILL.md +176 -0
  140. package/.agents/skills/mobile-design/SKILL.md +394 -0
  141. package/.agents/skills/mobile-design/decision-trees.md +516 -0
  142. package/.agents/skills/mobile-design/mobile-backend.md +491 -0
  143. package/.agents/skills/mobile-design/mobile-color-system.md +420 -0
  144. package/.agents/skills/mobile-design/mobile-debugging.md +122 -0
  145. package/.agents/skills/mobile-design/mobile-design-thinking.md +355 -0
  146. package/.agents/skills/mobile-design/mobile-navigation.md +458 -0
  147. package/.agents/skills/mobile-design/mobile-performance.md +767 -0
  148. package/.agents/skills/mobile-design/mobile-testing.md +356 -0
  149. package/.agents/skills/mobile-design/mobile-typography.md +432 -0
  150. package/.agents/skills/mobile-design/platform-android.md +666 -0
  151. package/.agents/skills/mobile-design/platform-ios.md +561 -0
  152. package/.agents/skills/mobile-design/scripts/mobile_audit.py +670 -0
  153. package/.agents/skills/mobile-design/touch-psychology.md +537 -0
  154. package/.agents/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +311 -0
  155. package/.agents/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +241 -0
  156. package/.agents/skills/nextjs-react-expert/3-server-server-side-performance.md +489 -0
  157. package/.agents/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +263 -0
  158. package/.agents/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +581 -0
  159. package/.agents/skills/nextjs-react-expert/6-rendering-rendering-performance.md +431 -0
  160. package/.agents/skills/nextjs-react-expert/7-js-javascript-performance.md +683 -0
  161. package/.agents/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +149 -0
  162. package/.agents/skills/nextjs-react-expert/SKILL.md +286 -0
  163. package/.agents/skills/nextjs-react-expert/scripts/convert_rules.py +222 -0
  164. package/.agents/skills/nextjs-react-expert/scripts/react_performance_checker.py +252 -0
  165. package/.agents/skills/nodejs-best-practices/SKILL.md +333 -0
  166. package/.agents/skills/parallel-agents/SKILL.md +193 -0
  167. package/.agents/skills/performance-profiling/SKILL.md +149 -0
  168. package/.agents/skills/performance-profiling/scripts/lighthouse_audit.py +120 -0
  169. package/.agents/skills/plan-writing/SKILL.md +152 -0
  170. package/.agents/skills/powershell-windows/SKILL.md +166 -0
  171. package/.agents/skills/python-patterns/SKILL.md +441 -0
  172. package/.agents/skills/red-team-tactics/SKILL.md +203 -0
  173. package/.agents/skills/refactoring-patterns/SKILL.md +43 -0
  174. package/.agents/skills/rust-pro/SKILL.md +190 -0
  175. package/.agents/skills/seo-fundamentals/SKILL.md +135 -0
  176. package/.agents/skills/seo-fundamentals/scripts/seo_checker.py +215 -0
  177. package/.agents/skills/server-management/SKILL.md +161 -0
  178. package/.agents/skills/systematic-debugging/SKILL.md +114 -0
  179. package/.agents/skills/tailwind-patterns/SKILL.md +269 -0
  180. package/.agents/skills/tdd-workflow/SKILL.md +149 -0
  181. package/.agents/skills/testing-patterns/SKILL.md +178 -0
  182. package/.agents/skills/testing-patterns/scripts/test_runner.py +219 -0
  183. package/.agents/skills/vulnerability-scanner/SKILL.md +276 -0
  184. package/.agents/skills/vulnerability-scanner/checklists.md +131 -0
  185. package/.agents/skills/vulnerability-scanner/scripts/__pycache__/security_scan.cpython-310.pyc +0 -0
  186. package/.agents/skills/vulnerability-scanner/scripts/security_scan.py +524 -0
  187. package/.agents/skills/web-design-guidelines/SKILL.md +57 -0
  188. package/.agents/skills/webapp-testing/SKILL.md +187 -0
  189. package/.agents/skills/webapp-testing/scripts/playwright_runner.py +173 -0
  190. package/.agents/workflows/brainstorm.md +113 -0
  191. package/.agents/workflows/create.md +59 -0
  192. package/.agents/workflows/debug.md +103 -0
  193. package/.agents/workflows/deploy.md +176 -0
  194. package/.agents/workflows/enhance.md +63 -0
  195. package/.agents/workflows/orchestrate.md +242 -0
  196. package/.agents/workflows/plan.md +89 -0
  197. package/.agents/workflows/preview.md +80 -0
  198. package/.agents/workflows/restore-localize-compat.md +525 -0
  199. package/.agents/workflows/status.md +86 -0
  200. package/.agents/workflows/test.md +144 -0
  201. package/.agents/workflows/ui-ux-pro-max.md +295 -0
  202. package/.spec/profiles/codex/AGENTS.spec.md +7 -0
  203. package/.spec/profiles/codex/ling.spec.rules.md +4 -0
  204. package/.spec/profiles/gemini/GEMINI.spec.md +5 -0
  205. package/.spec/references/README.md +36 -0
  206. package/.spec/references/cse-quickstart.md +96 -0
  207. package/.spec/references/gda-framework.md +394 -0
  208. package/.spec/references/harness-engineering-digest.md +93 -0
  209. package/.spec/skills/cybernetic-systems-engineering/SKILL.md +792 -0
  210. package/.spec/skills/cybernetic-systems-engineering/agents/openai.yaml +5 -0
  211. package/.spec/skills/cybernetic-systems-engineering/assets/quickstart.md +96 -0
  212. package/.spec/skills/cybernetic-systems-engineering/references/README.md +36 -0
  213. package/.spec/skills/cybernetic-systems-engineering/references/gda-framework.md +394 -0
  214. package/.spec/skills/cybernetic-systems-engineering/scripts/issues.csv +20 -0
  215. package/.spec/skills/harness-engineering/SKILL.md +100 -0
  216. package/.spec/skills/harness-engineering/agents/openai.yaml +4 -0
  217. package/.spec/skills/harness-engineering/references/harness-engineering-digest.md +93 -0
  218. package/.spec/templates/driver-prompt.md +7 -0
  219. package/.spec/templates/handoff.md +9 -0
  220. package/.spec/templates/issues.template.csv +2 -0
  221. package/.spec/templates/phase-acceptance.md +9 -0
  222. package/.spec/templates/review-report.md +9 -0
  223. package/AGENT_FLOW.md +609 -0
  224. package/CHANGELOG.md +43 -0
  225. package/LICENSE +21 -0
  226. package/README.md +359 -0
  227. package/bin/adapters/base.js +63 -0
  228. package/bin/adapters/codex.js +421 -0
  229. package/bin/adapters/gemini.js +157 -0
  230. package/bin/ag-kit.js +2266 -0
  231. package/bin/core/builder.js +80 -0
  232. package/bin/core/generator.js +59 -0
  233. package/bin/core/resource-loader.js +64 -0
  234. package/bin/core/transformer.js +208 -0
  235. package/bin/interactive.js +65 -0
  236. package/bin/ling.js +3 -0
  237. package/bin/utils/atomic-writer.js +97 -0
  238. package/bin/utils/git-helper.js +68 -0
  239. package/bin/utils/managed-block.js +65 -0
  240. package/bin/utils/manifest.js +244 -0
  241. package/bin/utils.js +89 -0
  242. package/docs/PLAN.md +54 -0
  243. package/docs/TECH.md +191 -0
  244. package/package.json +56 -0
  245. package/scripts/ci-verify.js +110 -0
  246. package/scripts/clean.js +123 -0
  247. package/scripts/health-check.js +143 -0
  248. package/scripts/health-check.sh +6 -0
  249. package/scripts/postinstall-check.js +112 -0
  250. package/scripts/run-tests.js +49 -0
  251. package/tests/atomic-writer.test.js +47 -0
  252. package/tests/clean-script.test.js +77 -0
  253. package/tests/cli-smoke.test.js +479 -0
  254. package/tests/codex-adapter.test.js +132 -0
  255. package/tests/doctor.test.js +94 -0
  256. package/tests/gemini-adapter.test.js +30 -0
  257. package/tests/generator.test.js +48 -0
  258. package/tests/git-helper.test.js +53 -0
  259. package/tests/global-sync.test.js +133 -0
  260. package/tests/health-check-script.test.js +34 -0
  261. package/tests/managed-block.test.js +41 -0
  262. package/tests/manifest.test.js +97 -0
  263. package/tests/package-tarball.test.js +33 -0
  264. package/tests/phase-c.test.js +107 -0
  265. package/tests/spec-profile.test.js +86 -0
  266. package/tests/standards-compliance.test.js +303 -0
  267. package/tests/transformer.test.js +74 -0
  268. package/tests/versioning.test.js +51 -0
@@ -0,0 +1,421 @@
1
+ const fs = require("fs");
2
+ const os = require("os");
3
+ const path = require("path");
4
+ const BaseAdapter = require("./base");
5
+ const ManifestManager = require("../utils/manifest");
6
+ const AtomicWriter = require("../utils/atomic-writer");
7
+ const GitHelper = require("../utils/git-helper");
8
+ const { upsertManagedBlock } = require("../utils/managed-block");
9
+ const { cloneBranchAgentDir } = require("../utils");
10
+ const pkg = require("../../package.json");
11
+
12
+ const MANAGED_DIR_NAME = ".agents";
13
+ const LEGACY_DIR_NAME = ".codex";
14
+
15
+ class CodexAdapter extends BaseAdapter {
16
+ get targetName() {
17
+ return "codex";
18
+ }
19
+
20
+ getInstalledVersion() {
21
+ const managedManifest = path.join(this.workspaceRoot, MANAGED_DIR_NAME, "manifest.json");
22
+ const legacyManifest = path.join(this.workspaceRoot, LEGACY_DIR_NAME, "manifest.json");
23
+ const manifestPath = fs.existsSync(managedManifest) ? managedManifest : legacyManifest;
24
+
25
+ if (!fs.existsSync(manifestPath)) {
26
+ return null;
27
+ }
28
+
29
+ const manager = new ManifestManager(manifestPath, { target: "codex" });
30
+ const manifest = manager.load();
31
+ if (manifest && typeof manifest.kitVersion === "string" && manifest.kitVersion) {
32
+ return manifest.kitVersion;
33
+ }
34
+
35
+ return "1.0.0";
36
+ }
37
+
38
+ install(sourceDir) {
39
+ this._applyManagedFlow("install", sourceDir);
40
+ }
41
+
42
+ update(sourceDir) {
43
+ this._applyManagedFlow("update", sourceDir);
44
+ }
45
+
46
+ _applyManagedFlow(mode, sourceDir) {
47
+ const managedDir = path.join(this.workspaceRoot, MANAGED_DIR_NAME);
48
+ const legacyDir = path.join(this.workspaceRoot, LEGACY_DIR_NAME);
49
+ const managedExists = fs.existsSync(managedDir);
50
+ const legacyExists = fs.existsSync(legacyDir);
51
+ const hasExistingInstall = managedExists || legacyExists;
52
+ const currentDataDir = managedExists ? managedDir : legacyDir;
53
+
54
+ if (mode === "install" && hasExistingInstall && !this.options.force) {
55
+ throw new Error(`${MANAGED_DIR_NAME} 或 ${LEGACY_DIR_NAME} 目录已存在。请使用 --force 覆盖。`);
56
+ }
57
+ if (mode === "update" && !hasExistingInstall) {
58
+ throw new Error(`${MANAGED_DIR_NAME} 目录不存在,无法更新。请先执行 init --target codex。`);
59
+ }
60
+
61
+ const { installSource, sourceLabel, cleanup } = this._resolveInstallSource(sourceDir);
62
+ let stagingDir = "";
63
+ let incomingFiles = {};
64
+
65
+ try {
66
+ const staging = this._createStaging(installSource, sourceLabel);
67
+ stagingDir = staging.stagingDir;
68
+ incomingFiles = staging.incomingFiles;
69
+
70
+ if (this.options.dryRun) {
71
+ this.log(`[dry-run] 将原子更新: ${managedDir}`);
72
+ if (legacyExists) {
73
+ this.log(`[dry-run] 将删除遗留目录: ${legacyDir}`);
74
+ }
75
+ if (hasExistingInstall && this.options.force) {
76
+ const candidates = this._collectBackupCandidates(currentDataDir, incomingFiles);
77
+ if (candidates.fullSnapshot) {
78
+ this.log(`[dry-run] 发现旧版或缺失 manifest,覆盖前将备份整目录 ${path.basename(currentDataDir)}`);
79
+ } else if (candidates.files.length > 0) {
80
+ this.log(`[dry-run] 将备份 ${candidates.files.length} 个用户修改文件到 .agents-backup`);
81
+ }
82
+ }
83
+ this.log("[dry-run] 将更新工作区托管文件: AGENTS.md, ling.rules");
84
+ this._cleanupGitIgnore();
85
+ return;
86
+ }
87
+
88
+ if (hasExistingInstall && this.options.force) {
89
+ const candidates = this._collectBackupCandidates(currentDataDir, incomingFiles);
90
+ const backupResult = this._backupCandidates(currentDataDir, candidates);
91
+ if (backupResult) {
92
+ this.log(`[backup] 已备份覆盖前文件: ${backupResult.summary}`);
93
+ }
94
+ }
95
+
96
+ AtomicWriter.atomicCopyDir(stagingDir, managedDir, { logger: this.log.bind(this) });
97
+ this.log(`[ok] ${MANAGED_DIR_NAME} 原子更新完成`);
98
+
99
+ if (legacyExists) {
100
+ fs.rmSync(legacyDir, { recursive: true, force: true });
101
+ this.log(`[clean] 已移除遗留 ${LEGACY_DIR_NAME} 目录`);
102
+ }
103
+
104
+ this._syncWorkspaceManagedFiles(managedDir);
105
+ this._cleanupGitIgnore();
106
+
107
+ this.log(`[ok] [Codex] ${mode === "install" ? "安装" : "更新"}完成`);
108
+ } finally {
109
+ if (stagingDir) {
110
+ fs.rmSync(stagingDir, { recursive: true, force: true });
111
+ }
112
+ if (cleanup) {
113
+ cleanup();
114
+ }
115
+ }
116
+ }
117
+
118
+ _resolveInstallSource(sourceDir) {
119
+ let installSource = sourceDir;
120
+ let cleanup = null;
121
+ let sourceLabel = this.options.branch ? `branch:${this.options.branch}` : "bundled";
122
+
123
+ if (this.options.branch) {
124
+ const remote = cloneBranchAgentDir(this.options.branch, {
125
+ quiet: this.options.quiet,
126
+ logger: this.log.bind(this),
127
+ });
128
+ installSource = remote.agentDir;
129
+ cleanup = remote.cleanup;
130
+ }
131
+
132
+ const CodexBuilder = require("../core/builder");
133
+ let buildTemp = "";
134
+
135
+ const hasAgentsRoot = fs.existsSync(path.join(installSource, ".agents"));
136
+ const hasLegacyAgentRoot = fs.existsSync(path.join(installSource, ".agent"));
137
+ const hasSkillsDir = fs.existsSync(path.join(installSource, "skills"));
138
+ const isCodexPrebuilt = fs.existsSync(path.join(installSource, "manifest.json"));
139
+
140
+ if (!isCodexPrebuilt) {
141
+ if (hasSkillsDir) {
142
+ this.log("[build] 检测到模板目录格式,正在构建 Codex 结构...");
143
+ const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-root-"));
144
+ const mockAgents = path.join(mockRoot, ".agents");
145
+ this._copyDir(installSource, mockAgents);
146
+
147
+ buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-out-"));
148
+ CodexBuilder.build(mockRoot, buildTemp);
149
+ installSource = buildTemp;
150
+ sourceLabel = `${sourceLabel}:compiled`;
151
+
152
+ const previousCleanup = cleanup;
153
+ cleanup = () => {
154
+ if (previousCleanup) previousCleanup();
155
+ fs.rmSync(mockRoot, { recursive: true, force: true });
156
+ fs.rmSync(buildTemp, { recursive: true, force: true });
157
+ };
158
+ } else if (hasAgentsRoot) {
159
+ this.log("[build] 检测到仓库根目录格式(.agents),正在构建 Codex 结构...");
160
+ buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-out-"));
161
+ CodexBuilder.build(installSource, buildTemp);
162
+ installSource = buildTemp;
163
+ sourceLabel = `${sourceLabel}:compiled`;
164
+
165
+ const previousCleanup = cleanup;
166
+ cleanup = () => {
167
+ if (previousCleanup) previousCleanup();
168
+ fs.rmSync(buildTemp, { recursive: true, force: true });
169
+ };
170
+ } else if (hasLegacyAgentRoot) {
171
+ this.log("[build] 检测到旧版仓库根目录格式(.agent),正在构建 Codex 结构...");
172
+ const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-root-"));
173
+ const mockAgents = path.join(mockRoot, ".agents");
174
+ this._copyDir(path.join(installSource, ".agent"), mockAgents);
175
+
176
+ buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-build-out-"));
177
+ CodexBuilder.build(mockRoot, buildTemp);
178
+ installSource = buildTemp;
179
+ sourceLabel = `${sourceLabel}:compiled`;
180
+
181
+ const previousCleanup = cleanup;
182
+ cleanup = () => {
183
+ if (previousCleanup) previousCleanup();
184
+ fs.rmSync(mockRoot, { recursive: true, force: true });
185
+ fs.rmSync(buildTemp, { recursive: true, force: true });
186
+ };
187
+ }
188
+ }
189
+
190
+ return { installSource, sourceLabel, cleanup };
191
+ }
192
+
193
+ _createStaging(installSource, sourceLabel) {
194
+ const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-codex-stage-"));
195
+ this._copyDir(installSource, stagingDir);
196
+
197
+ const manifestPath = path.join(stagingDir, "manifest.json");
198
+ const manager = new ManifestManager(manifestPath, {
199
+ target: "codex",
200
+ kitVersion: pkg.version,
201
+ });
202
+ manager.manifest.files = ManifestManager.generateFileEntriesFromDir(stagingDir, {
203
+ baseDir: stagingDir,
204
+ sourcePrefix: sourceLabel,
205
+ });
206
+ manager.save();
207
+
208
+ return {
209
+ stagingDir,
210
+ incomingFiles: manager.manifest.files,
211
+ };
212
+ }
213
+
214
+ _collectBackupCandidates(targetDir, incomingFiles) {
215
+ const manifestPath = path.join(targetDir, "manifest.json");
216
+ if (!fs.existsSync(manifestPath)) {
217
+ return { fullSnapshot: true, files: [] };
218
+ }
219
+
220
+ try {
221
+ const raw = fs.readFileSync(manifestPath, "utf8");
222
+ const parsed = JSON.parse(raw);
223
+ const files = parsed && typeof parsed.files === "object" ? parsed.files : null;
224
+ if (!files || Object.keys(files).length === 0) {
225
+ return { fullSnapshot: true, files: [] };
226
+ }
227
+ } catch (err) {
228
+ return { fullSnapshot: true, files: [] };
229
+ }
230
+
231
+ const manager = new ManifestManager(manifestPath, { target: "codex" });
232
+ manager.load();
233
+
234
+ return {
235
+ fullSnapshot: false,
236
+ files: manager.collectSmartOverwriteConflicts(targetDir, incomingFiles),
237
+ };
238
+ }
239
+
240
+ _backupCandidates(targetDir, candidates) {
241
+ if (!candidates.fullSnapshot && candidates.files.length === 0) {
242
+ return null;
243
+ }
244
+
245
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
246
+ const backupRoot = path.join(this.workspaceRoot, ".agents-backup", timestamp);
247
+ fs.mkdirSync(backupRoot, { recursive: true });
248
+
249
+ if (candidates.fullSnapshot) {
250
+ const snapshotDir = path.join(backupRoot, "full-snapshot");
251
+ this._copyDir(targetDir, snapshotDir);
252
+ return { summary: `${backupRoot} (full snapshot)` };
253
+ }
254
+
255
+ for (const relPath of candidates.files) {
256
+ const src = path.join(targetDir, relPath);
257
+ if (!fs.existsSync(src)) {
258
+ continue;
259
+ }
260
+ const dest = path.join(backupRoot, relPath);
261
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
262
+ fs.copyFileSync(src, dest);
263
+ }
264
+
265
+ return { summary: `${backupRoot} (${candidates.files.length} files)` };
266
+ }
267
+
268
+ _syncWorkspaceManagedFiles(managedDir) {
269
+ const managedAgentsPath = path.join(managedDir, "AGENTS.md");
270
+ const managedRulesPath = path.join(managedDir, "ling.rules");
271
+
272
+ if (fs.existsSync(managedAgentsPath)) {
273
+ const body = fs.readFileSync(managedAgentsPath, "utf8");
274
+ const outputPath = path.join(this.workspaceRoot, "AGENTS.md");
275
+ const result = upsertManagedBlock(outputPath, "codex-core-rules", body, {
276
+ dryRun: this.options.dryRun,
277
+ });
278
+ this.log(`[managed] AGENTS.md 托管区块同步: ${result.action}`);
279
+ }
280
+
281
+ if (fs.existsSync(managedRulesPath)) {
282
+ const body = fs.readFileSync(managedRulesPath, "utf8");
283
+ const outputPath = path.join(this.workspaceRoot, "ling.rules");
284
+ const legacyOutputPath = path.join(this.workspaceRoot, "antigravity.rules");
285
+
286
+ if (!this.options.dryRun && !fs.existsSync(outputPath) && fs.existsSync(legacyOutputPath)) {
287
+ fs.renameSync(legacyOutputPath, outputPath);
288
+ this.log("[migrate] 已将工作区 antigravity.rules 迁移为 ling.rules");
289
+ }
290
+
291
+ const result = upsertManagedBlock(outputPath, "codex-risk-controls", body, {
292
+ dryRun: this.options.dryRun,
293
+ });
294
+ this.log(`[managed] ling.rules 托管区块同步: ${result.action}`);
295
+ }
296
+ }
297
+
298
+ _cleanupGitIgnore() {
299
+ const cleanupResult = GitHelper.removeIgnoreRules(this.workspaceRoot, [MANAGED_DIR_NAME, LEGACY_DIR_NAME], this.options);
300
+ if (cleanupResult.removedCount > 0) {
301
+ this.log(`[clean] 已从 .gitignore 移除 ${cleanupResult.removedCount} 条规则`);
302
+ }
303
+ }
304
+
305
+ _copyDir(src, dest) {
306
+ fs.mkdirSync(dest, { recursive: true });
307
+ const entries = fs.readdirSync(src, { withFileTypes: true });
308
+ for (const entry of entries) {
309
+ const srcPath = path.join(src, entry.name);
310
+ const destPath = path.join(dest, entry.name);
311
+ if (entry.isDirectory()) {
312
+ this._copyDir(srcPath, destPath);
313
+ } else {
314
+ fs.copyFileSync(srcPath, destPath);
315
+ }
316
+ }
317
+ }
318
+
319
+ checkIntegrity() {
320
+ const managedDir = path.join(this.workspaceRoot, MANAGED_DIR_NAME);
321
+ const legacyDir = path.join(this.workspaceRoot, LEGACY_DIR_NAME);
322
+ const result = { status: "ok", issues: [] };
323
+
324
+ if (!fs.existsSync(managedDir)) {
325
+ if (fs.existsSync(legacyDir)) {
326
+ return {
327
+ status: "broken",
328
+ issues: [`Legacy: ${LEGACY_DIR_NAME} directory detected; run update to migrate to ${MANAGED_DIR_NAME}`],
329
+ };
330
+ }
331
+ return { status: "missing", issues: [`Critical: ${MANAGED_DIR_NAME} directory missing`] };
332
+ }
333
+
334
+ const manifestPath = path.join(managedDir, "manifest.json");
335
+ if (!fs.existsSync(manifestPath)) {
336
+ result.status = "broken";
337
+ result.issues.push("Critical: manifest.json missing");
338
+ return result;
339
+ }
340
+
341
+ if (fs.existsSync(legacyDir)) {
342
+ result.status = "broken";
343
+ result.issues.push(`Legacy: ${LEGACY_DIR_NAME} directory should be removed`);
344
+ }
345
+
346
+ const manager = new ManifestManager(manifestPath, { target: "codex" });
347
+ manager.load();
348
+ if (manager.lastLoadError) {
349
+ result.status = "broken";
350
+ result.issues.push("Critical: manifest.json invalid JSON");
351
+ return result;
352
+ }
353
+ const drift = manager.checkDrift(managedDir);
354
+
355
+ if (drift.missing.length > 0) {
356
+ result.status = "broken";
357
+ for (const relPath of drift.missing) {
358
+ result.issues.push(`Missing managed file: ${relPath}`);
359
+ }
360
+ }
361
+
362
+ if (drift.modified.length > 0) {
363
+ if (result.status === "ok") {
364
+ result.status = "drift";
365
+ }
366
+ for (const relPath of drift.modified) {
367
+ result.issues.push(`File modified (Drift): ${relPath}`);
368
+ }
369
+ }
370
+
371
+ return result;
372
+ }
373
+
374
+ fixIntegrity() {
375
+ const managedDir = path.join(this.workspaceRoot, MANAGED_DIR_NAME);
376
+ const legacyDir = path.join(this.workspaceRoot, LEGACY_DIR_NAME);
377
+ const fixes = [];
378
+
379
+ if (!fs.existsSync(managedDir)) {
380
+ if (fs.existsSync(legacyDir)) {
381
+ AtomicWriter.atomicCopyDir(legacyDir, managedDir, { logger: this.log.bind(this) });
382
+ fs.rmSync(legacyDir, { recursive: true, force: true });
383
+ fixes.push(`migrated ${LEGACY_DIR_NAME} to ${MANAGED_DIR_NAME}`);
384
+ } else {
385
+ return {
386
+ fixed: false,
387
+ summary: `缺少 ${MANAGED_DIR_NAME},无法自动修复。请执行 ling init --target codex 或 ling update。`,
388
+ };
389
+ }
390
+ }
391
+
392
+ if (fs.existsSync(legacyDir)) {
393
+ fs.rmSync(legacyDir, { recursive: true, force: true });
394
+ fixes.push(`removed stale ${LEGACY_DIR_NAME} directory`);
395
+ }
396
+
397
+ const manifestPath = path.join(managedDir, "manifest.json");
398
+ if (!fs.existsSync(manifestPath)) {
399
+ const manager = new ManifestManager(manifestPath, {
400
+ target: "codex",
401
+ kitVersion: pkg.version,
402
+ });
403
+ manager.manifest.files = ManifestManager.generateFileEntriesFromDir(managedDir, {
404
+ baseDir: managedDir,
405
+ sourcePrefix: "recovered",
406
+ });
407
+ manager.save();
408
+ fixes.push("regenerated manifest.json");
409
+ }
410
+
411
+ this._syncWorkspaceManagedFiles(managedDir);
412
+ this._cleanupGitIgnore();
413
+
414
+ return {
415
+ fixed: fixes.length > 0,
416
+ summary: fixes.length > 0 ? `Fixed: ${fixes.join(", ")}` : "No automatic fixes available.",
417
+ };
418
+ }
419
+ }
420
+
421
+ module.exports = CodexAdapter;
@@ -0,0 +1,157 @@
1
+ const fs = require("fs");
2
+ const os = require("os");
3
+ const path = require("path");
4
+ const BaseAdapter = require("./base");
5
+ const { cloneBranchAgentDir } = require("../utils");
6
+ const GitHelper = require("../utils/git-helper");
7
+
8
+ class GeminiAdapter extends BaseAdapter {
9
+ get targetName() {
10
+ return "gemini";
11
+ }
12
+
13
+ getInstalledVersion() {
14
+ const agentDir = path.join(this.workspaceRoot, ".agent");
15
+ if (fs.existsSync(agentDir)) {
16
+ return null;
17
+ }
18
+ return null;
19
+ }
20
+
21
+ _copyDir(src, dest) {
22
+ fs.mkdirSync(dest, { recursive: true });
23
+ const entries = fs.readdirSync(src, { withFileTypes: true });
24
+
25
+ for (const entry of entries) {
26
+ const srcPath = path.join(src, entry.name);
27
+ const destPath = path.join(dest, entry.name);
28
+
29
+ if (entry.isDirectory()) {
30
+ this._copyDir(srcPath, destPath);
31
+ } else {
32
+ fs.copyFileSync(srcPath, destPath);
33
+ }
34
+ }
35
+ }
36
+
37
+ // Remove old _removeAgentIgnoreRules implementation
38
+ _removeAgentIgnoreRules() {
39
+ // Deprecated, using GitHelper
40
+ return { fileExists: false, removedCount: 0 };
41
+ }
42
+
43
+ _samePath(a, b) {
44
+ const left = path.resolve(a);
45
+ const right = path.resolve(b);
46
+ if (process.platform === "win32") {
47
+ return left.toLowerCase() === right.toLowerCase();
48
+ }
49
+ return left === right;
50
+ }
51
+
52
+ install(sourceDir) {
53
+ let installSource = sourceDir;
54
+ let cleanup = null;
55
+
56
+ if (this.options.branch) {
57
+ const remote = cloneBranchAgentDir(this.options.branch, {
58
+ quiet: this.options.quiet,
59
+ logger: this.log.bind(this)
60
+ });
61
+ installSource = remote.agentDir;
62
+ cleanup = remote.cleanup;
63
+ }
64
+
65
+ try {
66
+ const targetDir = path.join(this.workspaceRoot, ".agent");
67
+
68
+ if (!fs.existsSync(installSource)) {
69
+ throw new Error(`未找到模板目录: ${installSource}`);
70
+ }
71
+
72
+ if (this._samePath(installSource, targetDir) && !this.options.dryRun) {
73
+ const tempSource = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-gemini-src-"));
74
+ this._copyDir(installSource, tempSource);
75
+ const oldCleanup = cleanup;
76
+ cleanup = () => {
77
+ if (oldCleanup) oldCleanup();
78
+ fs.rmSync(tempSource, { recursive: true, force: true });
79
+ };
80
+ installSource = tempSource;
81
+ this.log("[info] 检测到源目录与目标目录相同,已切换为临时副本执行覆盖更新。");
82
+ }
83
+
84
+ // Log logic handled by caller mostly, but validation here
85
+ if (fs.existsSync(targetDir)) {
86
+ if (!this.options.force) {
87
+ throw new Error(".agent 目录已存在。请使用 --force 覆盖。");
88
+ }
89
+ if (this.options.dryRun) {
90
+ this.log(`[dry-run] 将删除: ${targetDir}`);
91
+ } else {
92
+ fs.rmSync(targetDir, { recursive: true, force: true });
93
+ this.log(`[clean] 已删除旧目录: ${targetDir}`);
94
+ }
95
+ }
96
+
97
+ if (this.options.dryRun) {
98
+ this.log(`[dry-run] 将复制: ${installSource} -> ${targetDir}`);
99
+ const cleanupGit = GitHelper.removeIgnoreRules(this.workspaceRoot, [".agent"], this.options);
100
+ if(cleanupGit.removedCount > 0) this.log(`[dry-run] 将移除 .gitignore 规则`);
101
+ return;
102
+ }
103
+
104
+ fs.mkdirSync(this.workspaceRoot, { recursive: true });
105
+ this._copyDir(installSource, targetDir);
106
+ const cleanupResult = GitHelper.removeIgnoreRules(this.workspaceRoot, [".agent"], this.options);
107
+ if(cleanupResult.removedCount > 0) {
108
+ this.log(`[clean] 已从 .gitignore 移除 ${cleanupResult.removedCount} 条规则`);
109
+ }
110
+
111
+ this.log("[ok] [Gemini] 安装完成 (.agent)");
112
+ } finally {
113
+ if (cleanup) cleanup();
114
+ }
115
+ }
116
+
117
+ update(sourceDir) {
118
+ this.options.force = true; // Updates are forced installs
119
+ this.install(sourceDir);
120
+ }
121
+
122
+ checkIntegrity() {
123
+ const agentDir = path.join(this.workspaceRoot, ".agent");
124
+ if (!fs.existsSync(agentDir)) {
125
+ return { status: "missing", issues: [".agent directory missing"] };
126
+ }
127
+
128
+ const issues = [];
129
+ const requiredDirs = ["agents", "skills", "rules", "workflows"];
130
+ for (const relPath of requiredDirs) {
131
+ const absPath = path.join(agentDir, relPath);
132
+ if (!fs.existsSync(absPath) || !fs.statSync(absPath).isDirectory()) {
133
+ issues.push(`Missing required directory: .agent/${relPath}`);
134
+ }
135
+ }
136
+
137
+ const requiredFiles = ["rules/GEMINI.md", "agents/orchestrator.md"];
138
+ for (const relPath of requiredFiles) {
139
+ const absPath = path.join(agentDir, relPath);
140
+ if (!fs.existsSync(absPath) || !fs.statSync(absPath).isFile()) {
141
+ issues.push(`Missing required file: .agent/${relPath}`);
142
+ }
143
+ }
144
+
145
+ if (issues.length > 0) {
146
+ return { status: "broken", issues };
147
+ }
148
+
149
+ return { status: "ok", issues: [] };
150
+ }
151
+
152
+ fixIntegrity() {
153
+ return { fixed: false, summary: "Gemini Adapter does not support self-healing yet. Please run update." };
154
+ }
155
+ }
156
+
157
+ module.exports = GeminiAdapter;