@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,107 @@
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 CodexAdapter = require('../bin/adapters/codex');
7
+ const pkg = require('../package.json');
8
+
9
+ describe('Phase C Integration', () => {
10
+ let workDir;
11
+ let geminiRepo;
12
+
13
+ beforeEach(() => {
14
+ workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'phase-c-test-'));
15
+ geminiRepo = path.join(workDir, 'gemini-repo');
16
+
17
+ // Setup specialized Gemini-like structure
18
+ const agentDir = path.join(geminiRepo, '.agent');
19
+ const skillsDir = path.join(agentDir, 'skills');
20
+ const workflowsDir = path.join(agentDir, 'workflows');
21
+
22
+ fs.mkdirSync(skillsDir, { recursive: true });
23
+ fs.mkdirSync(workflowsDir, { recursive: true });
24
+
25
+ // Create a Skill
26
+ const skillPath = path.join(skillsDir, 'test-skill');
27
+ fs.mkdirSync(skillPath);
28
+ fs.writeFileSync(path.join(skillPath, 'SKILL.md'), '# Test Skill');
29
+
30
+ // Create a Workflow
31
+ fs.writeFileSync(path.join(workflowsDir, 'test-flow.md'), '# Test Workflow');
32
+ });
33
+
34
+ afterEach(() => {
35
+ fs.rmSync(workDir, { recursive: true, force: true });
36
+ });
37
+
38
+ test('CodexAdapter should build from Gemini structure on the fly', () => {
39
+ const options = { quiet: true, force: true };
40
+ const adapter = new CodexAdapter(workDir, options);
41
+
42
+ // Install from Gemini Repo Root
43
+ adapter.install(geminiRepo);
44
+
45
+ const codexDir = path.join(workDir, '.agents');
46
+ // Verification 1: Structure Created
47
+ assert.ok(fs.existsSync(codexDir));
48
+
49
+ // Verification 2: Transformation Happened
50
+ const builtSkill = path.join(codexDir, 'skills', 'test-skill', 'SKILL.md');
51
+ assert.ok(fs.existsSync(builtSkill));
52
+
53
+ // Workflow: workflow-test-flow
54
+ const builtWorkflow = path.join(codexDir, 'skills', 'workflow-test-flow', 'SKILL.md');
55
+ assert.ok(fs.existsSync(builtWorkflow));
56
+
57
+ // Verification 3: Manifest & Meta
58
+ assert.ok(fs.existsSync(path.join(codexDir, 'codex.json')));
59
+ assert.ok(fs.existsSync(path.join(codexDir, 'AGENTS.md')));
60
+ assert.ok(fs.existsSync(path.join(codexDir, 'ling.rules')));
61
+
62
+ const agentsMd = fs.readFileSync(path.join(codexDir, 'AGENTS.md'), 'utf8');
63
+ assert.ok(agentsMd.includes('test-skill'));
64
+ assert.ok(agentsMd.includes('(Codex Managed)'));
65
+
66
+ // Verification 4: Workspace managed block injection
67
+ const workspaceAgents = fs.readFileSync(path.join(workDir, 'AGENTS.md'), 'utf8');
68
+ const workspaceRules = fs.readFileSync(path.join(workDir, 'ling.rules'), 'utf8');
69
+ assert.ok(workspaceAgents.includes('BEGIN AG-KIT MANAGED BLOCK: codex-core-rules'));
70
+ assert.ok(workspaceAgents.includes('test-skill'));
71
+ assert.ok(workspaceRules.includes('BEGIN AG-KIT MANAGED BLOCK: codex-risk-controls'));
72
+
73
+ const codexJson = JSON.parse(fs.readFileSync(path.join(codexDir, 'codex.json'), 'utf8'));
74
+ assert.strictEqual(codexJson.version, pkg.version);
75
+ assert.ok(agentsMd.includes(`Version: ${pkg.version}`));
76
+ assert.ok(workspaceRules.includes(`version: ${pkg.version}`));
77
+ });
78
+
79
+ test('CodexBuilder should avoid ID collisions between skills and workflows', () => {
80
+ const skillCollisionPath = path.join(geminiRepo, '.agent', 'skills', 'wf-test-flow');
81
+ fs.mkdirSync(skillCollisionPath, { recursive: true });
82
+ fs.writeFileSync(path.join(skillCollisionPath, 'SKILL.md'), '# Skill wf-test-flow');
83
+
84
+ const options = { quiet: true, force: true };
85
+ const adapter = new CodexAdapter(workDir, options);
86
+ adapter.install(geminiRepo);
87
+
88
+ const codexJson = JSON.parse(
89
+ fs.readFileSync(path.join(workDir, '.agents', 'codex.json'), 'utf8')
90
+ );
91
+ const collisionEntries = (codexJson.skills || []).filter(
92
+ (item) => item.originalName === 'wf-test-flow' || item.originalName === 'test-flow'
93
+ );
94
+
95
+ assert.strictEqual(collisionEntries.length, 2, 'skill/workflow should both be preserved');
96
+ assert.notStrictEqual(
97
+ collisionEntries[0].id,
98
+ collisionEntries[1].id,
99
+ 'colliding IDs should be disambiguated',
100
+ );
101
+
102
+ for (const entry of collisionEntries) {
103
+ const skillFile = path.join(workDir, '.agents', entry.path);
104
+ assert.ok(fs.existsSync(skillFile), `missing transformed file: ${entry.path}`);
105
+ }
106
+ });
107
+ });
@@ -0,0 +1,86 @@
1
+ const { test, describe, beforeEach, afterEach } = require("node:test");
2
+ const assert = require("node:assert");
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
+ return spawnSync(process.execPath, [CLI_PATH, ...args], {
19
+ cwd: options.cwd || REPO_ROOT,
20
+ env,
21
+ encoding: "utf8",
22
+ });
23
+ }
24
+
25
+ describe("Spec Profile", () => {
26
+ let tempRoot;
27
+
28
+ beforeEach(() => {
29
+ tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ling-spec-test-"));
30
+ });
31
+
32
+ afterEach(() => {
33
+ fs.rmSync(tempRoot, { recursive: true, force: true });
34
+ });
35
+
36
+ test("spec status should report missing before enable", () => {
37
+ const result = runCli(["spec", "status", "--quiet"], {
38
+ env: { LING_GLOBAL_ROOT: tempRoot },
39
+ });
40
+ assert.strictEqual(result.status, 2);
41
+ assert.strictEqual((result.stdout || "").trim(), "missing");
42
+ });
43
+
44
+ test("spec enable should install skills and assets, and disable should remove them", () => {
45
+ const env = { LING_GLOBAL_ROOT: tempRoot };
46
+
47
+ const enableResult = runCli(["spec", "enable", "--target", "codex", "--quiet"], { env });
48
+ assert.strictEqual(enableResult.status, 0, enableResult.stderr || enableResult.stdout);
49
+
50
+ const codexSkill = path.join(tempRoot, ".codex", "skills", "harness-engineering", "SKILL.md");
51
+ const stateFile = path.join(tempRoot, ".ling", "spec", "state.json");
52
+ const templatesDir = path.join(tempRoot, ".ling", "spec", "templates");
53
+ const referencesDir = path.join(tempRoot, ".ling", "spec", "references");
54
+
55
+ assert.ok(fs.existsSync(codexSkill), "missing installed codex spec skill");
56
+ assert.ok(fs.existsSync(stateFile), "missing spec state");
57
+ assert.ok(fs.existsSync(path.join(templatesDir, "issues.template.csv")), "missing spec template");
58
+ assert.ok(fs.existsSync(path.join(referencesDir, "harness-engineering-digest.md")), "missing spec reference");
59
+
60
+ const statusResult = runCli(["spec", "status", "--quiet"], { env });
61
+ assert.strictEqual(statusResult.status, 0);
62
+ assert.strictEqual((statusResult.stdout || "").trim(), "installed");
63
+
64
+ const disableResult = runCli(["spec", "disable", "--target", "codex", "--quiet"], { env });
65
+ assert.strictEqual(disableResult.status, 0, disableResult.stderr || disableResult.stdout);
66
+ assert.ok(!fs.existsSync(path.join(tempRoot, ".codex", "skills", "harness-engineering")), "spec skill should be removed");
67
+ assert.ok(!fs.existsSync(stateFile), "spec state should be removed after final disable");
68
+ assert.ok(!fs.existsSync(templatesDir), "spec templates should be removed after final disable");
69
+ assert.ok(!fs.existsSync(referencesDir), "spec references should be removed after final disable");
70
+ });
71
+
72
+ test("spec disable should restore pre-existing skill backup", () => {
73
+ const env = { LING_GLOBAL_ROOT: tempRoot };
74
+ const skillDir = path.join(tempRoot, ".codex", "skills", "harness-engineering");
75
+ fs.mkdirSync(skillDir, { recursive: true });
76
+ fs.writeFileSync(path.join(skillDir, "SKILL.md"), "legacy skill", "utf8");
77
+
78
+ const enableResult = runCli(["spec", "enable", "--target", "codex", "--quiet"], { env });
79
+ assert.strictEqual(enableResult.status, 0, enableResult.stderr || enableResult.stdout);
80
+ assert.notStrictEqual(fs.readFileSync(path.join(skillDir, "SKILL.md"), "utf8"), "legacy skill");
81
+
82
+ const disableResult = runCli(["spec", "disable", "--target", "codex", "--quiet"], { env });
83
+ assert.strictEqual(disableResult.status, 0, disableResult.stderr || disableResult.stdout);
84
+ assert.strictEqual(fs.readFileSync(path.join(skillDir, "SKILL.md"), "utf8"), "legacy skill");
85
+ });
86
+ });
@@ -0,0 +1,303 @@
1
+ const { test, describe } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const REF_ROOT = path.resolve('reference/antigravity-kit');
7
+ const REF_AGENTS_ROOT = path.resolve('reference/antigravity-kit/.agents');
8
+ const REF_LEGACY_AGENT_ROOT = path.resolve('reference/antigravity-kit/.agent');
9
+ const REF_SCRIPTS_ROOT = fs.existsSync(REF_AGENTS_ROOT) ? REF_AGENTS_ROOT : REF_LEGACY_AGENT_ROOT;
10
+ const HAS_REF_SCRIPTS_ROOT = fs.existsSync(REF_SCRIPTS_ROOT);
11
+
12
+ function collectTokens(content, regex) {
13
+ const tokens = new Set();
14
+ for (const match of String(content || "").matchAll(regex)) {
15
+ tokens.add(match[1] || match[0]);
16
+ }
17
+ return tokens;
18
+ }
19
+
20
+ function collectFiles(rootDir, matcher) {
21
+ const matches = [];
22
+ const stack = [rootDir];
23
+ while (stack.length > 0) {
24
+ const current = stack.pop();
25
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
26
+ const abs = path.join(current, entry.name);
27
+ if (entry.isDirectory()) {
28
+ stack.push(abs);
29
+ continue;
30
+ }
31
+ if (matcher(abs)) {
32
+ matches.push(abs);
33
+ }
34
+ }
35
+ }
36
+ return matches.sort();
37
+ }
38
+
39
+ describe('Standards Compliance', () => {
40
+ test('all skill directories should include SKILL.md', () => {
41
+ const skillsRoot = path.resolve('.agents/skills');
42
+ assert.ok(fs.existsSync(skillsRoot), 'missing .agents/skills');
43
+
44
+ const skillDirs = fs
45
+ .readdirSync(skillsRoot, { withFileTypes: true })
46
+ .filter((entry) => entry.isDirectory())
47
+ .map((entry) => path.join(skillsRoot, entry.name));
48
+
49
+ for (const dir of skillDirs) {
50
+ const skillMd = path.join(dir, 'SKILL.md');
51
+ assert.ok(fs.existsSync(skillMd), `missing SKILL.md in ${path.relative(process.cwd(), dir)}`);
52
+ }
53
+ });
54
+
55
+ test('deprecated .codex primary-layout wording should be removed from user-facing docs and generator', () => {
56
+ const targets = [
57
+ 'README.md',
58
+ 'docs/PLAN.md',
59
+ 'docs/TECH.md',
60
+ 'bin/core/generator.js',
61
+ ];
62
+ const skipped = [];
63
+
64
+ for (const rel of targets) {
65
+ const abs = path.resolve(rel);
66
+ if (!fs.existsSync(abs)) {
67
+ skipped.push(rel);
68
+ continue;
69
+ }
70
+ const content = fs.readFileSync(abs, 'utf8');
71
+ assert.ok(!content.includes('Managed resources are synchronized under `.codex/`.'), `${rel} still contains deprecated .codex guidance`);
72
+ assert.ok(!content.includes('Do not edit files under `.codex/` directly.'), `${rel} still contains deprecated .codex guidance`);
73
+ }
74
+
75
+ if (skipped.length > 0) {
76
+ console.warn(`[standards-compliance] skipped missing optional files: ${skipped.join(', ')}`);
77
+ }
78
+ });
79
+
80
+ test('critical mechanism tokens should remain aligned with reference snapshot', { skip: !fs.existsSync(REF_ROOT) }, () => {
81
+ const refRoot = REF_ROOT;
82
+ const tokenRegex = /(ag-kit|ling|python3?|checklist\.py|verify_all\.py|security_scan\.py|ux_audit\.py|accessibility_checker\.py|schema_validator\.py|lint_runner\.py|type_coverage\.py|playwright_runner\.py|lighthouse_audit\.py|api_validator\.py|mobile_audit\.py|seo_checker\.py|geo_checker\.py|i18n_checker\.py|\.agent\/|\.agents\/|\.agents-backup\/|\.codex\/|AGENTS\.md|antigravity\.rules|ling\.rules|manifest\.json|--target|--targets|--fix|--path|--no-index|--dry-run|--quiet|--force)/g;
83
+ const slashCommandRegex = /(?:^|[\s`"'(\[])(\/(?:brainstorm|create|debug|deploy|enhance|orchestrate|plan|preview|status|test|ui-ux-pro-max))(?=$|[\s`"',。,.::)\]])/gm;
84
+
85
+ const markdownFiles = [];
86
+ const stack = [refRoot];
87
+ while (stack.length > 0) {
88
+ const current = stack.pop();
89
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
90
+ const abs = path.join(current, entry.name);
91
+ if (entry.isDirectory()) {
92
+ stack.push(abs);
93
+ continue;
94
+ }
95
+ if (/\.(md|mdx|txt)$/i.test(entry.name)) {
96
+ markdownFiles.push(abs);
97
+ }
98
+ }
99
+ }
100
+
101
+ const mismatches = [];
102
+ for (const refFile of markdownFiles) {
103
+ const rel = path.relative(refRoot, refFile);
104
+ const localFile = path.resolve(rel);
105
+ if (!fs.existsSync(localFile)) continue;
106
+
107
+ const refContent = fs.readFileSync(refFile, 'utf8');
108
+ const refTokens = new Set([
109
+ ...collectTokens(refContent, tokenRegex),
110
+ ...collectTokens(refContent, slashCommandRegex),
111
+ ]);
112
+ if (refTokens.size === 0) continue;
113
+
114
+ const localContent = fs.readFileSync(localFile, 'utf8');
115
+ const localTokens = new Set([
116
+ ...collectTokens(localContent, tokenRegex),
117
+ ...collectTokens(localContent, slashCommandRegex),
118
+ ]);
119
+
120
+ const missing = [...refTokens].filter((token) => !localTokens.has(token));
121
+ if (missing.length > 0) {
122
+ mismatches.push({ rel, missing });
123
+ }
124
+ }
125
+
126
+ assert.strictEqual(
127
+ mismatches.length,
128
+ 0,
129
+ `critical mechanism tokens drifted:\n${mismatches
130
+ .slice(0, 10)
131
+ .map((item) => `${item.rel} -> ${item.missing.join(', ')}`)
132
+ .join('\n')}`,
133
+ );
134
+ });
135
+
136
+ test('user-facing docs should track current repo and global skill locations', () => {
137
+ const file = path.resolve('docs/TECH.md');
138
+ const content = fs.readFileSync(file, 'utf8');
139
+
140
+ assert.ok(content.includes('$HOME/.codex/skills/'), 'missing global skill path: $HOME/.codex/skills/');
141
+ assert.ok(content.includes('$HOME/.gemini/skills/'), 'missing global skill path: $HOME/.gemini/skills/');
142
+ assert.ok(content.includes('$HOME/.gemini/antigravity/skills/'), 'missing global skill path: $HOME/.gemini/antigravity/skills/');
143
+ assert.ok(content.includes('.agents/skills'), 'missing repo skill path: .agents/skills');
144
+ assert.ok(!content.includes('$HOME/.agents/skills/'), 'should not contain deprecated global path: $HOME/.agents/skills/');
145
+ });
146
+
147
+ test('.agents script files should stay identical to reference snapshot', { skip: !HAS_REF_SCRIPTS_ROOT }, () => {
148
+ const refScriptsRoot = REF_SCRIPTS_ROOT;
149
+ const mismatches = [];
150
+
151
+ const stack = [refScriptsRoot];
152
+ while (stack.length > 0) {
153
+ const current = stack.pop();
154
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
155
+ const abs = path.join(current, entry.name);
156
+ if (entry.isDirectory()) {
157
+ stack.push(abs);
158
+ continue;
159
+ }
160
+ if (!abs.includes(`${path.sep}scripts${path.sep}`)) continue;
161
+ if (abs.includes(`${path.sep}__pycache__${path.sep}`) || abs.endsWith('.pyc')) continue;
162
+
163
+ const rel = path.relative(refScriptsRoot, abs);
164
+ const localFile = path.resolve('.agents', rel);
165
+ if (!fs.existsSync(localFile)) {
166
+ mismatches.push(`${rel} (missing local file)`);
167
+ continue;
168
+ }
169
+
170
+ const refContent = fs.readFileSync(abs, 'utf8');
171
+ const localContent = fs.readFileSync(localFile, 'utf8');
172
+ if (refContent !== localContent) {
173
+ mismatches.push(rel);
174
+ }
175
+ }
176
+ }
177
+
178
+ assert.strictEqual(
179
+ mismatches.length,
180
+ 0,
181
+ `script content drifted:\n${mismatches.slice(0, 20).join('\n')}`,
182
+ );
183
+ });
184
+
185
+ test('critical path handling should avoid hardcoded platform separators in managed paths', () => {
186
+ const adapterFile = path.resolve('bin/adapters/codex.js');
187
+ const content = fs.readFileSync(adapterFile, 'utf8');
188
+
189
+ // Keep this focused on managed path constants that must remain path.join-driven.
190
+ assert.ok(content.includes('path.join'), 'codex adapter should use path.join for managed paths');
191
+ assert.ok(content.includes('os.tmpdir()'), 'codex adapter should use os.tmpdir() for temp paths');
192
+ });
193
+
194
+ test('cli and maintenance scripts should avoid emoji output markers', () => {
195
+ const targetFiles = [
196
+ ...collectFiles(path.resolve('bin'), (abs) => abs.endsWith('.js')),
197
+ ...collectFiles(path.resolve('scripts'), (abs) => abs.endsWith('.js')),
198
+ ];
199
+ const emojiRegex = /[\u{2600}-\u{27BF}\u{1F300}-\u{1FAFF}]/u;
200
+ const offenders = [];
201
+
202
+ for (const file of targetFiles) {
203
+ const content = fs.readFileSync(file, 'utf8');
204
+ if (emojiRegex.test(content)) {
205
+ offenders.push(path.relative(process.cwd(), file));
206
+ }
207
+ }
208
+
209
+ assert.deepStrictEqual(offenders, [], `cli/script files should not contain emoji markers:\n${offenders.join('\n')}`);
210
+ });
211
+
212
+ test('official antigravity docs baselines should be present in localized pages', () => {
213
+ const checks = [
214
+ {
215
+ file: 'web/src/app/docs/skills/page.tsx',
216
+ required: [
217
+ 'SKILL.md',
218
+ 'workspace-root',
219
+ '~/.gemini/antigravity/skills',
220
+ 'description',
221
+ 'scripts/',
222
+ 'examples/',
223
+ 'resources/',
224
+ 'Discovery',
225
+ 'Activation',
226
+ 'Execution',
227
+ '--help',
228
+ ],
229
+ },
230
+ {
231
+ file: 'web/src/app/docs/rules-workflows/page.tsx',
232
+ required: [
233
+ '12,000',
234
+ '~/.gemini/GEMINI.md',
235
+ '.agent/rules',
236
+ 'Manual',
237
+ 'Always On',
238
+ 'Model Decision',
239
+ 'Glob',
240
+ '@filename',
241
+ '/workflow-name',
242
+ ],
243
+ },
244
+ {
245
+ file: 'web/src/app/docs/task-groups/page.tsx',
246
+ required: ['规划模式', '总体目标', '已编辑文件', '待处理区'],
247
+ },
248
+ {
249
+ file: 'web/src/app/docs/strict-mode/page.tsx',
250
+ required: ['Allowlist/Denylist', 'Request Review', '.gitignore', '工作区隔离'],
251
+ },
252
+ {
253
+ file: 'web/src/app/docs/sandbox-mode/page.tsx',
254
+ required: [
255
+ 'sandbox-exec',
256
+ 'Enable Terminal Sandboxing',
257
+ 'Sandbox Allow Network',
258
+ 'Bypass Sandbox',
259
+ 'Strict Mode',
260
+ ],
261
+ },
262
+ {
263
+ file: 'web/src/app/docs/mcp/page.tsx',
264
+ required: [
265
+ 'Model Context Protocol',
266
+ 'MCP Store',
267
+ 'Manage MCP Servers',
268
+ 'View raw config',
269
+ 'mcp_config.json',
270
+ ],
271
+ },
272
+ {
273
+ file: 'web/src/app/docs/command/page.tsx',
274
+ required: ['Command + I', 'Ctrl + I'],
275
+ },
276
+ {
277
+ file: 'web/src/app/docs/allowlist-denylist/page.tsx',
278
+ required: ['BadUrlsChecker', 'always allow', 'localhost'],
279
+ },
280
+ {
281
+ file: 'web/src/app/docs/browser-subagent/page.tsx',
282
+ required: ['DOM 捕获', '截图', '蓝色边框'],
283
+ },
284
+ ];
285
+
286
+ const missing = [];
287
+ for (const { file, required } of checks) {
288
+ const abs = path.resolve(file);
289
+ const content = fs.readFileSync(abs, 'utf8');
290
+ for (const token of required) {
291
+ if (!content.includes(token)) {
292
+ missing.push(`${file} -> ${token}`);
293
+ }
294
+ }
295
+ }
296
+
297
+ assert.strictEqual(
298
+ missing.length,
299
+ 0,
300
+ `localized docs missing official baseline tokens:\n${missing.join('\n')}`,
301
+ );
302
+ });
303
+ });
@@ -0,0 +1,74 @@
1
+ const { test, describe, beforeEach, afterEach } = require("node:test");
2
+ const assert = require("node:assert");
3
+ const fs = require("fs");
4
+ const os = require("os");
5
+ const path = require("path");
6
+ const ResourceTransformer = require("../bin/core/transformer");
7
+
8
+ describe("ResourceTransformer", () => {
9
+ let tempDir;
10
+
11
+ beforeEach(() => {
12
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ag-kit-transformer-test-"));
13
+ });
14
+
15
+ afterEach(() => {
16
+ fs.rmSync(tempDir, { recursive: true, force: true });
17
+ });
18
+
19
+ function transformWorkflow(markdown) {
20
+ const workflowPath = path.join(tempDir, "workflow.md");
21
+ fs.writeFileSync(workflowPath, markdown, "utf8");
22
+
23
+ const result = ResourceTransformer.transform({
24
+ skills: [],
25
+ workflows: [{ name: "demo", path: workflowPath, type: "workflow" }],
26
+ });
27
+
28
+ return result.mappedFiles.find((item) => item.destPath.endsWith("/SKILL.md"));
29
+ }
30
+
31
+ test("workflow frontmatter should parse CRLF and keep colon in description", () => {
32
+ const mapped = transformWorkflow([
33
+ "---\r",
34
+ "description: \"Run /debug: inspect failures\"\r",
35
+ "---\r",
36
+ "",
37
+ "# Workflow body",
38
+ ].join("\n"));
39
+
40
+ assert.ok(mapped);
41
+ assert.ok(mapped.content.includes("description: \"Run /debug: inspect failures\""));
42
+ assert.ok(mapped.content.includes("# Workflow body"));
43
+ });
44
+
45
+ test("workflow frontmatter should parse folded multiline description", () => {
46
+ const mapped = transformWorkflow([
47
+ "---",
48
+ "description: >",
49
+ " 先执行 /plan",
50
+ " 再执行 /debug",
51
+ "---",
52
+ "",
53
+ "# Workflow body",
54
+ ].join("\n"));
55
+
56
+ assert.ok(mapped);
57
+ assert.ok(mapped.content.includes("description: \"先执行 /plan 再执行 /debug\""));
58
+ });
59
+
60
+ test("workflow frontmatter should parse indented multiline description", () => {
61
+ const mapped = transformWorkflow([
62
+ "---",
63
+ "description:",
64
+ " 统一排查流程: 先收集日志",
65
+ " 再定位根因",
66
+ "---",
67
+ "",
68
+ "# Workflow body",
69
+ ].join("\n"));
70
+
71
+ assert.ok(mapped);
72
+ assert.ok(mapped.content.includes("description: \"统一排查流程: 先收集日志 再定位根因\""));
73
+ });
74
+ });
@@ -0,0 +1,51 @@
1
+ const { test } = require("node:test");
2
+ const assert = require("node:assert");
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 LING_CLI = path.join(REPO_ROOT, "bin", "ling.js");
10
+ const AG_KIT_CLI = path.join(REPO_ROOT, "bin", "ag-kit.js");
11
+ const pkg = require(path.join(REPO_ROOT, "package.json"));
12
+
13
+ function runCli(cliPath, args, envOverrides = {}) {
14
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ling-version-test-"));
15
+ const env = {
16
+ ...process.env,
17
+ LING_SKIP_UPSTREAM_CHECK: "1",
18
+ LING_INDEX_PATH: path.join(tempRoot, "workspaces.json"),
19
+ ...envOverrides,
20
+ };
21
+
22
+ const result = spawnSync(process.execPath, [cliPath, ...args], {
23
+ cwd: REPO_ROOT,
24
+ env,
25
+ encoding: "utf8",
26
+ });
27
+
28
+ fs.rmSync(tempRoot, { recursive: true, force: true });
29
+ return result;
30
+ }
31
+
32
+ test("npm package version should remain SemVer", () => {
33
+ assert.match(pkg.version, /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/);
34
+ });
35
+
36
+ test("ling --version should print ling- prefixed version tag", () => {
37
+ const result = runCli(LING_CLI, ["--version"]);
38
+ assert.strictEqual(result.status, 0, result.stderr || result.stdout);
39
+ const stdout = String(result.stdout || "").trim();
40
+ assert.strictEqual(stdout, `ling version ling-${pkg.version}`);
41
+ assert.ok(!stdout.includes("[warn]"), "ling entry should not include legacy alias warning");
42
+ });
43
+
44
+ test("ag-kit --version should warn and print ling- prefixed version tag", () => {
45
+ const result = runCli(AG_KIT_CLI, ["--version"]);
46
+ assert.strictEqual(result.status, 0, result.stderr || result.stdout);
47
+ const lines = String(result.stdout || "").trim().split(/\r?\n/);
48
+ assert.ok(lines.some((line) => line.includes("[warn]")), "ag-kit entry should include legacy alias warning");
49
+ assert.strictEqual(lines[lines.length - 1], `ling version ling-${pkg.version}`);
50
+ });
51
+