mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-09 17:29:12 +00:00
refactor(kap-server): rename server-v2 package to kap-server
- rename packages/server-v2 to packages/kap-server and update every @moonshot-ai/server-v2 reference across apps, packages, flake.nix, and build scripts - remove the experimental `kimi v2` CLI prefix and its tests from the apps/kimi-code main entry - add legacy BackgroundTask protocol types and the `blocked` turn interrupt reason for cross-engine compatibility
This commit is contained in:
parent
957c493136
commit
304883ab81
151 changed files with 144 additions and 211 deletions
|
|
@ -88,7 +88,7 @@
|
|||
"@moonshot-ai/migration-legacy": "workspace:^",
|
||||
"@moonshot-ai/pi-tui": "workspace:^",
|
||||
"@moonshot-ai/server": "workspace:^",
|
||||
"@moonshot-ai/server-v2": "workspace:^",
|
||||
"@moonshot-ai/kap-server": "workspace:^",
|
||||
"@moonshot-ai/vis-server": "workspace:^",
|
||||
"@moonshot-ai/vis-web": "workspace:*",
|
||||
"@types/semver": "^7.7.0",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
/**
|
||||
* Experimental agent-core-v2 engine gate.
|
||||
*
|
||||
* Both the `kimi v2 <subcommand>` prefix (see `main.ts`) and the
|
||||
* `kimi server run` → server-v2 routing (see `sub/server/run.ts`) key off this
|
||||
* single master switch. Read directly from the env (matching
|
||||
* The `kimi server run` → server-v2 routing (see `sub/server/run.ts`) keys off
|
||||
* this single master switch. Read directly from the env (matching
|
||||
* `cli/update/rollout.ts`) because the CLI must not depend on the core flag
|
||||
* registry. Unset / any non-truthy value keeps the v1 engine.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ const WEB_ASSETS_DIR = 'dist-web';
|
|||
|
||||
/**
|
||||
* `kimi server run` → server-v2 routing is gated by the master experimental
|
||||
* switch shared with the `kimi v2` prefix (`#/cli/experimental-v2`). When it is
|
||||
* truthy, the in-process runner boots the DI × Scope engine server
|
||||
* (`@moonshot-ai/server-v2`) instead of the default `@moonshot-ai/server`.
|
||||
* switch (`#/cli/experimental-v2`). When it is truthy, the in-process runner
|
||||
* boots the DI × Scope engine server (`@moonshot-ai/kap-server`) instead of
|
||||
* the default `@moonshot-ai/server`.
|
||||
*
|
||||
* Re-exported under the historical name so existing callers/tests keep working.
|
||||
*/
|
||||
|
|
@ -405,7 +405,7 @@ async function runServerInProcess(
|
|||
// the default (flag-off) path keeps the exact v1-only module graph — v2 and
|
||||
// its agent-core-v2 engine are only resolved when the flag is on.
|
||||
const { createServerLogger: createServerV2Logger, startServer: startServerV2 } =
|
||||
await import('@moonshot-ai/server-v2');
|
||||
await import('@moonshot-ai/kap-server');
|
||||
const logger = createServerV2Logger({ level: options.logLevel });
|
||||
const v2 = await startServerV2({
|
||||
host: options.host,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import {
|
|||
} from '@moonshot-ai/kimi-telemetry';
|
||||
|
||||
import { createProgram } from './cli/commands';
|
||||
import { isKimiV2Enabled, KIMI_V2_ENV } from './cli/experimental-v2';
|
||||
import { finalizeHeadlessRun } from './cli/headless-exit';
|
||||
import type { CLIOptions } from './cli/options';
|
||||
import { OptionConflictError, validateOptions } from './cli/options';
|
||||
|
|
@ -133,43 +132,6 @@ const MIGRATE_CLI_OPTIONS: CLIOptions = {
|
|||
skillsDirs: [],
|
||||
};
|
||||
|
||||
const V2_PREFIX_TOKEN = 'v2';
|
||||
|
||||
export type ApplyV2PrefixOutcome =
|
||||
| { readonly argv: readonly string[] }
|
||||
| { readonly error: string };
|
||||
|
||||
/**
|
||||
* Rewrite argv for the experimental `kimi v2` prefix.
|
||||
*
|
||||
* `v2` is not a Commander subcommand — it is a prefix handled here so that
|
||||
* `kimi v2 <subcommand> <args>` runs through the *identical* code paths as
|
||||
* `kimi <subcommand> <args>`. Engine selection stays keyed on
|
||||
* `KIMI_CODE_EXPERIMENTAL_FLAG` (e.g. `kimi v2 server run` boots server-v2 /
|
||||
* agent-core-v2, which `sub/server/run.ts` already honors).
|
||||
*
|
||||
* Only effective when the flag is set: with the flag off, the prefix is
|
||||
* rejected with a hint rather than silently falling back to the v1 engine.
|
||||
*/
|
||||
export function applyV2Prefix(
|
||||
argv: readonly string[],
|
||||
env: Readonly<Record<string, string | undefined>> = process.env,
|
||||
): ApplyV2PrefixOutcome {
|
||||
// The prefix must be the first positional token (right after node + script).
|
||||
if (argv[2] !== V2_PREFIX_TOKEN) {
|
||||
return { argv };
|
||||
}
|
||||
if (!isKimiV2Enabled(env)) {
|
||||
return {
|
||||
error:
|
||||
"'kimi v2' is experimental and requires the agent-core-v2 engine. " +
|
||||
`Set ${KIMI_V2_ENV}=1 to enable it.`,
|
||||
};
|
||||
}
|
||||
// Strip the `v2` token; the remaining argv is parsed as a normal `kimi` invocation.
|
||||
return { argv: [...argv.slice(0, 2), ...argv.slice(3)] };
|
||||
}
|
||||
|
||||
export function main(): void {
|
||||
process.title = PROCESS_NAME;
|
||||
installCrashHandlers();
|
||||
|
|
@ -191,12 +153,6 @@ export function main(): void {
|
|||
|
||||
const version = getVersion();
|
||||
|
||||
const v2 = applyV2Prefix(process.argv);
|
||||
if ('error' in v2) {
|
||||
process.stderr.write(`${v2.error}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const program = createProgram(
|
||||
version,
|
||||
(opts) => {
|
||||
|
|
@ -252,7 +208,7 @@ export function main(): void {
|
|||
},
|
||||
);
|
||||
|
||||
program.parse(v2.argv);
|
||||
program.parse(process.argv);
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { runPrompt } from '#/cli/run-prompt';
|
|||
import { runShell } from '#/cli/run-shell';
|
||||
import { formatStartupError } from '#/cli/startup-error';
|
||||
import { runUpdatePreflight } from '#/cli/update/preflight';
|
||||
import { applyV2Prefix, handleMainCommand, handleUpgradeCommand, main } from '#/main';
|
||||
import { handleMainCommand, handleUpgradeCommand, main } from '#/main';
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const parse = vi.fn();
|
||||
|
|
@ -421,87 +421,3 @@ describe('main entry command handling', () => {
|
|||
).toBe('error: failed to run prompt: Provider not set\n');
|
||||
});
|
||||
});
|
||||
|
||||
describe('kimi beta prefix', () => {
|
||||
const ON = { KIMI_CODE_EXPERIMENTAL_FLAG: '1' };
|
||||
const OFF: Readonly<Record<string, string | undefined>> = {};
|
||||
|
||||
describe('applyV2Prefix', () => {
|
||||
it('passes argv through unchanged when there is no beta token', () => {
|
||||
const argv = ['node', 'kimi', 'server', 'run'];
|
||||
expect(applyV2Prefix(argv, ON)).toEqual({ argv });
|
||||
expect(applyV2Prefix(argv, OFF)).toEqual({ argv });
|
||||
});
|
||||
|
||||
it('strips the beta token when the experimental flag is on', () => {
|
||||
expect(applyV2Prefix(['node', 'kimi', 'beta', 'server', 'run'], ON)).toEqual({
|
||||
argv: ['node', 'kimi', 'server', 'run'],
|
||||
});
|
||||
});
|
||||
|
||||
it('strips a lone beta token (default chat) when the flag is on', () => {
|
||||
expect(applyV2Prefix(['node', 'kimi', 'beta'], ON)).toEqual({
|
||||
argv: ['node', 'kimi'],
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects the beta prefix with a hint when the flag is off', () => {
|
||||
const outcome = applyV2Prefix(['node', 'kimi', 'beta', 'server', 'run'], OFF);
|
||||
expect('error' in outcome && outcome.error).toMatch(/KIMI_CODE_EXPERIMENTAL_FLAG/);
|
||||
});
|
||||
|
||||
it('does not treat a later beta token as the prefix', () => {
|
||||
const argv = ['node', 'kimi', 'server', 'beta'];
|
||||
expect(applyV2Prefix(argv, ON)).toEqual({ argv });
|
||||
});
|
||||
});
|
||||
|
||||
describe('main() wiring', () => {
|
||||
let originalArgv: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
originalArgv = process.argv;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.argv = originalArgv;
|
||||
vi.unstubAllEnvs();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('parses the stripped argv when the flag is on', () => {
|
||||
vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '1');
|
||||
process.argv = ['node', 'kimi', 'beta', 'server', 'run'];
|
||||
|
||||
main();
|
||||
|
||||
expect(mocks.parse).toHaveBeenCalledWith(['node', 'kimi', 'server', 'run']);
|
||||
});
|
||||
|
||||
it('exits with a hint and never parses when the flag is off', () => {
|
||||
vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '');
|
||||
process.argv = ['node', 'kimi', 'beta', 'server', 'run'];
|
||||
const writes: string[] = [];
|
||||
vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => {
|
||||
writes.push(String(chunk));
|
||||
return true;
|
||||
});
|
||||
vi.spyOn(process, 'exit').mockImplementation((code?: string | number | null) => {
|
||||
throw new ExitCalled(Number(code ?? 0));
|
||||
});
|
||||
|
||||
let exitCode: number | undefined;
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
if (error instanceof ExitCalled) exitCode = error.code;
|
||||
else throw error;
|
||||
}
|
||||
|
||||
expect(exitCode).toBe(1);
|
||||
expect(mocks.parse).not.toHaveBeenCalled();
|
||||
expect(writes.join('')).toContain('KIMI_CODE_EXPERIMENTAL_FLAG');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -693,11 +693,10 @@ describe('server-v2 routing (KIMI_CODE_EXPERIMENTAL_FLAG)', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('is the canonical experimental-v2 gate shared with the `kimi beta` prefix', async () => {
|
||||
it('is the canonical experimental-v2 gate', async () => {
|
||||
const { isServerV2Enabled } = await import('#/cli/sub/server/run');
|
||||
const { isKimiV2Enabled, KIMI_V2_ENV } = await import('#/cli/experimental-v2');
|
||||
expect(KIMI_V2_ENV).toBe('KIMI_CODE_EXPERIMENTAL_FLAG');
|
||||
// Server routing and the `kimi beta` prefix must agree on the exact same gate.
|
||||
expect(isServerV2Enabled).toBe(isKimiV2Enabled);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { dirname, join } from 'node:path';
|
|||
* package.json `imports` field does — scoped to the IMPORTER's owning package,
|
||||
* honoring array fallbacks such as `"#/*": ["./src/*.ts", "./src/<x>/index.ts"]`.
|
||||
*
|
||||
* Why this is needed: when the CLI bundles `@moonshot-ai/server-v2`, rolldown
|
||||
* Why this is needed: when the CLI bundles `@moonshot-ai/kap-server`, rolldown
|
||||
* inlines `@moonshot-ai/agent-core-v2` source, whose internal `#/foo` imports
|
||||
* must resolve against each package's own `src/`. Rolldown (like tsx) only
|
||||
* honors the first array element of an `imports` target and therefore breaks
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
./packages/agent-core
|
||||
./packages/agent-core-v2
|
||||
./packages/server
|
||||
./packages/server-v2
|
||||
./packages/kap-server
|
||||
./packages/server-e2e
|
||||
./packages/kaos
|
||||
./packages/kosong
|
||||
|
|
@ -91,7 +91,7 @@
|
|||
"@moonshot-ai/agent-core"
|
||||
"@moonshot-ai/agent-core-v2"
|
||||
"@moonshot-ai/server"
|
||||
"@moonshot-ai/server-v2"
|
||||
"@moonshot-ai/kap-server"
|
||||
"@moonshot-ai/server-e2e"
|
||||
"@moonshot-ai/kaos"
|
||||
"@moonshot-ai/kosong"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* logs through `log`. Bound at App scope.
|
||||
*
|
||||
* WS event fan-out (sequencing, journaling, replay, per-connection dispatch)
|
||||
* is a transport concern and lives in the edge package (`packages/server-v2`)
|
||||
* is a transport concern and lives in the edge package (`packages/kap-server`)
|
||||
* on top of `IEventService` + `IAgentRecordService` — not here.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1283,7 +1283,8 @@ type TelemetryInterruptReason =
|
|||
| 'aborted'
|
||||
| 'max_steps'
|
||||
| 'error'
|
||||
| 'filtered';
|
||||
| 'filtered'
|
||||
| 'blocked';
|
||||
|
||||
function telemetryInterruptReason(
|
||||
reason: LoopTurnInterruptedEvent['reason'] | Exclude<TurnEndedEvent['reason'], 'completed'>,
|
||||
|
|
@ -1294,6 +1295,7 @@ function telemetryInterruptReason(
|
|||
}
|
||||
if (reason === 'aborted' || reason === 'cancelled') return 'aborted';
|
||||
if (reason === 'failed') return 'error';
|
||||
if (reason === 'blocked') return 'blocked';
|
||||
// Remaining values are `max_steps` | `error` | `filtered`, which match the
|
||||
// telemetry enum.
|
||||
return reason;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@moonshot-ai/server-v2",
|
||||
"name": "@moonshot-ai/kap-server",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "Kimi Code server backed by the DI × Scope agent engine (agent-core-v2)",
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* `@moonshot-ai/server-v2/contract` — the public `/api/v2` wire contract.
|
||||
* `@moonshot-ai/kap-server/contract` — the public `/api/v2` wire contract.
|
||||
*
|
||||
* Re-exports the server-side allowlists that bind public `resource:action`
|
||||
* segments and event names to internal Services. Client SDKs import this
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* `@moonshot-ai/server-v2` public surface — the Kimi Code server backed by the
|
||||
* `@moonshot-ai/kap-server` public surface — the Kimi Code server backed by the
|
||||
* DI × Scope agent engine (`@moonshot-ai/agent-core-v2`).
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue