diff --git a/.gitignore b/.gitignore index ee813182ca..5abca0800d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ bin/gstack-global-discover* .cursor/ .openclaw/ .hermes/ +.kimi-code/ .gbrain/ .gbrain-source .context/ diff --git a/README.md b/README.md index 7b2b9305ea..fe3fdd5069 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ These are conversational skills. Your OpenClaw agent runs them directly via chat ### Other AI Agents -gstack works on 10 AI coding agents, not just Claude. Setup auto-detects which +gstack works on 11 AI coding agents, not just Claude. Setup auto-detects which agents you have installed: ```bash @@ -121,6 +121,7 @@ Or target a specific agent with `./setup --host `: | Kiro | `--host kiro` | `~/.kiro/skills/gstack-*/` | | Hermes | `--host hermes` | `~/.hermes/skills/gstack-*/` | | GBrain (mod) | `--host gbrain` | `~/.gbrain/skills/gstack-*/` | +| Kimi Code CLI | `--host kimi` | `~/.kimi-code/skills/gstack-*/` | For Codex, setup reads the top-level `model` from `${CODEX_HOME:-~/.codex}/config.toml` and generates the matching behavioral diff --git a/bin/gstack-team-init b/bin/gstack-team-init index 99538425f2..be0d1d3fbe 100755 --- a/bin/gstack-team-init +++ b/bin/gstack-team-init @@ -71,7 +71,7 @@ else ```bash _GS="" -for _D in "${GSTACK_ROOT:-}" "$HOME/.claude/skills/gstack" "$HOME/.codex/skills/gstack" "$HOME/.factory/skills/gstack" "$HOME/.kiro/skills/gstack" "$HOME/.config/opencode/skills/gstack" "$HOME/.slate/skills/gstack" "$HOME/.cursor/skills/gstack" "$HOME/.openclaw/skills/gstack" "$HOME/.hermes/skills/gstack" "$HOME/.gbrain/skills/gstack" "$HOME/.gstack/repos/gstack"; do +for _D in "${GSTACK_ROOT:-}" "$HOME/.claude/skills/gstack" "$HOME/.codex/skills/gstack" "$HOME/.factory/skills/gstack" "$HOME/.kiro/skills/gstack" "$HOME/.config/opencode/skills/gstack" "$HOME/.slate/skills/gstack" "$HOME/.cursor/skills/gstack" "$HOME/.openclaw/skills/gstack" "$HOME/.hermes/skills/gstack" "$HOME/.gbrain/skills/gstack" "$HOME/.kimi-code/skills/gstack" "$HOME/.gstack/repos/gstack"; do [ -z "$_GS" ] && [ -n "$_D" ] && [ -d "$_D/bin" ] && _GS="$_D" done [ -n "$_GS" ] && echo "GSTACK_OK: $_GS" || echo "GSTACK_MISSING" @@ -125,7 +125,7 @@ if [ "$MODE" = "required" ]; then # repo location. Block only when NONE exist (#2500 — hardcoding # ~/.claude/skills/gstack false-blocked Codex-host and migrated-repo installs). _GSTACK_ROOT="" -for _D in "${GSTACK_ROOT:-}" "$HOME/.claude/skills/gstack" "$HOME/.codex/skills/gstack" "$HOME/.factory/skills/gstack" "$HOME/.kiro/skills/gstack" "$HOME/.config/opencode/skills/gstack" "$HOME/.slate/skills/gstack" "$HOME/.cursor/skills/gstack" "$HOME/.openclaw/skills/gstack" "$HOME/.hermes/skills/gstack" "$HOME/.gbrain/skills/gstack" "$HOME/.gstack/repos/gstack"; do +for _D in "${GSTACK_ROOT:-}" "$HOME/.claude/skills/gstack" "$HOME/.codex/skills/gstack" "$HOME/.factory/skills/gstack" "$HOME/.kiro/skills/gstack" "$HOME/.config/opencode/skills/gstack" "$HOME/.slate/skills/gstack" "$HOME/.cursor/skills/gstack" "$HOME/.openclaw/skills/gstack" "$HOME/.hermes/skills/gstack" "$HOME/.gbrain/skills/gstack" "$HOME/.kimi-code/skills/gstack" "$HOME/.gstack/repos/gstack"; do [ -z "$_GSTACK_ROOT" ] && [ -n "$_D" ] && [ -d "$_D/bin" ] && _GSTACK_ROOT="$_D" done diff --git a/docs/ADDING_A_HOST.md b/docs/ADDING_A_HOST.md index d699816df9..06daa76be7 100644 --- a/docs/ADDING_A_HOST.md +++ b/docs/ADDING_A_HOST.md @@ -2,7 +2,7 @@ gstack uses a declarative host config system. Each supported AI coding agent (Claude, Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw, Hermes, -GBrain) is defined as a typed TypeScript config object built by the +GBrain, Kimi Code CLI) is defined as a typed TypeScript config object built by the `defineHost()` factory. Adding a new host means creating one file and re-exporting it. Zero code changes to the generator, setup, or tooling. @@ -21,6 +21,7 @@ hosts/ ├── openclaw.ts # OpenClaw ├── hermes.ts # Hermes (Nous Research) ├── gbrain.ts # GBrain +├── kimi.ts # Kimi Code CLI └── index.ts # Registry: imports all, derives Host type ``` diff --git a/hosts/index.ts b/hosts/index.ts index cc1c213b53..a624b5152f 100644 --- a/hosts/index.ts +++ b/hosts/index.ts @@ -16,9 +16,10 @@ import cursor from './cursor'; import openclaw from './openclaw'; import hermes from './hermes'; import gbrain from './gbrain'; +import kimi from './kimi'; /** All registered host configs. Add new hosts here. */ -export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain]; +export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain, kimi]; /** Map from host name to config. */ export const HOST_CONFIG_MAP: Record = Object.fromEntries( @@ -65,4 +66,4 @@ export function getExternalHosts(): HostConfig[] { } // Re-export individual configs for direct import -export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain }; +export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw, hermes, gbrain, kimi }; diff --git a/hosts/kimi.ts b/hosts/kimi.ts new file mode 100644 index 0000000000..23852c849f --- /dev/null +++ b/hosts/kimi.ts @@ -0,0 +1,22 @@ +import { defineHost } from './define-host'; + +const kimi = defineHost({ + name: 'kimi', + displayName: 'Kimi Code CLI', + + // Kimi Code scans skills at two project tiers: .kimi-code/skills/ (Kimi-specific) + // and .agents/skills/ (generic). We use the Kimi-specific root so generated + // output never collides with the codex host's .agents/skills/ render. + // User level mirrors the same layout under $KIMI_CODE_HOME (~/.kimi-code). + globalRoot: '.kimi-code/skills/gstack', + localSkillRoot: '.kimi-code/skills/gstack', + hostSubdir: '.kimi-code', + + extraPathRewrites: [ + // Kimi Code reads AGENTS.md, not CLAUDE.md (same as hermes). + { from: 'CLAUDE.md', to: 'AGENTS.md' }, + ], + // No toolRewrites: Kimi's tools share Claude Code names (Bash/Read/Write/Edit/Grep/Glob/Agent). +}); + +export default kimi; diff --git a/setup b/setup index 8c5d6c0772..c97bc32332 100755 --- a/setup +++ b/setup @@ -11,7 +11,7 @@ Usage: ./setup [options] Options: --host Install for a specific host (claude, codex, kiro, factory, - opencode, openclaw, hermes, gbrain, auto). Default: claude. + opencode, openclaw, hermes, gbrain, kimi, auto). Default: claude. --model Codex model profile override. Otherwise reads Codex config. --prefix Install skills with the gstack- prefix (e.g. /gstack-review). --no-prefix Install skills with short names (e.g. /review). Default. @@ -177,7 +177,7 @@ MODEL_OVERRIDE="" MODEL_OVERRIDE_SET=0 while [ $# -gt 0 ]; do case "$1" in - --host) [ -z "$2" ] && echo "Missing value for --host (expected claude, codex, kiro, factory, opencode, cursor, slate, openclaw, hermes, gbrain, or auto)" >&2 && exit 1; HOST="$2"; shift 2 ;; + --host) [ -z "$2" ] && echo "Missing value for --host (expected claude, codex, kiro, factory, opencode, cursor, slate, openclaw, hermes, gbrain, kimi, or auto)" >&2 && exit 1; HOST="$2"; shift 2 ;; --host=*) HOST="${1#--host=}"; shift ;; --model) [ -z "$2" ] && echo "Missing value for --model" >&2 && exit 1; MODEL_OVERRIDE="$2"; MODEL_OVERRIDE_SET=1; shift 2 ;; --model=*) MODEL_OVERRIDE="${1#--model=}"; MODEL_OVERRIDE_SET=1; shift ;; @@ -230,7 +230,19 @@ case "$HOST" in echo "GBrain setup and brain skills ship from the GBrain repo." echo "" exit 0 ;; - *) echo "Unknown --host value: $HOST (expected claude, codex, kiro, factory, opencode, cursor, slate, openclaw, hermes, gbrain, or auto)" >&2; exit 1 ;; + kimi) + echo "" + echo "Kimi Code CLI reads gstack skills natively — no wrapper or runtime" + echo "adapter needed. Generation writes Kimi-format skills to" + echo ".kimi-code/skills/gstack-*/, which Kimi Code auto-discovers at project" + echo "level (user level: ~/.kimi-code/skills/)." + echo "" + echo "To integrate gstack with Kimi Code CLI:" + echo " 1. Generate artifacts: bun run gen:skill-docs --host kimi" + echo " 2. Kimi Code picks up .kimi-code/skills/gstack-*/ automatically in this repo" + echo "" + exit 0 ;; + *) echo "Unknown --host value: $HOST (expected claude, codex, kiro, factory, opencode, cursor, slate, openclaw, hermes, gbrain, kimi, or auto)" >&2; exit 1 ;; esac # ─── Resolve skill prefix preference ───────────────────────── diff --git a/test/host-config.test.ts b/test/host-config.test.ts index 0a167f409e..21b6c082a1 100644 --- a/test/host-config.test.ts +++ b/test/host-config.test.ts @@ -32,8 +32,8 @@ const RESOLVER_NAMES = new Set(Object.keys(RESOLVERS)); // ─── hosts/index.ts ───────────────────────────────────────── describe('hosts/index.ts', () => { - test('ALL_HOST_CONFIGS has 10 hosts', () => { - expect(ALL_HOST_CONFIGS.length).toBe(10); + test('ALL_HOST_CONFIGS has 11 hosts', () => { + expect(ALL_HOST_CONFIGS.length).toBe(11); }); test('ALL_HOST_NAMES matches config names', () => {