From 27a460f5d7efb4d520cf491b1ead03faf639b495 Mon Sep 17 00:00:00 2001 From: diepcd Date: Sat, 30 May 2026 20:13:29 +0700 Subject: [PATCH] feat(antigravity): add full skill-based editor support --- CHANGELOG.md | 6 + README.md | 9 +- bin/cli.js | 4 +- bun.lock | 120 ++++++++++++++++++++ src/commands/install.ts | 233 ++++++++++++++++++++++++++++++++++++-- src/commands/list.ts | 36 ++++++ src/commands/status.ts | 35 ++++++ src/commands/uninstall.ts | 81 +++++++++++-- src/utils/symlink.ts | 15 ++- 9 files changed, 512 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a267b1..611bb60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.2.0](https://github.com/phuthuycoding/moicle/compare/v2.1.0...v2.2.0) (2026-05-30) + +### Features + +* **antigravity:** add full skill-based support for Antigravity editor with dedicated installation, architecture, and skill mapping flows + ## [2.1.0](https://github.com/phuthuycoding/moicle/compare/v2.0.0...v2.1.0) (2026-05-26) ### Features diff --git a/README.md b/README.md index 8610a5c..37795bc 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ A toolkit to bootstrap and accelerate project development with Claude Code throu - [x] Claude - [x] Codex CLI -- [ ] Antigravity +- [x] Antigravity - [ ] Cursor - [ ] Windsurf @@ -43,8 +43,11 @@ moicle install # Install for Codex CLI moicle install --target codex --global +# Install for Antigravity +moicle install --target antigravity --global + # Choose: -# 1. Pick Claude Code or Codex CLI +# 1. Pick Claude Code, Codex CLI, or Antigravity # 2. Pick global or project scope ``` @@ -211,6 +214,8 @@ When an agent is invoked, it **reads the architecture file first** before coding For Codex CLI, MoiCle installs architecture docs into `~/.codex/architecture` or `./.codex/architecture`, and converts MoiCle agents, commands, and existing skills into native Codex skills under `.codex/skills`. Restart Codex after a global install so the new skills are loaded. +For Antigravity, MoiCle installs architecture docs into `~/.gemini/architecture` or `./.gemini/architecture`, and converts MoiCle agents, commands, and existing skills into native Antigravity skills under `.gemini/skills`. + ## Usage Examples ### Using Commands diff --git a/bin/cli.js b/bin/cli.js index 1541299..1fb7ebf 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -46,7 +46,7 @@ program .description('List installed agents, commands, and skills') .option('-g, --global', 'List global installations') .option('-p, --project', 'List project installations') - .option('-t, --target ', 'Target editor (claude, codex)') + .option('-t, --target ', 'Target editor (claude, codex, antigravity)') .action(listCommand); program @@ -75,7 +75,7 @@ program .description('Show enabled/disabled status of all items') .option('-g, --global', 'Show global status') .option('-p, --project', 'Show project status') - .option('-t, --target ', 'Target editor (claude, codex)') + .option('-t, --target ', 'Target editor (claude, codex, antigravity)') .action(statusCommand); program diff --git a/bun.lock b/bun.lock index 797c6c3..cd4094e 100644 --- a/bun.lock +++ b/bun.lock @@ -13,27 +13,47 @@ "devDependencies": { "@types/inquirer": "^9.0.7", "@types/node": "^20.11.0", + "conventional-changelog-cli": "^5.0.0", + "conventional-changelog-conventionalcommits": "^8.0.0", "typescript": "^5.3.3", }, }, }, "packages": { + "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], + + "@conventional-changelog/git-client": ["@conventional-changelog/git-client@2.7.0", "", { "dependencies": { "@simple-libs/child-process-utils": "^1.0.0", "@simple-libs/stream-utils": "^1.2.0", "semver": "^7.5.2" }, "peerDependencies": { "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.4.0" }, "optionalPeers": ["conventional-commits-filter", "conventional-commits-parser"] }, "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw=="], + + "@hutson/parse-repository-url": ["@hutson/parse-repository-url@5.0.0", "", {}, "sha512-e5+YUKENATs1JgYHMzTr2MW/NDcXGfYFAuOQU8gJgF/kEh4EqKgfGrfLI67bMD4tbhZVlkigz/9YYwWcbOFthg=="], + "@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="], "@inquirer/figures": ["@inquirer/figures@1.0.15", "", {}, "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g=="], + "@simple-libs/child-process-utils": ["@simple-libs/child-process-utils@1.0.2", "", { "dependencies": { "@simple-libs/stream-utils": "^1.2.0" } }, "sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw=="], + + "@simple-libs/stream-utils": ["@simple-libs/stream-utils@1.2.0", "", {}, "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA=="], + "@types/inquirer": ["@types/inquirer@9.0.9", "", { "dependencies": { "@types/through": "*", "rxjs": "^7.2.0" } }, "sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw=="], "@types/node": ["@types/node@20.19.28", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-VyKBr25BuFDzBFCK5sUM6ZXiWfqgCTwTAOK8qzGV/m9FCirXYDlmczJ+d5dXBAQALGCdRRdbteKYfJ84NGEusw=="], + "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], + "@types/through": ["@types/through@0.0.33", "", { "dependencies": { "@types/node": "*" } }, "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ=="], + "add-stream": ["add-stream@1.0.0", "", {}, "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ=="], + "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "array-ify": ["array-ify@1.0.0", "", {}, "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], @@ -58,18 +78,66 @@ "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="], + + "conventional-changelog": ["conventional-changelog@6.0.0", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-atom": "^5.0.0", "conventional-changelog-codemirror": "^5.0.0", "conventional-changelog-conventionalcommits": "^8.0.0", "conventional-changelog-core": "^8.0.0", "conventional-changelog-ember": "^5.0.0", "conventional-changelog-eslint": "^6.0.0", "conventional-changelog-express": "^5.0.0", "conventional-changelog-jquery": "^6.0.0", "conventional-changelog-jshint": "^5.0.0", "conventional-changelog-preset-loader": "^5.0.0" } }, "sha512-tuUH8H/19VjtD9Ig7l6TQRh+Z0Yt0NZ6w/cCkkyzUbGQTnUEmKfGtkC9gGfVgCfOL1Rzno5NgNF4KY8vR+Jo3w=="], + + "conventional-changelog-angular": ["conventional-changelog-angular@8.3.1", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg=="], + + "conventional-changelog-atom": ["conventional-changelog-atom@5.1.0", "", {}, "sha512-fw7GpI9jHNCWGBnTsPRI452ypQbNupGwsjrXfozvRNE0c92pJRpoj9rXfzDKUYJcsmk0H4XKaQjhjelwI9z27w=="], + + "conventional-changelog-cli": ["conventional-changelog-cli@5.0.0", "", { "dependencies": { "add-stream": "^1.0.0", "conventional-changelog": "^6.0.0", "meow": "^13.0.0", "tempfile": "^5.0.0" }, "bin": { "conventional-changelog": "cli.js" } }, "sha512-9Y8fucJe18/6ef6ZlyIlT2YQUbczvoQZZuYmDLaGvcSBP+M6h+LAvf7ON7waRxKJemcCII8Yqu5/8HEfskTxJQ=="], + + "conventional-changelog-codemirror": ["conventional-changelog-codemirror@5.1.0", "", {}, "sha512-iXhy63YczB+yWA9DrsYbquSYLvWKsK9M3WC+xQPEm8cOn4oXzKpmTp2uH3qi7+i10oTcGJTvq9lsBpZmMADaNg=="], + + "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@8.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA=="], + + "conventional-changelog-core": ["conventional-changelog-core@8.0.0", "", { "dependencies": { "@hutson/parse-repository-url": "^5.0.0", "add-stream": "^1.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-parser": "^6.0.0", "git-raw-commits": "^5.0.0", "git-semver-tags": "^8.0.0", "hosted-git-info": "^7.0.0", "normalize-package-data": "^6.0.0", "read-package-up": "^11.0.0", "read-pkg": "^9.0.0" } }, "sha512-EATUx5y9xewpEe10UEGNpbSHRC6cVZgO+hXQjofMqpy+gFIrcGvH3Fl6yk2VFKh7m+ffenup2N7SZJYpyD9evw=="], + + "conventional-changelog-ember": ["conventional-changelog-ember@5.1.0", "", {}, "sha512-XNcgGcdJt7wh341BBML0CI8DKpqE5lKD1WahzFHGZFvKTzJr1rZW976cw7beqKLOBbzdrH9ZIkE/s2TfbOuM3g=="], + + "conventional-changelog-eslint": ["conventional-changelog-eslint@6.1.0", "", {}, "sha512-beWr3qzuEMN9gznMWa8PhTVfGkGXoq+XnUzViNXg5KygrgV728ZRqZngz3uPhz5+ayUhPrpNFYqIE0qHWz9NAw=="], + + "conventional-changelog-express": ["conventional-changelog-express@5.1.0", "", {}, "sha512-g/s9eLohrefYTSNQaB6+k0ONbiVx41YOKBbIOIM3ST/NtedAgppCJnrpKXVN9sOmpPkN4vjFwURlfvpEDUjoeg=="], + + "conventional-changelog-jquery": ["conventional-changelog-jquery@6.1.0", "", {}, "sha512-/sFhULybhFrMg+qc8MHHHSj7kTVMfx5C7rSM6Z9EjduVoAQJdGRq/wpv/SWPMQ+KPNSYHqDLwm/x2Z5hOcYvqQ=="], + + "conventional-changelog-jshint": ["conventional-changelog-jshint@5.2.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-OaatyvHXP1fjI7Mx0b1IkmhbhTsVHsytnsQSkOj4rhGbFMoTcfvbwm/vAtCzRMXOxojK1EDMBBmBj1pM9KNy/Q=="], + + "conventional-changelog-preset-loader": ["conventional-changelog-preset-loader@5.0.0", "", {}, "sha512-SetDSntXLk8Jh1NOAl1Gu5uLiCNSYenB5tm0YVeZKePRIgDW9lQImromTwLa3c/Gae298tsgOM+/CYT9XAl0NA=="], + + "conventional-changelog-writer": ["conventional-changelog-writer@8.4.0", "", { "dependencies": { "@simple-libs/stream-utils": "^1.2.0", "conventional-commits-filter": "^5.0.0", "handlebars": "^4.7.7", "meow": "^13.0.0", "semver": "^7.5.2" }, "bin": { "conventional-changelog-writer": "dist/cli/index.js" } }, "sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g=="], + + "conventional-commits-filter": ["conventional-commits-filter@5.0.0", "", {}, "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q=="], + + "conventional-commits-parser": ["conventional-commits-parser@6.4.0", "", { "dependencies": { "@simple-libs/stream-utils": "^1.2.0", "meow": "^13.0.0" }, "bin": { "conventional-commits-parser": "dist/cli/index.js" } }, "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw=="], + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "find-up-simple": ["find-up-simple@1.0.1", "", {}, "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ=="], + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + "git-raw-commits": ["git-raw-commits@5.0.1", "", { "dependencies": { "@conventional-changelog/git-client": "^2.6.0", "meow": "^13.0.0" }, "bin": { "git-raw-commits": "src/cli.js" } }, "sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ=="], + + "git-semver-tags": ["git-semver-tags@8.0.1", "", { "dependencies": { "@conventional-changelog/git-client": "^2.6.0", "meow": "^13.0.0" }, "bin": { "git-semver-tags": "src/cli.js" } }, "sha512-zMbamckSNdlT4U48IMFa2Cn6FTzM+2yF6/gEmStPJI8PiLxd/bT6dw10+mc6u5Qe4fhrc/y9nU290FWjQhAV7g=="], + + "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], + "iconv-lite": ["iconv-lite@0.7.1", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "inquirer": ["inquirer@9.3.8", "", { "dependencies": { "@inquirer/external-editor": "^1.0.2", "@inquirer/figures": "^1.0.3", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "1.0.0", "ora": "^5.4.1", "run-async": "^3.0.0", "rxjs": "^7.8.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" } }, "sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w=="], @@ -78,20 +146,42 @@ "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], + "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="], + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="], + "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], + "parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="], + + "read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], @@ -104,8 +194,20 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "semver": ["semver@7.8.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -116,18 +218,30 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "temp-dir": ["temp-dir@3.0.0", "", {}, "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw=="], + + "tempfile": ["tempfile@5.0.0", "", { "dependencies": { "temp-dir": "^3.0.0" } }, "sha512-bX655WZI/F7EoTDw9JvQURqAXiPHi8o8+yFxPF2lWYyz1aHnmMRuXWqL6YB6GmeO0o4DIYWHLgGNi/X64T+X4Q=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], @@ -140,6 +254,12 @@ "ora/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + "parse-json/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "read-package-up/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "read-pkg/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + "inquirer/ora/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "inquirer/ora/cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], diff --git a/src/commands/install.ts b/src/commands/install.ts index e307aea..a5145d3 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -17,6 +17,7 @@ import { getArchitectureDir, getClaudeDir, getCodexDir, + getAntigravityDir, getEditorDir, getEditorConfig, getFiles, @@ -177,10 +178,17 @@ const installScope = async (scope: Scope, useSymlink: boolean): Promise => console.log(chalk.green(`✓ ${label} installation complete!`)); }; -const rewriteClaudePaths = (content: string, target: 'claude' | 'codex'): string => { +const rewriteClaudePaths = (content: string, target: 'claude' | 'codex' | 'antigravity'): string => { if (target === 'claude') { return content; } + if (target === 'antigravity') { + return content + .replace(/~\/\.claude\//g, '~/.gemini/') + .replace(/\.claude\//g, '.gemini/') + .replace(/Claude Code/g, 'Antigravity') + .replace(/CLAUDE\.md/g, 'GEMINI.md'); + } return content .replace(/~\/\.claude\//g, '~/.codex/') @@ -400,6 +408,198 @@ const installCodexScope = async (scope: Scope): Promise => { console.log(chalk.green(`✓ ${label} Codex installation complete!`)); }; +const ensureAntigravitySkillDir = (baseDir: string, name: string): string => { + const skillDir = path.join(baseDir, name); + ensureDir(skillDir); + return skillDir; +}; + +const installAntigravitySkillFolder = ( + sourceDir: string, + targetSkillsDir: string +): FileResult => { + const skillName = path.basename(sourceDir); + const targetDir = ensureAntigravitySkillDir(targetSkillsDir, skillName); + const sourceFiles = getFiles(sourceDir, 8); + + let status: FileResult['status'] = 'created'; + for (const file of sourceFiles) { + const relativePath = path.relative(sourceDir, file); + const targetFile = path.join(targetDir, relativePath); + ensureDir(path.dirname(targetFile)); + + const content = rewriteClaudePaths(fs.readFileSync(file, 'utf-8'), 'antigravity'); + const existed = fs.existsSync(targetFile); + if (existed && fs.readFileSync(targetFile, 'utf-8') === content) { + status = status === 'created' ? 'exists' : status; + continue; + } + + fs.writeFileSync(targetFile, content); + if (existed) { + status = 'updated'; + } + } + + return { status, name: skillName }; +}; + +const buildGeneratedAntigravitySkill = ( + name: string, + description: string, + body: string +): string => `--- +name: ${name} +description: ${description} +--- + +${body} +`; + +const installGeneratedAntigravitySkill = ( + targetSkillsDir: string, + name: string, + description: string, + body: string +): FileResult => { + const skillDir = ensureAntigravitySkillDir(targetSkillsDir, name); + const targetFile = path.join(skillDir, 'SKILL.md'); + const content = buildGeneratedAntigravitySkill(name, description, rewriteClaudePaths(body, 'antigravity')); + + if (fs.existsSync(targetFile)) { + if (fs.readFileSync(targetFile, 'utf-8') === content) { + return { status: 'exists', name }; + } + fs.writeFileSync(targetFile, content); + return { status: 'updated', name }; + } + + fs.writeFileSync(targetFile, content); + return { status: 'created', name }; +}; + +const installDirectAntigravitySkill = ( + targetSkillsDir: string, + name: string, + content: string +): FileResult => { + const skillDir = ensureAntigravitySkillDir(targetSkillsDir, name); + const targetFile = path.join(skillDir, 'SKILL.md'); + const rewritten = rewriteClaudePaths(content, 'antigravity'); + + if (fs.existsSync(targetFile)) { + if (fs.readFileSync(targetFile, 'utf-8') === rewritten) { + return { status: 'exists', name }; + } + fs.writeFileSync(targetFile, rewritten); + return { status: 'updated', name }; + } + + fs.writeFileSync(targetFile, rewritten); + return { status: 'created', name }; +}; + +const installAntigravityArchitecture = (targetDir: string): FileResult[] => { + const results: FileResult[] = []; + const archDir = path.join(ASSETS_DIR, 'architecture'); + const targetArchDir = path.join(targetDir, 'architecture'); + + ensureDir(targetArchDir); + + if (!fs.existsSync(archDir)) { + return results; + } + + for (const file of getFiles(archDir)) { + const targetFile = path.join(targetArchDir, path.basename(file)); + const content = rewriteClaudePaths(fs.readFileSync(file, 'utf-8'), 'antigravity'); + if (fs.existsSync(targetFile)) { + if (fs.readFileSync(targetFile, 'utf-8') === content) { + results.push({ status: 'exists', name: path.basename(file) }); + continue; + } + fs.writeFileSync(targetFile, content); + results.push({ status: 'updated', name: path.basename(file) }); + continue; + } + + fs.writeFileSync(targetFile, content); + results.push({ status: 'created', name: path.basename(file) }); + } + + return results; +}; + +const installAntigravitySkills = (targetDir: string): FileResult[] => { + const results: FileResult[] = []; + const targetSkillsDir = path.join(targetDir, 'skills'); + ensureDir(targetSkillsDir); + + const skillsDir = path.join(ASSETS_DIR, 'skills'); + if (fs.existsSync(skillsDir)) { + for (const dir of getDirs(skillsDir)) { + results.push(installAntigravitySkillFolder(dir, targetSkillsDir)); + } + } + + const commandsDir = path.join(ASSETS_DIR, 'commands'); + if (fs.existsSync(commandsDir)) { + for (const file of getFiles(commandsDir)) { + const name = path.basename(file, '.md'); + const content = fs.readFileSync(file, 'utf-8'); + results.push(installDirectAntigravitySkill(targetSkillsDir, name, content)); + } + } + + const agentDirs = ['developers', 'utilities']; + for (const dirName of agentDirs) { + const sourceDir = path.join(ASSETS_DIR, 'agents', dirName); + if (!fs.existsSync(sourceDir)) { + continue; + } + + for (const file of getFiles(sourceDir)) { + const name = path.basename(file, '.md'); + const rawContent = fs.readFileSync(file, 'utf-8'); + const parsed = extractFrontmatter(rawContent); + const description = parsed.description + ? parsed.description + : dirName === 'developers' + ? `Imported MoiCle developer persona for ${name}. Use when the task matches this stack specialist.` + : `Imported MoiCle utility persona for ${name}. Use when the task matches this specialist.`; + + results.push(installGeneratedAntigravitySkill(targetSkillsDir, name, description, parsed.body.trimStart())); + } + } + + return results; +}; + +const installAntigravityScope = async (scope: Scope): Promise => { + const isGlobal = scope === 'global'; + const label = isGlobal ? 'Global' : 'Project'; + const targetPath = isGlobal ? '~/.gemini/' : `${process.cwd()}/.gemini/`; + + console.log(''); + console.log(chalk.cyan(`>>> ${label} Antigravity Installation`)); + console.log(chalk.gray(` Target: ${targetPath}`)); + console.log(''); + + const antigravityDir = getAntigravityDir(scope); + ensureDir(antigravityDir); + + const archResults = installAntigravityArchitecture(antigravityDir); + console.log(chalk.green(` ✓ Architecture installed to ${chalk.cyan(path.join(antigravityDir, 'architecture'))}`)); + printSummary(archResults); + + const skillResults = installAntigravitySkills(antigravityDir); + console.log(chalk.green(` ✓ Antigravity skills installed to ${chalk.cyan(path.join(antigravityDir, 'skills'))}`)); + printSummary(skillResults); + + console.log(''); + console.log(chalk.green(`✓ ${label} Antigravity installation complete!`)); +}; + const showTargetMenu = async (): Promise => { const { target } = await inquirer.prompt([ { @@ -409,6 +609,7 @@ const showTargetMenu = async (): Promise => { choices: [ { name: 'Claude Code', value: 'claude' }, { name: 'Codex CLI', value: 'codex' }, + { name: 'Antigravity', value: 'antigravity' }, ], }, ]); @@ -417,10 +618,10 @@ const showTargetMenu = async (): Promise => { }; const showInteractiveMenu = async ( - target: 'claude' | 'codex' + target: 'claude' | 'codex' | 'antigravity' ): Promise<'global' | 'project' | 'all'> => { - const globalPath = target === 'claude' ? '~/.claude/' : '~/.codex/'; - const projectPath = target === 'claude' ? './.claude/' : './.codex/'; + const globalPath = target === 'claude' ? '~/.claude/' : target === 'codex' ? '~/.codex/' : '~/.gemini/'; + const projectPath = target === 'claude' ? './.claude/' : target === 'codex' ? './.codex/' : './.gemini/'; const { installType } = await inquirer.prompt([ { @@ -529,7 +730,7 @@ export const installCommand = async (options: CommandOptions): Promise => for (const target of targets) { addTarget(target); - if (target === 'claude' || target === 'codex') { + if (target === 'claude' || target === 'codex' || target === 'antigravity') { let installType: 'global' | 'project' | 'all'; if (options.global) { @@ -546,24 +747,31 @@ export const installCommand = async (options: CommandOptions): Promise => case 'global': if (target === 'claude') { await installScope('global', useSymlink); - } else { + } else if (target === 'codex') { await installCodexScope('global'); + } else { + await installAntigravityScope('global'); } break; case 'project': if (target === 'claude') { await installScope('project', false); - } else { + } else if (target === 'codex') { await installCodexScope('project'); + } else { + await installAntigravityScope('project'); } break; case 'all': if (target === 'claude') { await installScope('global', useSymlink); await installScope('project', false); - } else { + } else if (target === 'codex') { await installCodexScope('global'); await installCodexScope('project'); + } else { + await installAntigravityScope('global'); + await installAntigravityScope('project'); } break; } @@ -604,7 +812,14 @@ export const installCommand = async (options: CommandOptions): Promise => console.log(''); } - const otherTargets = targets.filter((t) => t !== 'claude' && t !== 'codex'); + if (targets.includes('antigravity')) { + console.log(chalk.bold(' Antigravity:')); + console.log(chalk.gray(' Skills installed under ~/.gemini/skills or ./.gemini/skills')); + console.log(chalk.gray(' Architecture docs installed under ~/.gemini/architecture or ./.gemini/architecture')); + console.log(''); + } + + const otherTargets = targets.filter((t) => t !== 'claude' && t !== 'codex' && t !== 'antigravity'); if (otherTargets.length > 0) { console.log(chalk.bold(' Other Editors:')); for (const target of otherTargets) { diff --git a/src/commands/list.ts b/src/commands/list.ts index e0859e6..20e5c37 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -11,6 +11,7 @@ import { getSkillsDir, getClaudeDir, getCodexDir, + getAntigravityDir, } from '../utils/symlink.js'; const printHeader = (): void => { @@ -112,6 +113,29 @@ const listCodexScope = (scope: Scope): void => { console.log(''); }; +const listAntigravityScope = (scope: Scope): void => { + const antigravityDir = getAntigravityDir(scope); + const label = + scope === 'global' ? 'Global (~/.gemini/)' : `Project (${process.cwd()}/.gemini/)`; + + console.log(chalk.cyan(`>>> ${label}`)); + console.log(''); + + if (!fs.existsSync(antigravityDir)) { + console.log(chalk.gray(' Not installed')); + console.log(''); + return; + } + + console.log(chalk.yellow(' Architecture:')); + printPlainItems(listItems(path.join(antigravityDir, 'architecture')), 'architecture docs'); + console.log(''); + + console.log(chalk.yellow(' Skills:')); + printPlainItems(listItems(path.join(antigravityDir, 'skills')), 'skills'); + console.log(''); +}; + export const listCommand = async (options: CommandOptions): Promise => { printHeader(); @@ -127,6 +151,18 @@ export const listCommand = async (options: CommandOptions): Promise => { return; } + if (options.target === 'antigravity') { + if (options.global) { + listAntigravityScope('global'); + } else if (options.project) { + listAntigravityScope('project'); + } else { + listAntigravityScope('global'); + listAntigravityScope('project'); + } + return; + } + if (options.global) { listScope('global'); } else if (options.project) { diff --git a/src/commands/status.ts b/src/commands/status.ts index 891c0bf..0438618 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -10,6 +10,7 @@ import { getSkillsDir, getClaudeDir, getCodexDir, + getAntigravityDir, getEditorDir, listItems, } from '../utils/symlink.js'; @@ -130,6 +131,28 @@ const showCodexStatus = (scope: Scope = 'global'): void => { console.log(''); }; +const showAntigravityStatus = (scope: Scope = 'global'): void => { + const antigravityDir = getAntigravityDir(scope); + const label = + scope === 'global' ? 'Global (~/.gemini/)' : `Project (${process.cwd()}/.gemini/)`; + + console.log(chalk.cyan(`>>> ${label}`)); + console.log(''); + + if (!fs.existsSync(antigravityDir)) { + console.log(chalk.gray(' Not installed')); + console.log(''); + return; + } + + const architectureItems = listItems(path.join(antigravityDir, 'architecture')); + const skillItems = listItems(path.join(antigravityDir, 'skills')); + + console.log(` ${chalk.green('Architecture docs:')} ${architectureItems.length}`); + console.log(` ${chalk.green('Antigravity skills:')} ${skillItems.length}`); + console.log(''); +}; + const showTargetsStatus = (): void => { const targets = getTargets(); @@ -173,6 +196,18 @@ export const statusCommand = async (options: CommandOptions): Promise => { return; } + if (options.target === 'antigravity') { + if (options.global) { + showAntigravityStatus('global'); + } else if (options.project) { + showAntigravityStatus('project'); + } else { + showAntigravityStatus('global'); + showAntigravityStatus('project'); + } + return; + } + if (options.global) { showStatus('global'); } else if (options.project) { diff --git a/src/commands/uninstall.ts b/src/commands/uninstall.ts index b6bc607..7b73e63 100644 --- a/src/commands/uninstall.ts +++ b/src/commands/uninstall.ts @@ -12,6 +12,7 @@ import { getAgentsDir, getCommandsDir, getSkillsDir, + getAntigravityDir, getEditorDir, getEditorConfig, } from '../utils/symlink.js'; @@ -146,6 +147,63 @@ const uninstallCodexScope = async (scope: Scope): Promise => { console.log(chalk.green(`✓ ${label} Codex uninstall complete!`)); }; +const getAntigravityManagedNames = (): { architecture: string[]; skills: string[] } => { + const architecture: string[] = []; + const skills: string[] = []; + + const archDir = path.join(ASSETS_DIR, 'architecture'); + if (fs.existsSync(archDir)) { + fs.readdirSync(archDir).forEach((name) => architecture.push(name)); + } + + const skillsDir = path.join(ASSETS_DIR, 'skills'); + if (fs.existsSync(skillsDir)) { + fs.readdirSync(skillsDir).forEach((name) => skills.push(name)); + } + + const commandsDir = path.join(ASSETS_DIR, 'commands'); + if (fs.existsSync(commandsDir)) { + fs.readdirSync(commandsDir).forEach((name) => skills.push(name.replace(/\.md$/, ''))); + } + + for (const dirName of ['developers', 'utilities']) { + const agentsDir = path.join(ASSETS_DIR, 'agents', dirName); + if (fs.existsSync(agentsDir)) { + fs.readdirSync(agentsDir).forEach((name) => skills.push(name.replace(/\.md$/, ''))); + } + } + + return { architecture, skills }; +}; + +const uninstallAntigravityScope = async (scope: Scope): Promise => { + const label = scope === 'global' ? 'Global' : 'Project'; + const targetDir = getAntigravityDir(scope); + const spinner = ora(`Uninstalling Antigravity assets from ${label.toLowerCase()} scope...`).start(); + const managed = getAntigravityManagedNames(); + + let removed = 0; + + const archDir = path.join(targetDir, 'architecture'); + for (const name of managed.architecture) { + const result = removeItem(path.join(archDir, name)); + if (result.status === 'removed') { + removed++; + } + } + + const skillsDir = path.join(targetDir, 'skills'); + for (const name of managed.skills) { + const result = removeItem(path.join(skillsDir, name)); + if (result.status === 'removed') { + removed++; + } + } + + spinner.succeed(`Removed ${removed} Antigravity items from ${label.toLowerCase()} scope`); + console.log(chalk.green(`✓ ${label} Antigravity uninstall complete!`)); +}; + const uninstallForOtherEditor = async (target: EditorTarget): Promise => { const config = getEditorConfig(target); const spinner = ora(`Uninstalling from ${config.name}...`).start(); @@ -171,7 +229,7 @@ const uninstallForOtherEditor = async (target: EditorTarget): Promise => { const showTargetMenu = async (): Promise => { const installedTargets = getTargets(); - const availableTargets = installedTargets.length > 0 ? installedTargets : (['claude', 'codex'] as EditorTarget[]); + const availableTargets = installedTargets.length > 0 ? installedTargets : (['claude', 'codex', 'antigravity'] as EditorTarget[]); const { target } = await inquirer.prompt([ { @@ -189,10 +247,10 @@ const showTargetMenu = async (): Promise => { }; const showInteractiveMenu = async ( - target: 'claude' | 'codex' + target: 'claude' | 'codex' | 'antigravity' ): Promise<'global' | 'project' | 'all'> => { - const globalPath = target === 'claude' ? '~/.claude/' : '~/.codex/'; - const projectPath = target === 'claude' ? './.claude/' : './.codex/'; + const globalPath = target === 'claude' ? '~/.claude/' : target === 'codex' ? '~/.codex/' : '~/.gemini/'; + const projectPath = target === 'claude' ? './.claude/' : target === 'codex' ? './.codex/' : './.gemini/'; const { uninstallType } = await inquirer.prompt([ { @@ -230,7 +288,7 @@ export const uninstallCommand = async (options: CommandOptions): Promise = const targets = options.target ? [options.target] : [await showTargetMenu()]; for (const target of targets) { - if (target === 'claude' || target === 'codex') { + if (target === 'claude' || target === 'codex' || target === 'antigravity') { let uninstallType: 'global' | 'project' | 'all'; if (options.global) { @@ -247,24 +305,31 @@ export const uninstallCommand = async (options: CommandOptions): Promise = case 'global': if (target === 'claude') { await uninstallScope('global'); - } else { + } else if (target === 'codex') { await uninstallCodexScope('global'); + } else { + await uninstallAntigravityScope('global'); } break; case 'project': if (target === 'claude') { await uninstallScope('project'); - } else { + } else if (target === 'codex') { await uninstallCodexScope('project'); + } else { + await uninstallAntigravityScope('project'); } break; case 'all': if (target === 'claude') { await uninstallScope('global'); await uninstallScope('project'); - } else { + } else if (target === 'codex') { await uninstallCodexScope('global'); await uninstallCodexScope('project'); + } else { + await uninstallAntigravityScope('global'); + await uninstallAntigravityScope('project'); } break; } diff --git a/src/utils/symlink.ts b/src/utils/symlink.ts index a50de9b..0a2df84 100644 --- a/src/utils/symlink.ts +++ b/src/utils/symlink.ts @@ -58,13 +58,12 @@ export const EDITOR_CONFIGS: Record = { antigravity: { name: 'Antigravity', globalDir: path.join(os.homedir(), '.gemini'), - agentsDir: '.', - commandsDir: '.', - skillsDir: '.', - rulesFile: 'GEMINI.md', + agentsDir: 'skills', + commandsDir: 'skills', + skillsDir: 'skills', supportsAgents: true, - supportsCommands: false, - supportsSkills: false, + supportsCommands: true, + supportsSkills: true, }, }; @@ -92,6 +91,10 @@ export const getEditorDir = (target: EditorTarget, scope: Scope = 'global'): str return path.join(process.cwd(), '.gemini'); }; +export const getAntigravityDir = (scope: Scope = 'global'): string => { + return getEditorDir('antigravity', scope); +}; + export const getEditorAgentsDir = (target: EditorTarget, scope: Scope = 'global'): string => { const baseDir = getEditorDir(target, scope); const config = EDITOR_CONFIGS[target];