@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
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@mison/ling",
3
+ "version": "1.0.0",
4
+ "description": "AI Agent templates - Skills, Agents, and Workflows for enhanced coding assistance",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/MisonL/Ling.git"
8
+ },
9
+ "homepage": "https://github.com/MisonL/Ling#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/MisonL/Ling/issues"
12
+ },
13
+ "keywords": [
14
+ "ling",
15
+ "ai",
16
+ "agent",
17
+ "gemini",
18
+ "skills",
19
+ "templates"
20
+ ],
21
+ "author": "vudovn",
22
+ "license": "MIT",
23
+ "scripts": {
24
+ "clean": "node scripts/clean.js",
25
+ "clean:dry-run": "node scripts/clean.js --dry-run",
26
+ "health-check": "node scripts/health-check.js",
27
+ "postinstall": "node scripts/postinstall-check.js",
28
+ "test": "node scripts/run-tests.js",
29
+ "ci:verify": "node scripts/ci-verify.js"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "files": [
35
+ ".agents/**",
36
+ ".spec/**",
37
+ "bin/**",
38
+ "scripts/clean.js",
39
+ "scripts/ci-verify.js",
40
+ "scripts/health-check.js",
41
+ "scripts/health-check.sh",
42
+ "scripts/postinstall-check.js",
43
+ "scripts/run-tests.js",
44
+ "tests/**/*.test.js",
45
+ "README.md",
46
+ "LICENSE",
47
+ "CHANGELOG.md",
48
+ "AGENT_FLOW.md",
49
+ "docs/PLAN.md",
50
+ "docs/TECH.md"
51
+ ],
52
+ "bin": {
53
+ "ling": "./bin/ling.js",
54
+ "ag-kit": "./bin/ag-kit.js"
55
+ }
56
+ }
@@ -0,0 +1,110 @@
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", "ling.js");
10
+
11
+ function runCli(args, options = {}) {
12
+ const env = {
13
+ ...process.env,
14
+ LING_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(`命令失败: ling ${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(), "ling-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
+ LING_INDEX_PATH: indexPath,
48
+ LING_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
+ runCli(["spec", "enable", "--target", "codex", "--quiet"], { env });
80
+ const specStatus = runCli(["spec", "status", "--quiet"], { env }).trim();
81
+ if (specStatus !== "installed") {
82
+ throw new Error(`spec status 结果异常: ${specStatus}`);
83
+ }
84
+ runCli(["spec", "disable", "--target", "codex", "--quiet"], { env });
85
+ const specStatusAfterDisable = runCli(["spec", "status", "--quiet"], { env }).trim();
86
+ if (specStatusAfterDisable !== "missing") {
87
+ throw new Error(`spec disable 后状态异常: ${specStatusAfterDisable}`);
88
+ }
89
+
90
+ const codexSkill = path.join(globalRoot, ".codex", "skills", "workflow-plan", "SKILL.md");
91
+ const geminiCliSkill = path.join(globalRoot, ".gemini", "skills", "clean-code", "SKILL.md");
92
+ const antigravitySkill = path.join(globalRoot, ".gemini", "antigravity", "skills", "clean-code", "SKILL.md");
93
+ const specCodexSkill = path.join(globalRoot, ".codex", "skills", "harness-engineering");
94
+ ensureExists(codexSkill, "全局 Codex workflow-plan Skill");
95
+ ensureExists(geminiCliSkill, "全局 Gemini CLI clean-code Skill");
96
+ ensureExists(antigravitySkill, "全局 Antigravity clean-code Skill");
97
+ if (fs.existsSync(specCodexSkill)) {
98
+ throw new Error(`spec disable 后仍残留 Spec Skill: ${specCodexSkill}`);
99
+ }
100
+
101
+ fs.rmSync(tempRoot, { recursive: true, force: true });
102
+ }
103
+
104
+ try {
105
+ main();
106
+ console.log("[ok] CI 全链路演练通过");
107
+ } catch (err) {
108
+ console.error(`[error] ${err.message}`);
109
+ process.exit(1);
110
+ }
@@ -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(`[clean] 已清理: ${item.path}`);
85
+ continue;
86
+ }
87
+ if (item.action === "would_remove") {
88
+ console.log(`[dry-run] 将清理: ${item.path}`);
89
+ continue;
90
+ }
91
+ console.log(`[skip] 已跳过: ${item.path} (${item.reason})`);
92
+ }
93
+ console.log(`[summary] 清理完成: 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(`[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,143 @@
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(), "ling-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
+ LING_INDEX_PATH: indexPath,
70
+ LING_GLOBAL_ROOT: globalRoot,
71
+ LING_SKIP_UPSTREAM_CHECK: "1",
72
+ };
73
+
74
+ runCommand(`node bin/ling.js init --targets gemini,codex --path "${workspaceDir}" --quiet`, { env });
75
+
76
+ const status = runCommand(`node bin/ling.js status --path "${workspaceDir}" --quiet`, { env }).trim();
77
+ if (status !== "installed") {
78
+ throw new Error(`status 结果异常: ${status}`);
79
+ }
80
+
81
+ runCommand(`node bin/ling.js doctor --path "${workspaceDir}" --quiet`, { env });
82
+ runCommand(`node bin/ling.js update --path "${workspaceDir}" --quiet`, { env });
83
+ runCommand("node bin/ling.js update-all --dry-run --quiet", { env });
84
+ runCommand(`node bin/ling.js exclude add --path "${workspaceDir}" --quiet`, { env });
85
+
86
+ const excluded = runCommand("node bin/ling.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/ling.js exclude remove --path "${workspaceDir}" --quiet`, { env });
92
+ const excludedAfter = runCommand("node bin/ling.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/ling.js global sync --quiet", { env });
98
+ const globalStatus = runCommand("node bin/ling.js global status --quiet", { env }).trim();
99
+ if (globalStatus !== "installed") {
100
+ throw new Error(`global status 结果异常: ${globalStatus}`);
101
+ }
102
+
103
+ runCommand("node bin/ling.js spec enable --target codex --quiet", { env });
104
+ const specStatus = runCommand("node bin/ling.js spec status --quiet", { env }).trim();
105
+ if (specStatus !== "installed") {
106
+ throw new Error(`spec status 结果异常: ${specStatus}`);
107
+ }
108
+ runCommand("node bin/ling.js spec disable --target codex --quiet", { env });
109
+ const specStatusAfterDisable = runCommand("node bin/ling.js spec status --quiet", { env }).trim();
110
+ if (specStatusAfterDisable !== "missing") {
111
+ throw new Error(`spec disable 后状态异常: ${specStatusAfterDisable}`);
112
+ }
113
+
114
+ const globalChecks = [
115
+ path.join(globalRoot, ".codex", "skills", "workflow-plan", "SKILL.md"),
116
+ path.join(globalRoot, ".gemini", "skills", "clean-code", "SKILL.md"),
117
+ path.join(globalRoot, ".gemini", "antigravity", "skills", "clean-code", "SKILL.md"),
118
+ ];
119
+ for (const targetPath of globalChecks) {
120
+ if (!fs.existsSync(targetPath)) {
121
+ throw new Error(`global sync 未生成预期文件: ${targetPath}`);
122
+ }
123
+ }
124
+ } finally {
125
+ fs.rmSync(tempRoot, { recursive: true, force: true });
126
+ }
127
+
128
+ logStep("执行清理预检");
129
+ if (packageRunner === "bun") {
130
+ runCommand("bun run clean:dry-run");
131
+ } else {
132
+ runCommand("npm run clean:dry-run --silent");
133
+ }
134
+
135
+ console.log("[ok] 健康检查通过");
136
+ }
137
+
138
+ try {
139
+ main();
140
+ } catch (err) {
141
+ console.error(`[error] ${err.message}`);
142
+ process.exit(1);
143
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
+ node "${ROOT_DIR}/scripts/health-check.js" "$@"
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execSync } = require("child_process");
4
+ const readline = require("node:readline");
5
+ const { stdin: input, stdout: output } = require("node:process");
6
+
7
+ const UPSTREAM_GLOBAL_PACKAGE = "@vudovn/ag-kit";
8
+
9
+ const { readGlobalNpmDependencies } = require("../bin/utils");
10
+
11
+ function canPromptUser() {
12
+ return Boolean(input.isTTY && output.isTTY);
13
+ }
14
+
15
+ function askQuestion(question) {
16
+ return new Promise((resolve) => {
17
+ const rl = readline.createInterface({ input, output });
18
+ rl.question(question, (answer) => {
19
+ rl.close();
20
+ resolve(answer);
21
+ });
22
+ });
23
+ }
24
+
25
+ function parseYesNo(answer, defaultYes) {
26
+ const text = String(answer || "").trim().toLowerCase();
27
+ if (!text) {
28
+ return defaultYes;
29
+ }
30
+ if (["y", "yes", "1", "true", "是"].includes(text)) {
31
+ return true;
32
+ }
33
+ if (["n", "no", "0", "false", "否"].includes(text)) {
34
+ return false;
35
+ }
36
+ return defaultYes;
37
+ }
38
+
39
+ async function askForUninstallConfirmation() {
40
+ const answer = await askQuestion(`是否现在自动卸载 ${UPSTREAM_GLOBAL_PACKAGE}?[Y/n]: `);
41
+ return parseYesNo(answer, true);
42
+ }
43
+
44
+ function uninstallUpstreamPackage() {
45
+ try {
46
+ execSync(`npm uninstall -g ${UPSTREAM_GLOBAL_PACKAGE}`, {
47
+ stdio: "inherit",
48
+ });
49
+ return true;
50
+ } catch (err) {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ async function main() {
56
+ const isGlobalInstall = process.env.npm_config_global === "true";
57
+ if (!isGlobalInstall) {
58
+ return;
59
+ }
60
+
61
+ if (process.env.LING_SKIP_UPSTREAM_CHECK === "1" || process.env.AG_KIT_SKIP_UPSTREAM_CHECK === "1") {
62
+ return;
63
+ }
64
+
65
+ const deps = readGlobalNpmDependencies();
66
+ if (!deps) {
67
+ return;
68
+ }
69
+
70
+ if (!Object.prototype.hasOwnProperty.call(deps, UPSTREAM_GLOBAL_PACKAGE)) {
71
+ return;
72
+ }
73
+
74
+ console.warn(`\n[warn] 检测到全局已安装上游英文版 ${UPSTREAM_GLOBAL_PACKAGE}`);
75
+ console.warn("[warn] 上游英文版与当前版本共用 `ag-kit` 兼容命令名,后安装者会覆盖该入口。");
76
+ console.warn("[warn] 为避免后续混淆,建议仅保留一个来源。\n");
77
+
78
+ if (!canPromptUser()) {
79
+ console.warn("[info] 当前环境不是交互式终端,无法确认是否自动卸载。");
80
+ console.warn(`[hint] 如需卸载,请手动执行: npm uninstall -g ${UPSTREAM_GLOBAL_PACKAGE}`);
81
+ console.warn("[info] 本次将继续安装;安装完成后正式命令请使用 `ling`。\n");
82
+ return;
83
+ }
84
+
85
+ const shouldUninstall = await askForUninstallConfirmation();
86
+
87
+ if (!shouldUninstall) {
88
+ console.warn(`[info] 已保留 ${UPSTREAM_GLOBAL_PACKAGE},继续安装当前版本。`);
89
+ console.warn("[info] 结果说明:正式命令请使用 `ling`,旧 `ag-kit` 仅保留兼容入口。\n");
90
+ return;
91
+ }
92
+
93
+ console.warn(`\n[clean] 正在卸载 ${UPSTREAM_GLOBAL_PACKAGE} ...`);
94
+ const ok = uninstallUpstreamPackage();
95
+
96
+ if (ok) {
97
+ console.warn(`[ok] 已卸载 ${UPSTREAM_GLOBAL_PACKAGE},继续安装当前版本。\n`);
98
+ return;
99
+ }
100
+
101
+ console.warn(`[error] 自动卸载 ${UPSTREAM_GLOBAL_PACKAGE} 失败,将继续安装当前版本。`);
102
+ console.warn("[info] 若需手动处理,请执行:");
103
+ console.warn(` npm uninstall -g ${UPSTREAM_GLOBAL_PACKAGE}`);
104
+ console.warn("[info] 安装完成后,正式命令请使用 `ling`;旧 `ag-kit` 仅保留兼容入口。\n");
105
+ }
106
+
107
+ main().catch((err) => {
108
+ console.warn("[warn] postinstall 冲突检测出现异常,已跳过,不影响安装继续。");
109
+ if (err && err.message) {
110
+ console.warn(` ${err.message}`);
111
+ }
112
+ });
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { spawnSync } = require("node:child_process");
6
+
7
+ const ROOT_DIR = path.resolve(__dirname, "..");
8
+ const TESTS_DIR = path.join(ROOT_DIR, "tests");
9
+
10
+ function collectTestFiles(dir) {
11
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
12
+ const files = [];
13
+
14
+ for (const entry of entries) {
15
+ const fullPath = path.join(dir, entry.name);
16
+ if (entry.isDirectory()) {
17
+ files.push(...collectTestFiles(fullPath));
18
+ continue;
19
+ }
20
+
21
+ if (entry.isFile() && entry.name.endsWith(".test.js")) {
22
+ files.push(fullPath);
23
+ }
24
+ }
25
+
26
+ return files.sort();
27
+ }
28
+
29
+ function main() {
30
+ const testFiles = collectTestFiles(TESTS_DIR);
31
+ if (testFiles.length === 0) {
32
+ console.error("未找到测试文件");
33
+ process.exit(1);
34
+ }
35
+
36
+ const result = spawnSync(process.execPath, ["--test", ...testFiles], {
37
+ cwd: ROOT_DIR,
38
+ stdio: "inherit",
39
+ });
40
+
41
+ if (result.error) {
42
+ console.error(result.error.message);
43
+ process.exit(1);
44
+ }
45
+
46
+ process.exit(result.status || 0);
47
+ }
48
+
49
+ main();
@@ -0,0 +1,47 @@
1
+ const { test, describe, beforeEach, afterEach } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const AtomicWriter = require('../bin/utils/atomic-writer');
7
+
8
+ describe('AtomicWriter', () => {
9
+ let workDir;
10
+ let sourceDir;
11
+ let targetDir;
12
+
13
+ beforeEach(() => {
14
+ workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'atomic-test-'));
15
+ sourceDir = path.join(workDir, 'source');
16
+ targetDir = path.join(workDir, 'target');
17
+
18
+ fs.mkdirSync(sourceDir);
19
+ fs.writeFileSync(path.join(sourceDir, 'data.txt'), 'version 1');
20
+ });
21
+
22
+ afterEach(() => {
23
+ fs.rmSync(workDir, { recursive: true, force: true });
24
+ });
25
+
26
+ test('atomicCopyDir should copy directory when target does not exist', () => {
27
+ AtomicWriter.atomicCopyDir(sourceDir, targetDir);
28
+
29
+ assert.ok(fs.existsSync(targetDir));
30
+ assert.strictEqual(fs.readFileSync(path.join(targetDir, 'data.txt'), 'utf8'), 'version 1');
31
+ });
32
+
33
+ test('atomicCopyDir should overwrite existing directory', () => {
34
+ // Setup initial target
35
+ fs.mkdirSync(targetDir);
36
+ fs.writeFileSync(path.join(targetDir, 'old.txt'), 'old data');
37
+
38
+ // Prepare new source
39
+ fs.writeFileSync(path.join(sourceDir, 'data.txt'), 'version 2');
40
+
41
+ AtomicWriter.atomicCopyDir(sourceDir, targetDir);
42
+
43
+ assert.ok(fs.existsSync(targetDir));
44
+ assert.strictEqual(fs.readFileSync(path.join(targetDir, 'data.txt'), 'utf8'), 'version 2');
45
+ assert.ok(!fs.existsSync(path.join(targetDir, 'old.txt')), 'Old file should be gone');
46
+ });
47
+ });