kimi-code/flake.nix
Haozhe 4cffd732c2
feat(klient): contract-driven facade with http/ipc/memory transports (#1768)
* feat(klient): contract-driven facade with http/ipc/memory transports

- add zod-validated contract sections (global/session/agent) under
  src/contract and a facade exposing global.*, session(id).*, agent(id).*
- select transport once at creation via subpath entries
  (@moonshot-ai/klient/http|ipc|memory); drop legacy channel/client/
  httpChannel/wsChannel/wsKlient/proxy implementations
- absorb packages/server-e2e into packages/klient test/e2e suites
  (dual-backend, legacy v1, v2 wire) and remove the server-e2e workspace
- expose model registry and catalog services on kap-server v2 RPC surface

* fix(klient): derive session status from agentActivityView

The engine retired its sessionActivity service in #1751 (session busy is
now derived from agent activity views), but the facade still called the
deleted wire channel and imported the deleted engine module, breaking
typecheck and every klient suite at import time.

- drop the sessionActivity contract/registry entries and mirror the
  agentActivityView service instead (agent scope)
- compose session status() client-side from the pending interaction lists
  and each agent's agentActivityView, keeping the retired service's
  precedence and typing SessionStatus locally in the facade
- replace the deleted-channel call in the v2 smoke suite with a
  sessionInteractionService probe
- fix the legacy image-file suite to wait with the harness's
  waitForSessionBusy
2026-07-16 16:43:09 +08:00

259 lines
8.4 KiB
Nix

