fix: align kimi runtime support with review
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 817
|
||||
pr: 743
|
||||
---
|
||||
**Kimi CLI runtime support is now documented and installable** — users can install global GSD Agent Skills with `--kimi --global`, invoke them as `/skill:gsd-*`, and launch the generated custom agent explicitly with `kimi --agent-file`.
|
||||
|
||||
135
bin/install.js
135
bin/install.js
File diff suppressed because one or more lines are too long
@@ -563,7 +563,7 @@ Equivalent paths for other runtimes:
|
||||
- **OpenCode:** `~/.config/opencode/` global or `./.opencode/` local
|
||||
- **Kilo:** `~/.config/kilo/` global or `./.kilo/` local
|
||||
- **Gemini CLI:** `~/.gemini/` global or `./.gemini/` local
|
||||
- **Kimi CLI:** `~/.config/agents/` global; local install is deferred and guarded
|
||||
- **Kimi CLI:** `~/.agents/` global; local install is deferred and guarded
|
||||
- **Codex:** `~/.codex/` global or `./.codex/` local
|
||||
- **Copilot:** `~/.copilot/` global or `./.github/` local
|
||||
- **Antigravity:** auto-detected global root (`~/.gemini/antigravity/`, `~/.gemini/antigravity-ide/`, or `~/.gemini/antigravity-cli/`) or `./.agent/` local
|
||||
@@ -802,7 +802,7 @@ The migration-specific ownership and source snapshots live in
|
||||
| OpenCode | `~/.config/opencode` | `./.opencode` | `command/gsd-*.md` | `agents/gsd-*.md` | `opencode.json` or `opencode.jsonc`; no GSD hooks |
|
||||
| Kilo | `~/.config/kilo` | `./.kilo` | `command/gsd-*.md` | `agents/gsd-*.md` | `kilo.json` or `kilo.jsonc`; no GSD hooks |
|
||||
| Gemini CLI | `~/.gemini` | `./.gemini` | `commands/gsd/*.toml` | `agents/gsd-*.md` | `settings.json` feature flag, hooks, and statusline |
|
||||
| Kimi CLI | `~/.config/agents` | Deferred and guarded | `skills/gsd-*/SKILL.md` invoked as `/skill:gsd-*` | `agents/gsd.yaml`, `agents/gsd.md`, and `agents/subagents/gsd-*` YAML/prompt pairs | Explicit `kimi --agent-file ~/.config/agents/agents/gsd.yaml`; no GSD hooks or statusline |
|
||||
| Kimi CLI | `~/.agents` | Deferred and guarded | `skills/gsd-*/SKILL.md` invoked as `/skill:gsd-*` | `agents/gsd.yaml`, `agents/gsd.md`, and `agents/subagents/gsd-*` YAML/prompt pairs | Explicit `kimi --agent-file ~/.agents/agents/gsd.yaml`; no GSD hooks or statusline |
|
||||
| Codex | `~/.codex` | `./.codex` | `skills/gsd-*/SKILL.md` | `agents/` source markdown plus per-agent TOML | `config.toml` `[agents.gsd-*]`, `[features].hooks` (canonical; legacy alias `codex_hooks` is recognized and migrated forward on reinstall, #3566), and hook tables |
|
||||
| GitHub Copilot | `~/.copilot` | `./.github` | `skills/gsd-*/SKILL.md` and `copilot-instructions.md` | `.agent.md` files | No GSD hooks or statusline |
|
||||
| Antigravity | auto-detected: `~/.gemini/antigravity`, `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `./.agent` | `skills/gsd-*/SKILL.md` | `agents/gsd-*.md` | Gemini-style `settings.json` hook entries when installed by GSD |
|
||||
@@ -818,15 +818,17 @@ The migration-specific ownership and source snapshots live in
|
||||
### Upstream Contract Sources
|
||||
|
||||
Runtime install expectations are checked against primary documentation where
|
||||
available. The current source snapshot is 2026-05-11:
|
||||
available. The current source snapshot is 2026-05-11, with Kimi CLI rechecked
|
||||
on 2026-06-06:
|
||||
|
||||
- Claude Code: Anthropic slash commands, settings, hooks, and subagents docs.
|
||||
- OpenCode and Kilo: OpenCode config docs and Kilo custom subagent docs.
|
||||
- Gemini CLI and Qwen Code: command/config docs; Qwen command docs were last
|
||||
updated 2026-05-06.
|
||||
- Kimi CLI: Agent Skills docs for `~/.config/agents/skills/` discovery and
|
||||
Agents docs for YAML files, `system_prompt_path`, `kimi_cli.tools.*` module
|
||||
paths, and explicit `kimi --agent-file` launch.
|
||||
- Kimi CLI: Agent Skills docs for `~/.kimi-code/skills/` and
|
||||
`~/.agents/skills/` user-level discovery, plus Agents docs for YAML files,
|
||||
`system_prompt_path`, `kimi_cli.tools.*` module paths, and explicit
|
||||
`kimi --agent-file` launch.
|
||||
- Codex: OpenAI Codex docs and `config-schema.json`; the installer also carries
|
||||
Codex 0.124.0 compatibility for agent table shape.
|
||||
- Copilot, Cursor, Cline, Augment, Hermes, and CodeBuddy: vendor docs for
|
||||
|
||||
@@ -110,42 +110,42 @@ Skills land in `~/.codex/skills/gsd-*/SKILL.md`. Agents are written with per-age
|
||||
npx @opengsd/gsd-core@latest --kimi --global
|
||||
```
|
||||
|
||||
Skills land in `~/.config/agents/skills/gsd-*/SKILL.md`. Start a new Kimi CLI session after install, then invoke GSD skills with `/skill:gsd-*`, for example:
|
||||
Skills land in `~/.agents/skills/gsd-*/SKILL.md`. Start a new Kimi CLI session after install, then invoke GSD skills with `/skill:gsd-*`, for example:
|
||||
|
||||
```text
|
||||
/skill:gsd-new-project
|
||||
```
|
||||
|
||||
The installer also writes the GSD custom agent definition to `~/.config/agents/agents/gsd.yaml` with its prompt at `~/.config/agents/agents/gsd.md`; subagents land under `~/.config/agents/agents/subagents/gsd-*.yaml` and `~/.config/agents/agents/subagents/gsd-*.md`.
|
||||
The installer also writes the GSD custom agent definition to `~/.agents/agents/gsd.yaml` with its prompt at `~/.agents/agents/gsd.md`; subagents land under `~/.agents/agents/subagents/gsd-*.yaml` and `~/.agents/agents/subagents/gsd-*.md`.
|
||||
|
||||
Kimi custom agents do not auto-activate just because the files exist. Launch Kimi with the generated agent file when you want the GSD agent surface:
|
||||
|
||||
```bash
|
||||
kimi --agent-file ~/.config/agents/agents/gsd.yaml
|
||||
kimi --agent-file ~/.agents/agents/gsd.yaml
|
||||
```
|
||||
|
||||
GSD uses Kimi's generic Agent Skills root (`~/.config/agents`) as the default so the install follows the shared agents discovery convention. Kimi also discovers user skills from the brand-specific `~/.kimi` directory. If your Kimi setup is already centered on `~/.kimi`, install there explicitly:
|
||||
GSD uses Kimi's generic Agent Skills root (`~/.agents`) as the default so the install follows the shared agents discovery convention. Kimi also discovers user skills from the brand-specific `~/.kimi-code` directory. If your Kimi setup is already centered on `~/.kimi-code`, install there explicitly:
|
||||
|
||||
```bash
|
||||
npx @opengsd/gsd-core@latest --kimi --global --config-dir ~/.kimi
|
||||
npx @opengsd/gsd-core@latest --kimi --global --config-dir ~/.kimi-code
|
||||
```
|
||||
|
||||
Then launch the generated agent from that directory:
|
||||
|
||||
```bash
|
||||
kimi --agent-file ~/.kimi/agents/gsd.yaml
|
||||
kimi --agent-file ~/.kimi-code/agents/gsd.yaml
|
||||
```
|
||||
|
||||
**Override the install directory:**
|
||||
|
||||
```bash
|
||||
KIMI_CONFIG_DIR=~/.config/agents-alt npx @opengsd/gsd-core@latest --kimi --global
|
||||
KIMI_CONFIG_DIR=~/.agents-alt npx @opengsd/gsd-core@latest --kimi --global
|
||||
```
|
||||
|
||||
For brand-specific scripted installs, use:
|
||||
|
||||
```bash
|
||||
KIMI_CONFIG_DIR=~/.kimi npx @opengsd/gsd-core@latest --kimi --global
|
||||
KIMI_CONFIG_DIR=~/.kimi-code npx @opengsd/gsd-core@latest --kimi --global
|
||||
```
|
||||
|
||||
`--kimi --local` is intentionally deferred and guarded in v1; use the global install path above for Kimi CLI.
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
* cline — Rules-based; commands are embedded in .clinerules. Cline does
|
||||
* not use a skills/ directory. getGlobalSkillDir() returns null
|
||||
* for cline so the caller can emit an appropriate warning.
|
||||
* kimi — Agent Skills are discovered from the generic agents root:
|
||||
* ~/.config/agents/skills. ~/.kimi/skills is compatible with
|
||||
* Kimi CLI, but is not GSD's canonical Phase 1 install target.
|
||||
* kimi — Agent Skills are discovered from Kimi's generic user root:
|
||||
* ~/.agents/skills. ~/.kimi-code/skills is compatible with
|
||||
* Kimi Code CLI and can be selected with KIMI_CONFIG_DIR.
|
||||
*/
|
||||
|
||||
import os from 'node:os';
|
||||
@@ -128,11 +128,10 @@ export function getGlobalConfigDir(runtime: string): string {
|
||||
case 'cline':
|
||||
return env['CLINE_CONFIG_DIR'] ? expandTilde(env['CLINE_CONFIG_DIR']) : path.join(home, '.cline');
|
||||
|
||||
// ── Kimi CLI (generic agents XDG root) ─────────────────────────────────
|
||||
// ── Kimi CLI (generic agents user root) ────────────────────────────────
|
||||
case 'kimi': {
|
||||
if (env['KIMI_CONFIG_DIR']) return expandTilde(env['KIMI_CONFIG_DIR']);
|
||||
if (env['XDG_CONFIG_HOME']) return path.join(expandTilde(env['XDG_CONFIG_HOME']), 'agents');
|
||||
return path.join(home, '.config', 'agents');
|
||||
return path.join(home, '.agents');
|
||||
}
|
||||
|
||||
// ── OpenCode (XDG) ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -47,47 +47,47 @@ function withEnv(updates, fn) {
|
||||
}
|
||||
|
||||
describe('Kimi runtime homes', () => {
|
||||
test('canonical global skills base is ~/.config/agents/skills, not ~/.kimi/skills', () => {
|
||||
test('canonical global skills base is ~/.agents/skills, not ~/.kimi-code/skills', () => {
|
||||
withEnv({ KIMI_CONFIG_DIR: undefined, XDG_CONFIG_HOME: undefined }, () => {
|
||||
assert.strictEqual(
|
||||
getGlobalConfigDir('kimi'),
|
||||
path.join(os.homedir(), '.config', 'agents'),
|
||||
path.join(os.homedir(), '.agents'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
getGlobalSkillsBase('kimi'),
|
||||
path.join(os.homedir(), '.config', 'agents', 'skills'),
|
||||
path.join(os.homedir(), '.agents', 'skills'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
getGlobalSkillDir('kimi', 'gsd-help'),
|
||||
path.join(os.homedir(), '.config', 'agents', 'skills', 'gsd-help'),
|
||||
path.join(os.homedir(), '.agents', 'skills', 'gsd-help'),
|
||||
);
|
||||
assert.notStrictEqual(
|
||||
getGlobalSkillsBase('kimi'),
|
||||
path.join(os.homedir(), '.kimi', 'skills'),
|
||||
path.join(os.homedir(), '.kimi-code', 'skills'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('KIMI_CONFIG_DIR overrides the Kimi generic agents config root', () => {
|
||||
withEnv({ KIMI_CONFIG_DIR: '/tmp/custom-kimi-agents', XDG_CONFIG_HOME: undefined }, () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kimi'), '/tmp/custom-kimi-agents');
|
||||
test('KIMI_CONFIG_DIR can select the brand-specific ~/.kimi-code root', () => {
|
||||
withEnv({ KIMI_CONFIG_DIR: '/tmp/custom-kimi-code', XDG_CONFIG_HOME: undefined }, () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kimi'), '/tmp/custom-kimi-code');
|
||||
assert.strictEqual(
|
||||
getGlobalSkillsBase('kimi'),
|
||||
path.join('/tmp/custom-kimi-agents', 'skills'),
|
||||
path.join('/tmp/custom-kimi-code', 'skills'),
|
||||
);
|
||||
assert.strictEqual(getGlobalDir('kimi'), '/tmp/custom-kimi-agents');
|
||||
assert.strictEqual(getGlobalDir('kimi'), '/tmp/custom-kimi-code');
|
||||
});
|
||||
});
|
||||
|
||||
test('XDG_CONFIG_HOME participates in the default Kimi generic agents path', () => {
|
||||
test('XDG_CONFIG_HOME does not change Kimi default root', () => {
|
||||
withEnv({ KIMI_CONFIG_DIR: undefined, XDG_CONFIG_HOME: '/tmp/xdg-home' }, () => {
|
||||
assert.strictEqual(
|
||||
getGlobalConfigDir('kimi'),
|
||||
path.join('/tmp/xdg-home', 'agents'),
|
||||
path.join(os.homedir(), '.agents'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
getConfigDirFromHome('kimi', true),
|
||||
"'.config', 'agents'",
|
||||
"'.agents'",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -138,7 +138,8 @@ describe('Kimi local install guard', () => {
|
||||
assert.match(combined, /Kimi local install/i);
|
||||
assert.match(combined, /deferred/i);
|
||||
|
||||
assert.ok(!fs.existsSync(path.join(tmpProject, '.kimi')), 'must not create .kimi/');
|
||||
assert.ok(!fs.existsSync(path.join(tmpProject, '.kimi')), 'must not create legacy .kimi/');
|
||||
assert.ok(!fs.existsSync(path.join(tmpProject, '.kimi-code')), 'must not create .kimi-code/');
|
||||
assert.ok(!fs.existsSync(path.join(tmpProject, '.agents')), 'must not create .agents/');
|
||||
assert.ok(!fs.existsSync(path.join(tmpProject, '.claude')), 'must not fall back to Claude local install');
|
||||
} finally {
|
||||
@@ -169,15 +170,19 @@ describe('Kimi local install guard', () => {
|
||||
);
|
||||
const combined = `${result.stdout}\n${result.stderr}`;
|
||||
assert.match(combined, /Installing for .*Kimi/i);
|
||||
assert.match(combined, /Installed \d+ skills to skills\//i);
|
||||
assert.match(combined, /Installed \d+ Kimi skills to skills\//i);
|
||||
assert.match(combined, /Generated Kimi root agent: .*agents.*gsd\.yaml/i);
|
||||
assert.match(combined, /kimi --agent-file/i);
|
||||
assert.match(combined, /Wrote file manifest/i);
|
||||
|
||||
const skillFile = path.join(tmpConfig, 'skills', 'gsd-new-project', 'SKILL.md');
|
||||
assert.ok(fs.existsSync(skillFile), 'must write gsd-new-project/SKILL.md');
|
||||
const skillContent = fs.readFileSync(skillFile, 'utf8');
|
||||
assert.match(skillContent, /^name: gsd-new-project$/m);
|
||||
assert.match(skillContent, /\/skill:gsd-new-project/);
|
||||
assert.match(skillContent, /gsd-core\/workflows\/new-project\.md/);
|
||||
assert.doesNotMatch(skillContent, /@~\/\.claude\/gsd-core|@\$HOME\/\.claude\/gsd-core/);
|
||||
assert.doesNotMatch(skillContent, /@[^\r\n]*\\/, 'serialized Kimi payload references must use forward slashes');
|
||||
assert.doesNotMatch(skillContent, /kimi_cli\.tools|system_prompt_path|^version: 1$/m);
|
||||
|
||||
const rootYaml = path.join(tmpConfig, 'agents', 'gsd.yaml');
|
||||
@@ -204,8 +209,132 @@ describe('Kimi local install guard', () => {
|
||||
assert.match(executorYamlContent, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(executorYamlContent, /mcp__/);
|
||||
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'gsd-core')), 'must not write workflow payloads as Kimi artifacts');
|
||||
assert.ok(fs.existsSync(path.join(tmpConfig, 'gsd-core', 'workflows', 'new-project.md')), 'must write workflow payloads used by Kimi skills');
|
||||
const manifestPath = path.join(tmpConfig, 'gsd-file-manifest.json');
|
||||
assert.ok(fs.existsSync(manifestPath), 'must write gsd-file-manifest.json for Kimi installs');
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
||||
assert.ok(manifest.files['skills/gsd-new-project/SKILL.md'], 'manifest tracks generated Kimi skill');
|
||||
assert.ok(manifest.files['agents/gsd.yaml'], 'manifest tracks Kimi root agent YAML');
|
||||
assert.ok(manifest.files['agents/gsd.md'], 'manifest tracks Kimi root agent prompt');
|
||||
assert.ok(manifest.files['agents/subagents/gsd-executor.yaml'], 'manifest tracks Kimi subagent YAML');
|
||||
assert.ok(manifest.files['agents/subagents/gsd-executor.md'], 'manifest tracks Kimi subagent prompt');
|
||||
assert.ok(manifest.files['gsd-core/workflows/new-project.md'], 'manifest tracks installed workflow payload');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'hooks')), 'must not write hooks under the Kimi root');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'settings.json')), 'must not write settings.json under the Kimi root');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, '.clinerules')), 'must not write rules under the Kimi root');
|
||||
} finally {
|
||||
cleanup(tmpProject);
|
||||
cleanup(tmpConfig);
|
||||
cleanup(tmpHome);
|
||||
}
|
||||
});
|
||||
|
||||
test('--kimi --global backs up local edits to generated skills and agent artifacts on reinstall', () => {
|
||||
const tmpProject = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-reinstall-project-'));
|
||||
const tmpConfig = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-reinstall-config-'));
|
||||
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-reinstall-home-'));
|
||||
const env = installerEnv({ HOME: tmpHome, USERPROFILE: tmpHome });
|
||||
|
||||
try {
|
||||
const installArgs = [INSTALL_SCRIPT, '--kimi', '--global', '--config-dir', tmpConfig, '--no-sdk'];
|
||||
const first = spawnSync(process.execPath, installArgs, {
|
||||
cwd: tmpProject,
|
||||
encoding: 'utf8',
|
||||
env,
|
||||
});
|
||||
assert.strictEqual(
|
||||
first.status,
|
||||
0,
|
||||
`first install failed\nstdout: ${first.stdout}\nstderr: ${first.stderr}`,
|
||||
);
|
||||
|
||||
const skillFile = path.join(tmpConfig, 'skills', 'gsd-new-project', 'SKILL.md');
|
||||
const agentPrompt = path.join(tmpConfig, 'agents', 'subagents', 'gsd-executor.md');
|
||||
fs.appendFileSync(skillFile, '\nUSER LOCAL KIMI SKILL EDIT\n');
|
||||
fs.appendFileSync(agentPrompt, '\nUSER LOCAL KIMI AGENT EDIT\n');
|
||||
|
||||
const second = spawnSync(process.execPath, installArgs, {
|
||||
cwd: tmpProject,
|
||||
encoding: 'utf8',
|
||||
env,
|
||||
});
|
||||
assert.strictEqual(
|
||||
second.status,
|
||||
0,
|
||||
`second install failed\nstdout: ${second.stdout}\nstderr: ${second.stderr}`,
|
||||
);
|
||||
assert.match(`${second.stdout}\n${second.stderr}`, /locally modified GSD file/i);
|
||||
|
||||
const skillBackup = path.join(tmpConfig, 'gsd-local-patches', 'skills', 'gsd-new-project', 'SKILL.md');
|
||||
const agentBackup = path.join(tmpConfig, 'gsd-local-patches', 'agents', 'subagents', 'gsd-executor.md');
|
||||
assert.match(fs.readFileSync(skillBackup, 'utf8'), /USER LOCAL KIMI SKILL EDIT/);
|
||||
assert.match(fs.readFileSync(agentBackup, 'utf8'), /USER LOCAL KIMI AGENT EDIT/);
|
||||
|
||||
const meta = JSON.parse(fs.readFileSync(path.join(tmpConfig, 'gsd-local-patches', 'backup-meta.json'), 'utf8'));
|
||||
assert.ok(meta.files.includes('skills/gsd-new-project/SKILL.md'));
|
||||
assert.ok(meta.files.includes('agents/subagents/gsd-executor.md'));
|
||||
} finally {
|
||||
cleanup(tmpProject);
|
||||
cleanup(tmpConfig);
|
||||
cleanup(tmpHome);
|
||||
}
|
||||
});
|
||||
|
||||
test('--kimi --global --uninstall removes GSD artifacts and preserves non-GSD Kimi content', () => {
|
||||
const tmpProject = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-uninstall-project-'));
|
||||
const tmpConfig = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-uninstall-config-'));
|
||||
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-uninstall-home-'));
|
||||
const env = installerEnv({ HOME: tmpHome, USERPROFILE: tmpHome });
|
||||
|
||||
try {
|
||||
const installArgs = [INSTALL_SCRIPT, '--kimi', '--global', '--config-dir', tmpConfig, '--no-sdk'];
|
||||
const installResult = spawnSync(process.execPath, installArgs, {
|
||||
cwd: tmpProject,
|
||||
encoding: 'utf8',
|
||||
env,
|
||||
});
|
||||
assert.strictEqual(
|
||||
installResult.status,
|
||||
0,
|
||||
`install failed\nstdout: ${installResult.stdout}\nstderr: ${installResult.stderr}`,
|
||||
);
|
||||
|
||||
const foreignSkill = path.join(tmpConfig, 'skills', 'user-custom-skill', 'SKILL.md');
|
||||
const foreignRootAgent = path.join(tmpConfig, 'agents', 'user-agent.yaml');
|
||||
const foreignSubagent = path.join(tmpConfig, 'agents', 'subagents', 'user-agent.yaml');
|
||||
fs.mkdirSync(path.dirname(foreignSkill), { recursive: true });
|
||||
fs.mkdirSync(path.dirname(foreignSubagent), { recursive: true });
|
||||
fs.writeFileSync(foreignSkill, '# user skill\n', 'utf8');
|
||||
fs.writeFileSync(foreignRootAgent, 'version: 1\n', 'utf8');
|
||||
fs.writeFileSync(foreignSubagent, 'version: 1\n', 'utf8');
|
||||
|
||||
const uninstallResult = spawnSync(
|
||||
process.execPath,
|
||||
[INSTALL_SCRIPT, '--kimi', '--global', '--config-dir', tmpConfig, '--uninstall'],
|
||||
{
|
||||
cwd: tmpProject,
|
||||
encoding: 'utf8',
|
||||
env,
|
||||
},
|
||||
);
|
||||
assert.strictEqual(
|
||||
uninstallResult.status,
|
||||
0,
|
||||
`uninstall failed\nstdout: ${uninstallResult.stdout}\nstderr: ${uninstallResult.stderr}`,
|
||||
);
|
||||
assert.match(`${uninstallResult.stdout}\n${uninstallResult.stderr}`, /Kimi CLI/);
|
||||
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'skills', 'gsd-new-project')), 'must remove generated Kimi skills');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'agents', 'gsd.yaml')), 'must remove Kimi root agent YAML');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'agents', 'gsd.md')), 'must remove Kimi root agent prompt');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'agents', 'subagents', 'gsd-executor.yaml')), 'must remove generated Kimi subagent YAML');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'agents', 'subagents', 'gsd-executor.md')), 'must remove generated Kimi subagent prompt');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'gsd-core')), 'must remove installed workflow payload');
|
||||
assert.ok(!fs.existsSync(path.join(tmpConfig, 'gsd-file-manifest.json')), 'must remove the manifest');
|
||||
|
||||
assert.ok(fs.existsSync(foreignSkill), 'must preserve non-GSD Kimi skills');
|
||||
assert.ok(fs.existsSync(foreignRootAgent), 'must preserve non-GSD root agents');
|
||||
assert.ok(fs.existsSync(foreignSubagent), 'must preserve non-GSD subagents');
|
||||
} finally {
|
||||
cleanup(tmpProject);
|
||||
cleanup(tmpConfig);
|
||||
|
||||
@@ -48,7 +48,7 @@ const RUNTIME_META = {
|
||||
cursor: { localDir: '.cursor', globalSuffix: '.cursor' },
|
||||
gemini: { localDir: '.gemini', globalSuffix: '.gemini' },
|
||||
hermes: { localDir: '.hermes', globalSuffix: '.hermes' },
|
||||
kimi: { localDir: '.kimi', globalSuffix: path.join('.config', 'agents') },
|
||||
kimi: { localDir: '.kimi-code', globalSuffix: '.agents' },
|
||||
kilo: { localDir: '.kilo', globalSuffix: path.join('.config', 'kilo') },
|
||||
opencode: { localDir: '.opencode', globalSuffix: path.join('.config', 'opencode') },
|
||||
qwen: { localDir: '.qwen', globalSuffix: '.qwen' },
|
||||
|
||||
@@ -34,7 +34,7 @@ const RUNTIME_INSTALL_CONTRACTS = {
|
||||
cursor: { surface: 'flat-skills', settings: false, packageJson: false },
|
||||
gemini: { surface: 'commands-gsd', settings: true, packageJson: true },
|
||||
hermes: { surface: 'hermes-skills', settings: true, packageJson: true },
|
||||
kimi: { surface: 'kimi-skills-agents', settings: false, packageJson: false, workflowPayload: false },
|
||||
kimi: { surface: 'kimi-skills-agents', settings: false, packageJson: false },
|
||||
kilo: { surface: 'flat-command', settings: false, packageJson: true },
|
||||
opencode: { surface: 'flat-command', settings: true, packageJson: true },
|
||||
qwen: { surface: 'flat-skills', settings: true, packageJson: true },
|
||||
|
||||
@@ -32,6 +32,9 @@ describe('convertKimiToolName', () => {
|
||||
['TodoWrite', 'kimi_cli.tools.todo:SetTodoList'],
|
||||
['WebSearch', 'kimi_cli.tools.web:SearchWeb'],
|
||||
['WebFetch', 'kimi_cli.tools.web:FetchURL'],
|
||||
['TaskList', 'kimi_cli.tools.background:TaskList'],
|
||||
['TaskOutput', 'kimi_cli.tools.background:TaskOutput'],
|
||||
['TaskStop', 'kimi_cli.tools.background:TaskStop'],
|
||||
]);
|
||||
|
||||
for (const [claudeTool, kimiTool] of expectedMappings) {
|
||||
|
||||
@@ -187,6 +187,8 @@ describe('install.js exports multi-select runtime metadata', () => {
|
||||
'prompt lists Hermes Agent as option 10');
|
||||
assert.ok(/\b11\)\s*Kimi\b/.test(prompt),
|
||||
'prompt lists Kimi as option 11');
|
||||
assert.ok(/Kimi\s+\(~\/\.agents\)/.test(prompt),
|
||||
'prompt shows the canonical Kimi global root');
|
||||
assert.ok(/\b14\)\s*Qwen Code\b/.test(prompt),
|
||||
'prompt lists Qwen Code as option 14');
|
||||
assert.ok(/\b15\)\s*Trae\b/.test(prompt),
|
||||
|
||||
Reference in New Issue
Block a user