fix: close Kimi runtime review gaps
This commit is contained in:
@@ -9077,6 +9077,8 @@ function reportLocalPatches(configDir, runtime = 'claude') {
|
||||
? '$gsd-update --reapply'
|
||||
: runtime === 'cursor'
|
||||
? 'gsd-update --reapply (mention the skill name)'
|
||||
: runtime === 'kimi'
|
||||
? '/skill:gsd-update --reapply'
|
||||
: '/gsd-update --reapply';
|
||||
console.log('');
|
||||
console.log(' ' + yellow + 'Local patches detected' + reset + ' (from v' + meta.from_version + '):');
|
||||
|
||||
@@ -368,7 +368,7 @@ for the new shape before changing migration behavior.
|
||||
| OpenCode | Flat markdown commands in `command/gsd-*.md`; agents in `agents/gsd-*.md`; config updates in `opencode.json` or `opencode.jsonc` | Global `OPENCODE_CONFIG_DIR`, `dirname(OPENCODE_CONFIG)`, `XDG_CONFIG_HOME/opencode`, or `~/.config/opencode`; local `./.opencode` | GSD owns generated command/agent files and GSD entries in structured config only | [Config](https://opencode.ai/docs/config/); docs published 2026-05, checked 2026-05-11 |
|
||||
| Kilo | OpenCode-style flat markdown commands in `command/gsd-*.md`; agents in `agents/gsd-*.md`; config updates in `kilo.json` or `kilo.jsonc` | Global `KILO_CONFIG_DIR`, `dirname(KILO_CONFIG)`, `XDG_CONFIG_HOME/kilo`, or `~/.config/kilo`; local `./.kilo` | GSD owns generated command/agent files and GSD entries in structured config only | [Custom subagents](https://docs.kilo.ai/docs/customize/custom-subagents); docs not versioned, checked 2026-05-11 |
|
||||
| Gemini CLI | TOML slash commands in `commands/gsd/*.toml`; agents in `agents/gsd-*.md`; `settings.json` feature flag, hooks, and statusline | Global `GEMINI_CONFIG_DIR` or `~/.gemini`; local `./.gemini` | GSD owns generated commands/agents/hooks and only GSD settings entries; local command copy may be skipped when global GSD commands already exist | [Custom commands](https://google-gemini.github.io/gemini-cli/docs/cli/custom-commands.html), [configuration](https://google-gemini.github.io/gemini-cli/docs/cli/configuration.html); docs checked 2026-05-11 |
|
||||
| Kimi CLI | Agent Skills in `skills/gsd-*/SKILL.md`; explicit custom agent YAML/prompt artifacts in `agents/gsd.yaml`, `agents/gsd.md`, and `agents/subagents/gsd-*`; `gsd-core/` payload files referenced by generated skills; manifest, pristine, local-patch, and migration journal files from the normal installer safety pipeline | Global `KIMI_CONFIG_DIR`, explicit `--config-dir`, or first-existing generic skills root: `~/.config/agents` when `~/.config/agents/skills` exists or no generic skills root exists yet, otherwise `~/.agents` when `~/.agents/skills` exists and `~/.config/agents/skills` does not; local `--kimi --local` is guarded and writes no project-level artifacts | GSD owns only generated `skills/gsd-*`, `agents/gsd.*`, `agents/subagents/gsd-*`, installed `gsd-core/` payload files, and manifest/preservation/migration records. GSD does not own Kimi config files, hooks, settings, rules, statusline, update-banner registration, or non-GSD Kimi skills/agents. Reinstall/update must preserve locally modified generated Kimi artifacts through manifest-backed `gsd-local-patches/`; uninstall removes only GSD-owned Kimi artifacts and preserves non-GSD user content. | [Agent Skills](https://moonshotai.github.io/kimi-cli/en/customization/skills.html), [Agents and Subagents](https://moonshotai.github.io/kimi-cli/en/customization/agents.html), [Tools](https://moonshotai.github.io/kimi-code/en/reference/tools.html); docs checked 2026-06-07 |
|
||||
| Kimi CLI | Agent Skills in `skills/gsd-*/SKILL.md`; explicit custom agent YAML/prompt artifacts in `agents/gsd.yaml`, `agents/gsd.md`, and `agents/subagents/gsd-*`; `gsd-core/` payload files referenced by generated skills; manifest, pristine, local-patch, and migration journal files from the normal installer safety pipeline | Global `KIMI_CONFIG_DIR`, explicit `--config-dir`, or first-existing generic skills root: `~/.config/agents` when `~/.config/agents/skills` exists or no generic skills root exists yet, otherwise `~/.agents` when `~/.agents/skills` exists and `~/.config/agents/skills` does not; `KIMI_CONFIG_DIR` and `--config-dir` are GSD write-location overrides and arbitrary roots require Kimi-side `--skills-dir` or `extra_skill_dirs` configuration for skill discovery; local `--kimi --local` is guarded and writes no project-level artifacts | GSD owns only generated `skills/gsd-*`, `agents/gsd.*`, `agents/subagents/gsd-*`, installed `gsd-core/` payload files, and manifest/preservation/migration records. GSD does not own Kimi config files, hooks, settings, rules, statusline, update-banner registration, or non-GSD Kimi skills/agents. Reinstall/update must preserve locally modified generated Kimi artifacts through manifest-backed `gsd-local-patches/`; uninstall removes only GSD-owned Kimi artifacts and preserves non-GSD user content. | [Agent Skills](https://moonshotai.github.io/kimi-cli/en/customization/skills.html), [Agents and Subagents](https://moonshotai.github.io/kimi-cli/en/customization/agents.html), [Tools](https://moonshotai.github.io/kimi-code/en/reference/tools.html); docs checked 2026-06-07 |
|
||||
| Codex | Skills in `skills/gsd-*/SKILL.md`; agents as source markdown plus per-agent TOML in `agents/`; `[agents.gsd-*]` and hooks in `config.toml` | Global `CODEX_HOME` or `~/.codex`; local `./.codex` | GSD owns generated skills, generated agent TOML, `agents.gsd-*` config sections, `[features].hooks` when added by GSD (canonical; legacy alias `codex_hooks` is recognized and migrated forward, #3566), and GSD hook entries | [Codex config schema](https://developers.openai.com/codex/config-schema.json), [Codex developer docs](https://developers.openai.com/codex/); docs not versioned, checked 2026-05-15; installer compatibility sentinel: Codex 0.130.0 features.hooks key (legacy `codex_hooks` recognized) |
|
||||
| GitHub Copilot | Skills in `skills/gsd-*/SKILL.md`; agents as `.agent.md`; repository instructions in `copilot-instructions.md` | Global `COPILOT_CONFIG_DIR`, `COPILOT_HOME`, or `~/.copilot`; local `./.github` | GSD owns generated skill/agent files and GSD-authored instruction files; no hook/statusline ownership | [Repository custom instructions](https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions), [Copilot CLI custom instructions](https://docs.github.com/en/copilot/how-tos/copilot-cli/add-custom-instructions); GitHub Docs product docs, checked 2026-05-11 |
|
||||
| Antigravity | Skills in `skills/gsd-*/SKILL.md`; agents in `agents/`; Gemini-style `settings.json` hooks when installed by GSD | Global `ANTIGRAVITY_CONFIG_DIR` or `~/.gemini/antigravity`; local `./.agent` | GSD owns generated skills/agents/hooks and GSD settings entries only | Public Antigravity install/config docs for this file layout were not stable or complete as of 2026-05-11; installer compatibility therefore uses GSD's Gemini-compatible settings policy, documented shim baseline. |
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
"sonnet": null,
|
||||
"haiku": null
|
||||
},
|
||||
"kimi": {
|
||||
"opus": null,
|
||||
"sonnet": null,
|
||||
"haiku": null
|
||||
},
|
||||
"cursor": {
|
||||
"opus": null,
|
||||
"sonnet": null,
|
||||
|
||||
13
src/core.cts
13
src/core.cts
@@ -1293,7 +1293,18 @@ function checkAgentsInstalled(runtime?: string): AgentsInstalledResult {
|
||||
const agentFile = path.join(agentsDir, `${agent}.md`);
|
||||
const agentFileCopilot = path.join(agentsDir, `${agent}.agent.md`);
|
||||
const agentFileCodex = path.join(agentsDir, `${agent}.toml`);
|
||||
if (fs.existsSync(agentFile) || fs.existsSync(agentFileCopilot) || fs.existsSync(agentFileCodex)) {
|
||||
const agentFileKimiYaml = path.join(agentsDir, 'subagents', `${agent}.yaml`);
|
||||
const agentFileKimiPrompt = path.join(agentsDir, 'subagents', `${agent}.md`);
|
||||
const kimiAgentInstalled =
|
||||
resolvedRuntime === 'kimi' &&
|
||||
fs.existsSync(agentFileKimiYaml) &&
|
||||
fs.existsSync(agentFileKimiPrompt);
|
||||
if (
|
||||
fs.existsSync(agentFile) ||
|
||||
fs.existsSync(agentFileCopilot) ||
|
||||
fs.existsSync(agentFileCodex) ||
|
||||
kimiAgentInstalled
|
||||
) {
|
||||
installed.push(agent);
|
||||
} else {
|
||||
missing.push(agent);
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* kimi — Agent Skills are discovered from Kimi's generic user roots:
|
||||
* ~/.config/agents/skills (recommended) then ~/.agents/skills,
|
||||
* with Kimi selecting the first existing generic skills directory.
|
||||
* ~/.kimi-code/skills is brand-specific and can be selected with
|
||||
* KIMI_CONFIG_DIR.
|
||||
* ~/.kimi-code/skills is brand-specific and can be selected as a
|
||||
* GSD write target with --config-dir or KIMI_CONFIG_DIR.
|
||||
*/
|
||||
|
||||
import os from 'node:os';
|
||||
@@ -79,6 +79,10 @@ export function resolveAntigravityGlobalDir(opts: ResolveAntigravityOpts = {}):
|
||||
* If neither generic skills directory exists yet, install to the recommended
|
||||
* ~/.config/agents root so the generated skills become the first generic
|
||||
* candidate Kimi discovers.
|
||||
*
|
||||
* KIMI_CONFIG_DIR is a GSD installer write-location override. It is not Kimi's
|
||||
* upstream data-root variable, and arbitrary roots are discoverable by Kimi only
|
||||
* when the user also configures Kimi --skills-dir or extra_skill_dirs.
|
||||
*/
|
||||
export function resolveKimiGlobalDir(opts: ResolveKimiOpts = {}): string {
|
||||
const env: Record<string, string | undefined> = opts.env ?? process.env;
|
||||
|
||||
@@ -10,12 +10,17 @@
|
||||
const { test, describe, beforeEach, afterEach } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('node:child_process');
|
||||
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
const { installerEnv } = require('./helpers/install-shared.cjs');
|
||||
|
||||
const AGENTS_DIR_NAME = 'agents';
|
||||
const MODEL_PROFILES = require('../gsd-core/bin/lib/model-profiles.cjs').MODEL_PROFILES;
|
||||
const EXPECTED_AGENTS = Object.keys(MODEL_PROFILES);
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const INSTALL_SCRIPT = path.join(ROOT, 'bin', 'install.js');
|
||||
|
||||
/**
|
||||
* Create a fake GSD install directory structure that mirrors what the installer
|
||||
@@ -276,6 +281,76 @@ describe('checkAgentsInstalled: Copilot .agent.md format (#1512)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Kimi agents/subagents detection (#743 review) ─────────────────────────
|
||||
|
||||
describe('checkAgentsInstalled: Kimi agents/subagents layout', () => {
|
||||
test('Kimi install is detected by init, validate agents, and health checks', () => {
|
||||
const tmpDir = createTempProject('gsd-kimi-agent-status-project-');
|
||||
const tmpConfig = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-agent-status-config-'));
|
||||
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-kimi-agent-status-home-'));
|
||||
const env = installerEnv({
|
||||
HOME: tmpHome,
|
||||
USERPROFILE: tmpHome,
|
||||
KIMI_CONFIG_DIR: tmpConfig,
|
||||
});
|
||||
|
||||
try {
|
||||
const installResult = spawnSync(
|
||||
process.execPath,
|
||||
[INSTALL_SCRIPT, '--kimi', '--global', '--config-dir', tmpConfig, '--no-sdk'],
|
||||
{
|
||||
cwd: tmpDir,
|
||||
encoding: 'utf8',
|
||||
env,
|
||||
},
|
||||
);
|
||||
assert.strictEqual(
|
||||
installResult.status,
|
||||
0,
|
||||
`Kimi install failed\nstdout: ${installResult.stdout}\nstderr: ${installResult.stderr}`,
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'config.json'),
|
||||
JSON.stringify({ runtime: 'kimi', model_profile: 'balanced' }, null, 2),
|
||||
);
|
||||
|
||||
const initResult = runGsdTools('init new-workspace --raw', tmpDir, env);
|
||||
assert.ok(initResult.success, `init failed: ${initResult.error}`);
|
||||
const initOutput = JSON.parse(initResult.output);
|
||||
assert.strictEqual(initOutput.agent_runtime, 'kimi');
|
||||
assert.strictEqual(initOutput.agents_dir, path.join(tmpConfig, 'agents'));
|
||||
assert.strictEqual(initOutput.agents_installed, true);
|
||||
assert.deepStrictEqual(initOutput.missing_agents, []);
|
||||
|
||||
const validateResult = runGsdTools('validate agents --raw', tmpDir, {
|
||||
...env,
|
||||
GSD_RUNTIME: 'kimi',
|
||||
});
|
||||
assert.ok(validateResult.success, `validate agents failed: ${validateResult.error}`);
|
||||
const validateOutput = JSON.parse(validateResult.output);
|
||||
assert.strictEqual(validateOutput.agents_dir, path.join(tmpConfig, 'agents'));
|
||||
assert.strictEqual(validateOutput.agents_found, true);
|
||||
assert.deepStrictEqual(validateOutput.missing, []);
|
||||
|
||||
const healthResult = runGsdTools('validate health --raw', tmpDir, {
|
||||
...env,
|
||||
GSD_RUNTIME: 'kimi',
|
||||
});
|
||||
assert.ok(healthResult.success, `validate health failed: ${healthResult.error}`);
|
||||
const healthOutput = JSON.parse(healthResult.output);
|
||||
const agentWarnings = (healthOutput.warnings || []).filter(
|
||||
(warning) => warning.code === 'W010' || /GSD agents/i.test(warning.message || ''),
|
||||
);
|
||||
assert.deepStrictEqual(agentWarnings, []);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
cleanup(tmpConfig);
|
||||
cleanup(tmpHome);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ─── validate agents subcommand ─────────────────────────────────────────────
|
||||
|
||||
describe('validate agents subcommand (#1371)', () => {
|
||||
|
||||
@@ -334,7 +334,10 @@ describe('Kimi local install guard', () => {
|
||||
0,
|
||||
`second install failed\nstdout: ${second.stdout}\nstderr: ${second.stderr}`,
|
||||
);
|
||||
assert.match(`${second.stdout}\n${second.stderr}`, /locally modified GSD file/i);
|
||||
const secondOutput = `${second.stdout}\n${second.stderr}`;
|
||||
assert.match(secondOutput, /locally modified GSD file/i);
|
||||
assert.match(secondOutput, /\/skill:gsd-update --reapply/);
|
||||
assert.doesNotMatch(secondOutput, /Run\s+\/gsd-update --reapply/);
|
||||
|
||||
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');
|
||||
|
||||
@@ -9,6 +9,7 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const { catalog, KNOWN_RUNTIMES } = require('../gsd-core/bin/lib/model-catalog.cjs');
|
||||
const { allRuntimes } = require('../bin/install.js');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const SETTINGS_ADVANCED = fs.readFileSync(path.join(ROOT, 'gsd-core', 'workflows', 'settings-advanced.md'), 'utf8');
|
||||
@@ -17,9 +18,14 @@ const CONFIG_DOC = fs.readFileSync(path.join(ROOT, 'docs', 'CONFIGURATION.md'),
|
||||
describe('model catalog runtime defaults parity (#3229)', () => {
|
||||
test('known runtimes include hermes and match catalog keys', () => {
|
||||
assert.ok(KNOWN_RUNTIMES.has('hermes'));
|
||||
assert.ok(KNOWN_RUNTIMES.has('kimi'));
|
||||
assert.deepStrictEqual([...KNOWN_RUNTIMES].sort(), Object.keys(catalog.runtimeTierDefaults).sort());
|
||||
});
|
||||
|
||||
test('installer-supported runtimes are all known to the model catalog', () => {
|
||||
assert.deepStrictEqual([...allRuntimes].sort(), [...KNOWN_RUNTIMES].sort());
|
||||
});
|
||||
|
||||
test('settings-advanced runtime defaults table matches catalog for concrete runtimes', () => {
|
||||
for (const [runtime, tiers] of Object.entries(catalog.runtimeTierDefaults)) {
|
||||
if (!tiers.opus) continue; // Group B runtimes intentionally have no built-ins
|
||||
|
||||
Reference in New Issue
Block a user