{
description = "Kimi Code CLI";
inputs = {
# Pinned to the 25.11 release channel because nixpkgs-unstable currently
# ships nodejs_24 = 24.14.1, which trips the >= 24.15.0 floor that the
# native SEA build enforces (see apps/kimi-code/scripts/native/build.mjs).
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
};
outputs =
{ self, nixpkgs }:
let
lib = nixpkgs.lib;
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forAllSystems =
f:
lib.genAttrs systems (
system:
f (import nixpkgs {
inherit system;
})
);
minNodeVersion = "24.15.0";
# Hardcode to Node.js 24.x; fail the evaluation if the pinned nixpkgs
# does not offer a new enough 24.x.
nodejsFor =
pkgs:
let
node = pkgs.nodejs_24;
in
if lib.versionAtLeast node.version minNodeVersion then
node
else
throw ''
Kimi Code requires Node.js >= ${minNodeVersion},
but nixpkgs only offers ${node.version}.
Pin a newer nixpkgs revision or update minNodeVersion in flake.nix.
'';
pnpmFor =
pkgs:
pkgs.pnpm_10.override {
nodejs = nodejsFor pkgs;
};
# -------------------------------------------------------------------
# Workspace members (kept in sync with pnpm-workspace.yaml).
#
# HARD REQUIREMENT: whenever you add or remove a workspace package,
# you MUST update both lists below. Missing a path will break the Nix
# build (src fileset silently drops files); missing a name will break
# pnpmConfigHook (dependencies for that workspace won't be fetched).
# -------------------------------------------------------------------
workspacePaths = [
./packages/acp-adapter
./packages/agent-core
./packages/agent-core-v2
./packages/kap-server
./packages/kaos
./packages/klient
./packages/kosong
./packages/migration-legacy
./packages/minidb
./packages/node-sdk
./packages/oauth
./packages/pi-tui
./packages/protocol
./packages/telemetry
./apps/kimi-code
./apps/kimi-desktop
./apps/kimi-web
./apps/vis
./apps/vis/server
./apps/vis/web
./docs
];
workspaceNames = [
"@moonshot-ai/acp-adapter"
"@moonshot-ai/agent-core"
"@moonshot-ai/agent-core-v2"
"@moonshot-ai/kap-server"
"@moonshot-ai/kaos"
"@moonshot-ai/kosong"
"@moonshot-ai/migration-legacy"
"@moonshot-ai/minidb"
"@moonshot-ai/kimi-code-sdk"
"@moonshot-ai/kimi-code-oauth"
"@moonshot-ai/klient"
"@moonshot-ai/pi-tui"
"@moonshot-ai/protocol"
"@moonshot-ai/kimi-telemetry"
"@moonshot-ai/kimi-code"
"@moonshot-ai/kimi-desktop"
"@moonshot-ai/kimi-web"
"@moonshot-ai/vis"
"@moonshot-ai/vis-server"
"@moonshot-ai/vis-web"
"kimi-code-docs"
];
in
{
packages = forAllSystems (
pkgs:
let
nodejs = nodejsFor pkgs;
pnpm = pnpmFor pkgs;
appPackageJson = builtins.fromJSON (builtins.readFile ./apps/kimi-code/package.json);
nativeTarget =
if pkgs.stdenv.hostPlatform.isLinux && pkgs.stdenv.hostPlatform.isAarch64 then
"linux-arm64"
else if pkgs.stdenv.hostPlatform.isLinux then
"linux-x64"
else if pkgs.stdenv.hostPlatform.isDarwin && pkgs.stdenv.hostPlatform.isAarch64 then
"darwin-arm64"
else if pkgs.stdenv.hostPlatform.isDarwin then
"darwin-x64"
else
throw "Unsupported Kimi Code native target for ${pkgs.stdenv.hostPlatform.system}";
kimi-code = pkgs.stdenv.mkDerivation (finalAttrs: {
pname = "kimi-code";
version = appPackageJson.version;
src = lib.fileset.toSource {
root = ./.;
fileset = lib.fileset.unions (
[
./build
./.npmrc
./.nvmrc
./package.json
./pnpm-lock.yaml
./pnpm-workspace.yaml
./tsconfig.json
./vitest.config.ts
./LICENSE
]
++ workspacePaths
);
};
pnpmWorkspaces = [ "." ] ++ workspaceNames;
pnpmDeps = pkgs.fetchPnpmDeps {
inherit (finalAttrs) pname version src pnpmWorkspaces;
inherit pnpm;
fetcherVersion = 3;
hash = "sha256-dqniDBWjKjtTcr+zKhtilkKXdNMfiwnfrqH/7Cg4eZ0=";
};
nativeBuildInputs = [
nodejs
pnpm
(pkgs.pnpmConfigHook.override { inherit pnpm; })
pkgs.makeWrapper
]
# The SEA inject step (postject) invalidates the macOS code
# signature on the copied Node executable; build.mjs then re-applies
# an ad-hoc signature via `codesign`. The Nix darwin sandbox does
# not expose /usr/bin/codesign, so we supply nixpkgs' ad-hoc-only
# replacement instead.
++ lib.optionals pkgs.stdenv.hostPlatform.isDarwin [
pkgs.darwin.sigtool
];
# The SEA binary is produced by `postject`-injecting a blob into a
# plain Node executable. Stripping rewrites section tables and can
# invalidate the injected blob's offsets, so leave the binary
# untouched after the build.
dontStrip = true;
buildPhase = ''
runHook preBuild
export KIMI_CODE_BUILD_TARGET=${nativeTarget}
${lib.optionalString pkgs.stdenv.hostPlatform.isDarwin ''
# pkgs.darwin.sigtool's codesign supports `--sign -` (ad-hoc)
# but not the inspection mode (`-dv`) that 05-verify.mjs runs
# afterwards. Disable the verify step for the Nix build; the
# release CI keeps it via the unmodified script.
substituteInPlace apps/kimi-code/scripts/native/build.mjs \
--replace-fail \
"await runVerifyStep({ requireGatekeeper: false });" \
"// runVerifyStep skipped in nix sandbox (sigtool lacks -dv)"
''}
# The SEA blob step (scripts/native/02-sea-blob.mjs) embeds the
# Kimi web assets from apps/kimi-code/dist-web and fails if that
# directory is missing. Build the web app and stage its assets
# before producing the native executable.
pnpm --filter=@moonshot-ai/kimi-web run build
node apps/kimi-code/scripts/copy-web-assets.mjs
pnpm --filter=@moonshot-ai/kimi-code run build:native:sea
runHook postBuild
'';
installPhase = ''
runHook preInstall
install -Dm755 \
"apps/kimi-code/dist-native/bin/${nativeTarget}/kimi" \
"$out/bin/kimi"
runHook postInstall
'';
postInstall = ''
wrapProgram $out/bin/kimi --prefix PATH : ${lib.makeBinPath [ pkgs.ripgrep pkgs.fd ]}
'';
meta = {
description = "Kimi Code CLI";
homepage = "https://github.com/MoonshotAI/kimi-code";
license = lib.licenses.mit;
mainProgram = "kimi";
platforms = systems;
};
});
in
{
inherit kimi-code;
default = kimi-code;
}
);
apps = forAllSystems (pkgs: {
kimi-code = {
type = "app";
program = "${self.packages.${pkgs.system}.kimi-code}/bin/kimi";
};
default = self.apps.${pkgs.system}.kimi-code;
});
devShells = forAllSystems (pkgs: {
default =
let
nodejs = nodejsFor pkgs;
pnpm = pnpmFor pkgs;
in
pkgs.mkShell {
packages = [
nodejs
pnpm
pkgs.ripgrep
pkgs.fd
];
};
});
};
}