mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-07 15:56:39 +00:00
Compare commits
No commits in common. "main" and "@moonshot-ai/kimi-code@0.31.1" have entirely different histories.
main
...
@moonshot-
1927 changed files with 82845 additions and 97856 deletions
|
|
@ -67,4 +67,4 @@ Invariants that hold across every stage. Each is expanded in the stage file note
|
||||||
9. Throw coded errors; register codes centrally; branch on `code` across the wire, never `instanceof`. (errors.md)
|
9. Throw coded errors; register codes centrally; branch on `code` across the wire, never `instanceof`. (errors.md)
|
||||||
10. Gate unreleased behavior behind a flag contributed via `registerFlagDefinition` and resolved through `IFlagService.enabled(id)`; no ad-hoc env toggles. (flags.md)
|
10. Gate unreleased behavior behind a flag contributed via `registerFlagDefinition` and resolved through `IFlagService.enabled(id)`; no ad-hoc env toggles. (flags.md)
|
||||||
11. Tests resolve the SUT by interface; shared stubs live under `test/`, never `src/`. (test.md)
|
11. Tests resolve the SUT by interface; shared stubs live under `test/`, never `src/`. (test.md)
|
||||||
12. Config is the preference registry: only preferences that are persistable, schema'd, and user/operator-facing go in `IConfigService`. Domain-specific config (including env-only operational toggles) goes through `registerConfigSection` + `envOverlay`. Facts → `IBootstrapService`, and host invocation arguments (CLI flags, host identity headers, prompt identity) → `BootstrapInput.args` / `IBootstrapService.args` — never new per-domain runtime-options services; domain runtime state (cron/flags/model) never goes onto `IBootstrapService`; session state → Session scope; constants → code. Business domains never call `IBootstrapService.getEnv()` directly. (config.md)
|
12. Config is the preference registry: only preferences that are persistable, schema'd, and user/operator-facing go in `IConfigService`. Domain-specific config (including env-only operational toggles) goes through `registerSection` + `envOverlay`. Facts → `IBootstrapService`, and host invocation arguments (CLI flags, host identity headers, prompt identity) → `BootstrapInput.args` / `IBootstrapService.args` — never new per-domain runtime-options services; domain runtime state (cron/flags/model) never goes onto `IBootstrapService`; session state → Session scope; constants → code. Business domains never call `IBootstrapService.getEnv()` directly. (config.md)
|
||||||
|
|
|
||||||
|
|
@ -157,8 +157,7 @@ import { InstantiationType, registerSingleton } from '../../di';
|
||||||
registerSingleton(IXxxService, XxxService, InstantiationType.Delayed);
|
registerSingleton(IXxxService, XxxService, InstantiationType.Delayed);
|
||||||
|
|
||||||
// v2
|
// v2
|
||||||
import { LifecycleScope } from '#/app/scopes';
|
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
|
||||||
registerScopedService(LifecycleScope.Session, IXxxService, XxxService, ScopeActivation.OnDemand, 'xxx');
|
registerScopedService(LifecycleScope.Session, IXxxService, XxxService, ScopeActivation.OnDemand, 'xxx');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
How the `config` domain works and how a domain owns its configuration section. Covers the section-registry model, the App vs Session split, the TOML on-disk format, and the recipe for adding or migrating a config section.
|
How the `config` domain works and how a domain owns its configuration section. Covers the section-registry model, the App vs Session split, the TOML on-disk format, and the recipe for adding or migrating a config section.
|
||||||
|
|
||||||
The `config` domain is a thin registry + loader: it does **not** know the shape of any individual section. Each domain owns the schema (and, where needed, the TOML transform) for the config it consumes, contributes the section (statically at module load via `registerConfigSection`, or at runtime as a `ConfigSectionContribution` collection record), and reads it through `IConfigService`. There is no whole-config object passed around.
|
The `config` domain is a thin registry + loader: it does **not** know the shape of any individual section. Each domain owns the schema (and, where needed, the TOML transform) for the config it consumes, registers the section into `IConfigRegistry`, and reads it through `IConfigService`. There is no whole-config object passed around.
|
||||||
|
|
||||||
## What belongs in Config
|
## What belongs in Config
|
||||||
|
|
||||||
|
|
@ -93,15 +93,13 @@ pass `ConfigTarget.Memory` for a per-run override that is never written to disk.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `src/app/config/config.ts` — `IConfigRegistry` / `IConfigService` tokens, `ConfigSection`, `ConfigEffectiveOverlay`, event types.
|
- `src/config/config.ts` — `IConfigRegistry` / `IConfigService` tokens, `ConfigSection`, `ConfigEffectiveOverlay`, event types.
|
||||||
- `src/app/config/configService.ts` — `ConfigRegistry` + `ConfigService` impl; self-registers at App scope. The registry is also the fold of the `ConfigSectionContribution` collection: it drains the module-level contributions at construction, then refolds incrementally (`added` → `registerSection`, `removed` → `unregisterSection`).
|
- `src/config/configService.ts` — `ConfigRegistry` + `ConfigService` impl; self-registers at App scope.
|
||||||
- `src/app/config/configSectionContributions.ts` — the `ConfigSectionContribution` collection token (the runtime channel: a unit contributes with `this.provide(ConfigSectionContribution, …)`) plus the module-level `registerConfigSection` collector (the static channel, import = register).
|
- `src/config/toml.ts` — generic snake_case ↔ camelCase machinery plus the registry-aware `transformTomlData` / `applySectionToToml` entry points. Per-domain normalization lives in the section owner's `configSection.ts` (registered as `fromToml` / `toToml`); this module stays free of any other domain's semantics.
|
||||||
- `src/app/config/configOverlayContributions.ts` — the module-level `registerConfigOverlay` collector for `ConfigEffectiveOverlay`s (drained at construction like the sections).
|
- `src/profile/thinking.ts` (owner domain, not `config`) — the `resolveThinkingEffort` helper; uses the authoritative `ThinkingConfig` from `configSection.ts`.
|
||||||
- `src/app/config/toml.ts` — generic snake_case ↔ camelCase machinery plus the registry-aware `transformTomlData` / `applySectionToToml` entry points. Per-domain normalization lives in the section owner's `configSection.ts` (registered as `fromToml` / `toToml`); this module stays free of any other domain's semantics.
|
- `src/config/configPure.ts` — `isPlainObject`, `deepMerge`, `omitUndefined`, `describeUnknownError`.
|
||||||
- `src/kosong/model/thinking.ts` (owner domain, not `config`) — the `resolveThinkingEffort` helper and the authoritative `ThinkingConfig` type (the `thinking` section itself registers from `src/app/kosongConfig/configSection.ts`).
|
|
||||||
- `src/app/config/configPure.ts` — `isPlainObject`, `deepMerge`, `omitUndefined`, `describeUnknownError`.
|
|
||||||
|
|
||||||
A domain that owns a section keeps the schema in its own `configSection.ts` (e.g. `src/app/flag/flag.ts` for `experimental`, `src/agent/loop/configSection.ts` for `loopControl`). Exception: kosong-owned sections (`providers`, `models`, `thinking`) — kosong is a pure, persistence-free abstraction layer that defines only the types (`src/kosong/{provider,model}`); the section constants, the zod schemas (re-derived from those types and compile-time pinned via `AssertExact<Equal<z.infer<typeof Schema>, Type>>`, see `_base/utils/typeEquality.ts`), the registrations, env bindings, and TOML transforms all live in the persistence wrapper `src/app/kosongConfig/configSection.ts`. (`modelCatalog` and `secondaryModel` have no kosong-side type at all — their sections are fully self-contained in `app/kosongConfig`, types derived from the schemas.) A cross-section env overlay (e.g. the `KIMI_MODEL_*` synthesis) lives in the wrapper too (`src/app/kosongConfig/envOverlay.ts`; the `[secondary_model]` derived-entry synthesis in `secondaryModelOverlay.ts`) and is registered via module-level `registerConfigOverlay`. The two-way sync between config sections and kosong's in-memory registries is owned by `IKosongConfigService` (`src/app/kosongConfig/kosongConfigService.ts`).
|
A domain that owns a section keeps the schema in its own `configSection.ts` (e.g. `src/flag/flag.ts` for `experimental`, `src/loop/configSection.ts` for `loopControl`). Exception: kosong-owned sections (`providers`, `models`, `thinking`) — kosong is a pure, persistence-free abstraction layer that defines only the types (`src/kosong/{provider,model}`); the section constants, the zod schemas (re-derived from those types and compile-time pinned via `AssertExact<Equal<z.infer<typeof Schema>, Type>>`, see `_base/utils/typeEquality.ts`), the registrations, env bindings, and TOML transforms all live in the persistence wrapper `src/app/kosongConfig/configSection.ts`. (`modelCatalog` and `secondaryModel` have no kosong-side type at all — their sections are fully self-contained in `app/kosongConfig`, types derived from the schemas.) A cross-section env overlay (e.g. the `KIMI_MODEL_*` synthesis) lives in the wrapper too (`src/app/kosongConfig/envOverlay.ts`; the `[secondary_model]` derived-entry synthesis in `secondaryModelOverlay.ts`) and is registered via `IConfigRegistry.registerEffectiveOverlay`. The two-way sync between config sections and kosong's in-memory registries is owned by `IKosongConfigService` (`src/app/kosongConfig/kosongConfigService.ts`).
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
|
|
@ -119,14 +117,9 @@ A config section is identified by a camelCase domain key (`'providers'`, `'think
|
||||||
- `fromToml?: ConfigFromToml` — read-path transform (snake_case file value → in-memory shape). Defaults to a plain key-casing pass; owners register one when the on-disk shape needs custom normalization (record key preservation, nested object conversion, array entries, key renames, reshapes).
|
- `fromToml?: ConfigFromToml` — read-path transform (snake_case file value → in-memory shape). Defaults to a plain key-casing pass; owners register one when the on-disk shape needs custom normalization (record key preservation, nested object conversion, array entries, key renames, reshapes).
|
||||||
- `toToml?: ConfigToToml` — write-path transform (in-memory value → snake_case file value). Defaults to a plain camelCase→snake_case key mapping.
|
- `toToml?: ConfigToToml` — write-path transform (in-memory value → snake_case file value). Defaults to a plain camelCase→snake_case key mapping.
|
||||||
|
|
||||||
Two contribution channels:
|
|
||||||
|
|
||||||
- **Static (import = register)** — the owning domain calls `registerConfigSection(domain, schema, options)` at the top level of its `configSection.ts`; `ConfigRegistry` drains the collected contributions when it is constructed. Every in-repo section uses this channel.
|
|
||||||
- **Runtime (collection record)** — a unit contributes `this.provide(ConfigSectionContribution, { domain, schema, options })` (e.g. a feature assembled through `IFeatureManager`); the `ConfigRegistry` fold registers the section when the record lands and unregisters it when the record is withdrawn (provider disposed). User TOML values survive a withdrawal — they just stop being validated and effective.
|
|
||||||
|
|
||||||
Ownership rules:
|
Ownership rules:
|
||||||
|
|
||||||
- **One owner per section.** `registerSection` throws if a domain is registered twice — the static channel fails fast when `ConfigRegistry` drains it; a conflicting runtime record is reported through `onUnexpectedError` and the first registration wins (the fold is an event path and never throws).
|
- **One owner per section.** `registerSection` throws if a domain is registered twice.
|
||||||
- **The domain that consumes a config owns its schema.** This is what keeps `config` from depending on its consumers: `config` must not import `externalHooks` / `permissionRules` / `provider` / `kosong` / etc. for a section's schema. If a schema needs a domain's types, the schema lives in that domain.
|
- **The domain that consumes a config owns its schema.** This is what keeps `config` from depending on its consumers: `config` must not import `externalHooks` / `permissionRules` / `provider` / `kosong` / etc. for a section's schema. If a schema needs a domain's types, the schema lives in that domain.
|
||||||
- **Demand-driven.** Do not register sections for config that no domain reads yet; a section appears (with its schema in the owning domain) only when a consumer appears.
|
- **Demand-driven.** Do not register sections for config that no domain reads yet; a section appears (with its schema in the owning domain) only when a consumer appears.
|
||||||
|
|
||||||
|
|
@ -138,7 +131,7 @@ Declare the bindings with `envBindings(schema, { … })` — the field names are
|
||||||
type-checked against the schema (no magic strings), and nested schemas recurse:
|
type-checked against the schema (no magic strings), and nested schemas recurse:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
registerConfigSection('thinking', ThinkingConfigSchema, {
|
registerSection('thinking', ThinkingConfigSchema, {
|
||||||
env: envBindings(ThinkingConfigSchema, {
|
env: envBindings(ThinkingConfigSchema, {
|
||||||
effort: 'KIMI_MODEL_THINKING_EFFORT',
|
effort: 'KIMI_MODEL_THINKING_EFFORT',
|
||||||
}),
|
}),
|
||||||
|
|
@ -146,7 +139,7 @@ registerConfigSection('thinking', ThinkingConfigSchema, {
|
||||||
|
|
||||||
// nested / record section — outer key is a runtime constant, inner fields are
|
// nested / record section — outer key is a runtime constant, inner fields are
|
||||||
// checked against the value schema:
|
// checked against the value schema:
|
||||||
registerConfigSection('providers', ProvidersSectionSchema, {
|
registerSection('providers', ProvidersSectionSchema, {
|
||||||
env: envBindings(ProvidersSectionSchema, {
|
env: envBindings(ProvidersSectionSchema, {
|
||||||
[ENV_MODEL_PROVIDER_KEY]: envBindings(ProviderConfigSchema, {
|
[ENV_MODEL_PROVIDER_KEY]: envBindings(ProviderConfigSchema, {
|
||||||
apiKey: 'KIMI_MODEL_API_KEY',
|
apiKey: 'KIMI_MODEL_API_KEY',
|
||||||
|
|
@ -159,18 +152,15 @@ registerConfigSection('providers', ProvidersSectionSchema, {
|
||||||
```
|
```
|
||||||
|
|
||||||
Each field is an `EnvBinding` — a string (env var name) or
|
Each field is an `EnvBinding` — a string (env var name) or
|
||||||
`{ env, deprecatedEnv?, parse?, default? }`. IConfig resolves every field by
|
`{ env, parse?, default? }`. IConfig resolves every field by
|
||||||
`env > config.toml > default`, sets it on the effective value, and validates the
|
`env > config.toml > default`, sets it on the effective value, and validates the
|
||||||
section. Empty nested entries (no field resolved) are omitted, so a synthetic
|
section. Empty nested entries (no field resolved) are omitted, so a synthetic
|
||||||
entry like `__kimi_env__` only appears when at least one of its env vars is set.
|
entry like `__kimi_env__` only appears when at least one of its env vars is set.
|
||||||
When `deprecatedEnv` is set and `env` itself is absent or fails `parse`, the
|
|
||||||
deprecated var still supplies the value and a warning diagnostic is reported —
|
|
||||||
use it to rename an env var without breaking existing setups.
|
|
||||||
|
|
||||||
`stripEnv(value, raw?, getEnv?)` removes env-derived fields before `set`/`replace`
|
`stripEnv(value, raw?, getEnv?)` removes env-derived fields before `set`/`replace`
|
||||||
persists, so env overrides never leak into `config.toml`. `raw` is the section's
|
persists, so env overrides never leak into `config.toml`. `raw` is the section's
|
||||||
env-free camelCase base (already `fromToml`-normalized), and `getEnv` reads the
|
env-free camelCase base (already `fromToml`-normalized, so legacy key renames
|
||||||
live env bag. For fields that are **both
|
are honored), and `getEnv` reads the live env bag. For fields that are **both
|
||||||
user-persistable and env-overridable**, register
|
user-persistable and env-overridable**, register
|
||||||
`stripEnv: stripEnvBoundFields(sectionEnvBindings)` (from `#/app/config/config`)
|
`stripEnv: stripEnvBoundFields(sectionEnvBindings)` (from `#/app/config/config`)
|
||||||
— it derives the guard from the same bindings the read path uses: while a
|
— it derives the guard from the same bindings the read path uses: while a
|
||||||
|
|
@ -191,27 +181,21 @@ never write their own env-merge logic.
|
||||||
export const MySectionSchema = z.object({ /* ... */ });
|
export const MySectionSchema = z.object({ /* ... */ });
|
||||||
export type MySection = z.infer<typeof MySectionSchema>;
|
export type MySection = z.infer<typeof MySectionSchema>;
|
||||||
```
|
```
|
||||||
2. Register it at the top level of the same module (import = register):
|
2. In the domain's service constructor, inject `IConfigRegistry` and register:
|
||||||
```ts
|
```ts
|
||||||
// src/<domain>/configSection.ts
|
constructor(@IConfigRegistry registry: IConfigRegistry) {
|
||||||
import { registerConfigSection } from '#/app/config/configSectionContributions';
|
registry.registerSection(MY_SECTION, MySectionSchema, { defaultValue: {} });
|
||||||
|
}
|
||||||
registerConfigSection(MY_SECTION, MySectionSchema, { defaultValue: {} });
|
|
||||||
```
|
```
|
||||||
`ConfigRegistry` drains module-level contributions when it is constructed, so the section exists before any consumer resolves `IConfigService` — no owning Service needs to be constructed first. Make sure `src/index.ts` imports the leaf so the top-level call runs.
|
Pick a service whose scope matches when the config is first needed. Registering from an Agent-scope service is fine — see "Late registration".
|
||||||
3. (Runtime variant) a dynamically loaded unit (e.g. one assembled through `IFeatureManager`) contributes the section as a collection record instead:
|
3. Read it anywhere via `IConfigService`:
|
||||||
```ts
|
|
||||||
this.provide(ConfigSectionContribution, { domain: MY_SECTION, schema: MySectionSchema, options: { defaultValue: {} } });
|
|
||||||
```
|
|
||||||
The `ConfigRegistry` fold registers it incrementally and unregisters it when the unit is retracted (user TOML values survive) — see "Late registration".
|
|
||||||
4. Read it anywhere via `IConfigService`:
|
|
||||||
```ts
|
```ts
|
||||||
constructor(@IConfigService private readonly config: IConfigService) {}
|
constructor(@IConfigService private readonly config: IConfigService) {}
|
||||||
// ...
|
// ...
|
||||||
const value = this.config.get<MySection>(MY_SECTION);
|
const value = this.config.get<MySection>(MY_SECTION);
|
||||||
```
|
```
|
||||||
5. React to edits by subscribing `IConfigService.onDidChange` and filtering on `e.domain === MY_SECTION` (see `FlagService`).
|
4. React to edits by subscribing `IConfigService.onDidChange` and filtering on `e.domain === MY_SECTION` (see `FlagService`).
|
||||||
6. Write it only through `IConfigService.set(domain, patch)` (merge) or `.replace(domain, value)` (wholesale). Never write `config.toml` directly.
|
5. Write it only through `IConfigService.set(domain, patch)` (merge) or `.replace(domain, value)` (wholesale). Never write `config.toml` directly.
|
||||||
|
|
||||||
## Reads vs writes
|
## Reads vs writes
|
||||||
|
|
||||||
|
|
@ -235,11 +219,11 @@ So `configure(...)` never overwrites the local file. Treat `config.toml` as the
|
||||||
|
|
||||||
## Late registration
|
## Late registration
|
||||||
|
|
||||||
`ConfigService` loads in its constructor (first `get(IConfigService)`). Static sections are drained before that, but a runtime-contributed section (a `ConfigSectionContribution` record) can register at any later moment. To keep validation and defaults correct:
|
`ConfigService` loads in its constructor (first `get(IConfigService)`). Domain services that register sections may be constructed later (especially Agent-scope services). To keep validation and defaults correct:
|
||||||
|
|
||||||
- `IConfigRegistry` emits `onDidRegisterSection` whenever a section is registered (and `onDidUnregisterSection` when a runtime record is withdrawn).
|
- `IConfigRegistry` emits `onDidRegisterSection` whenever a section is registered.
|
||||||
- `ConfigService` subscribes and, on registration, re-validates the already-loaded raw value for that domain, applies the default if the raw value is absent, re-runs the env overlay, and fires `onDidChange` if the effective value changed. On unregistration it devalidates the domain — `get(domain)` falls back to the raw value.
|
- `ConfigService` subscribes and, on registration, re-validates the already-loaded raw value for that domain, applies the default if the raw value is absent, re-runs the env overlay, and fires `onDidChange` if the effective value changed.
|
||||||
- Before a section is registered, `get(domain)` returns the raw (transformed, unvalidated) value; consumers that need validated values should read after the section lands, or react to `onDidChange`.
|
- Before a section is registered, `get(domain)` returns the raw (transformed, unvalidated) value; consumers that need validated values should read after the owning service is constructed, or react to `onDidChange`.
|
||||||
|
|
||||||
This means registration order is never a correctness concern — you do not need an eager bootstrap.
|
This means registration order is never a correctness concern — you do not need an eager bootstrap.
|
||||||
|
|
||||||
|
|
@ -247,7 +231,7 @@ This means registration order is never a correctness concern — you do not need
|
||||||
|
|
||||||
`config.toml` stores keys in **snake_case**; in-memory values are **camelCase**. `ConfigService` converts both ways by dispatching to each section's registered transform:
|
`config.toml` stores keys in **snake_case**; in-memory values are **camelCase**. `ConfigService` converts both ways by dispatching to each section's registered transform:
|
||||||
|
|
||||||
- **Read**: `transformTomlData(fileData, registry)` maps each top-level key to a domain and applies that domain's `fromToml` hook (or a plain key-casing pass when none is registered). Owner domains register their own normalization — e.g. provider `oauth`/`env`/`customHeaders`, permission `deny/allow/ask` → `rules`, `experimental` keys preserved verbatim. When a section registers after the initial load, `ConfigService` re-applies its `fromToml` against the preserved snake_case raw value (see "Late registration"), so registration order is never a correctness concern.
|
- **Read**: `transformTomlData(fileData, registry)` maps each top-level key to a domain and applies that domain's `fromToml` hook (or a plain key-casing pass when none is registered). Owner domains register their own normalization — e.g. provider `oauth`/`env`/`customHeaders`, permission `deny/allow/ask` → `rules`, `loop_control.max_steps_per_run` → `maxStepsPerTurn`, `experimental` keys preserved verbatim. When a section registers after the initial load, `ConfigService` re-applies its `fromToml` against the preserved snake_case raw value (see "Late registration"), so registration order is never a correctness concern.
|
||||||
- **Write**: `applySectionToToml(rawSnake, domain, value, registry)` applies the domain's `toToml` hook (or a plain camelCase→snake_case mapping) into a raw clone of the file, preserving unknown top-level keys and unknown sub-fields (lossless round-trip).
|
- **Write**: `applySectionToToml(rawSnake, domain, value, registry)` applies the domain's `toToml` hook (or a plain camelCase→snake_case mapping) into a raw clone of the file, preserving unknown top-level keys and unknown sub-fields (lossless round-trip).
|
||||||
|
|
||||||
`ConfigService` keeps four views:
|
`ConfigService` keeps four views:
|
||||||
|
|
@ -257,30 +241,13 @@ This means registration order is never a correctness concern — you do not need
|
||||||
- `validated` — validated `raw`, env-free; the base every live env re-application starts from, so a degraded or removed env value falls back to the file instead of a stale overlay.
|
- `validated` — validated `raw`, env-free; the base every live env re-application starts from, so a degraded or removed env value falls back to the file instead of a stale overlay.
|
||||||
- `effective` — `validated` plus the env overlay, recomputed on load/set; `get()`/`getAll()` re-apply the overlay on a fresh `validated` copy per read rather than caching it.
|
- `effective` — `validated` plus the env overlay, recomputed on load/set; `get()`/`getAll()` re-apply the overlay on a fresh `validated` copy per read rather than caching it.
|
||||||
|
|
||||||
### Renaming config keys and env vars (deprecations)
|
|
||||||
|
|
||||||
Renames are declared once on the section, never hand-rolled in `fromToml`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
registerSection(MY_SECTION, MySectionSchema, {
|
|
||||||
deprecations: [{ key: 'old_key', replacement: 'new_key' }], // snake_case, on-disk
|
|
||||||
env: envBindings(MySectionSchema, {
|
|
||||||
newKey: { env: 'KIMI_NEW_KEY', deprecatedEnv: 'KIMI_OLD_KEY', parse },
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
- A deprecated TOML key is **ignored** (its value no longer applies — the schema only knows the new key) and reports a warning `ConfigDiagnostic` while present; the file is never rewritten, so the warning is the migration guide. Diagnostics are recomputed on every load/reload and surface to clients via `IConfigService.diagnostics()` and `onDidChangeDiagnostics` (kap-server republishes them as the global `event.config.warning` WS event).
|
|
||||||
- A deprecated env var still **resolves** as a fallback (new var first), with the same warning treatment, and `stripEnvBoundFields` treats it as env-owned for writes.
|
|
||||||
- See `src/agent/loop/configSection.ts` for a worked example (`max_retries_per_step` → `max_attempts_per_step`).
|
|
||||||
|
|
||||||
### `KIMI_MODEL_*` env overlay
|
### `KIMI_MODEL_*` env overlay
|
||||||
|
|
||||||
When `KIMI_MODEL_NAME` is set, the `kosongConfig` wrapper's `kimiModelEnvOverlay` (`src/app/kosongConfig/envOverlay.ts`) injects a reserved model alias (`__kimi_env_model__`) into `effective`, points `defaultModel` at it, and merges the request `modelOverrides`; the reserved provider (`__kimi_env__`) comes from the `providers` section env bindings. The overlay is registered via module-level `registerConfigOverlay` and applied **only to `effective`**, never to `rawSnake`, so it is never persisted. Its `strip` (plus the providers section `stripEnv`) is the final guard so a caller that read `effective` (with the overlay) cannot write the reserved entries or the shell API key back to disk. `config` itself only runs registered overlays — it does not know the `KIMI_MODEL_*` semantics.
|
When `KIMI_MODEL_NAME` is set, the `kosongConfig` wrapper's `kimiModelEnvOverlay` (`src/app/kosongConfig/envOverlay.ts`) injects a reserved model alias (`__kimi_env_model__`) into `effective`, points `defaultModel` at it, and merges the request `modelOverrides`; the reserved provider (`__kimi_env__`) comes from the `providers` section env bindings. The overlay is registered via `IConfigRegistry.registerEffectiveOverlay` and applied **only to `effective`**, never to `rawSnake`, so it is never persisted. Its `strip` (plus the providers section `stripEnv`) is the final guard so a caller that read `effective` (with the overlay) cannot write the reserved entries or the shell API key back to disk. `config` itself only runs registered overlays — it does not know the `KIMI_MODEL_*` semantics.
|
||||||
|
|
||||||
## Owner-owned sections
|
## Owner-owned sections
|
||||||
|
|
||||||
`config` holds no monolithic config schema and no whole-config object. Every section is owned by the domain that consumes it: the schema (and any `fromToml` / `toToml` normalization and `stripEnv`) lives in that domain's `configSection.ts`, and the domain contributes it via module-level `registerConfigSection` (or a runtime `ConfigSectionContribution` record). Cross-section env behavior (e.g. `KIMI_MODEL_*`) lives in an owner-registered `ConfigEffectiveOverlay` (module-level `registerConfigOverlay`). To add a section, follow "Add a config section" above in the owning domain — never add schema or normalization to `config` itself.
|
`config` holds no monolithic config schema and no whole-config object. Every section is owned by the domain that consumes it: the schema (and any `fromToml` / `toToml` normalization and `stripEnv`) lives in that domain's `configSection.ts`, and the domain registers it via `IConfigRegistry.registerSection`. Cross-section env behavior (e.g. `KIMI_MODEL_*`) lives in an owner-registered `ConfigEffectiveOverlay`. To add a section, follow "Add a config section" above in the owning domain — never add schema or normalization to `config` itself.
|
||||||
|
|
||||||
## Ownership map (generated)
|
## Ownership map (generated)
|
||||||
|
|
||||||
|
|
@ -300,13 +267,13 @@ The authoritative, always-current list of registered sections — rendered in th
|
||||||
|
|
||||||
## Red lines (this topic)
|
## Red lines (this topic)
|
||||||
|
|
||||||
- One owner per section: a duplicate static registration throws when `ConfigRegistry` drains it; a conflicting runtime record is logged (`onUnexpectedError`) and the first registration wins.
|
- One owner per section; `registerSection` throws on duplicate domains.
|
||||||
- `config` never imports the domains that consume it — keep section schemas in the owning domain.
|
- `config` never imports the domains that consume it — keep section schemas in the owning domain.
|
||||||
- Config is the **preference registry**: register only values that are preferences, persistable, schema'd, and user/operator-facing. Facts → `IBootstrapService`; session state → Session scope; constants → code.
|
- Config is the **preference registry**: register only values that are preferences, persistable, schema'd, and user/operator-facing. Facts → `IBootstrapService`; session state → Session scope; constants → code.
|
||||||
- Business domains read `config.get(...)` or structured `IBootstrapService` facts; never call `IBootstrapService.getEnv()` directly — only `config` reads the raw env bag to build overlays.
|
- Business domains read `config.get(...)` or structured `IBootstrapService` facts; never call `IBootstrapService.getEnv()` directly — only `config` reads the raw env bag to build overlays.
|
||||||
- Keep `IBootstrapService` domain-agnostic: host invocation arguments (CLI flags, host identity headers, prompt identity) go into `BootstrapInput.args` / `IBootstrapService.args` — never into new per-domain runtime-options services; domain runtime state (cron, flags, model params, …) never goes onto `IBootstrapService` at all. Domain-specific config goes through `registerConfigSection` + `envBindings`, read via `config.get(...)`.
|
- Keep `IBootstrapService` domain-agnostic: host invocation arguments (CLI flags, host identity headers, prompt identity) go into `BootstrapInput.args` / `IBootstrapService.args` — never into new per-domain runtime-options services; domain runtime state (cron, flags, model params, …) never goes onto `IBootstrapService` at all. Domain-specific config goes through `registerSection` + `envBindings`, read via `config.get(...)`.
|
||||||
- Do not pass a whole config bag via options; read each section through `IConfigService`. There is no `KimiConfig` object — config is a registry of owner-owned sections.
|
- Do not pass a whole config bag via options; read each section through `IConfigService`. There is no `KimiConfig` object — config is a registry of owner-owned sections.
|
||||||
- `config.toml` is snake_case on disk, camelCase in memory — never write camelCase keys to disk, and never write to `config.toml` except through `IConfigService.set/replace`.
|
- `config.toml` is snake_case on disk, camelCase in memory — never write camelCase keys to disk, and never write to `config.toml` except through `IConfigService.set/replace`.
|
||||||
- Reading config / calling `configure(...)` / switching model at runtime must not rewrite `config.toml`; runtime state lives in memory and the session wireRecord, not the file.
|
- Reading config / calling `configure(...)` / switching model at runtime must not rewrite `config.toml`; runtime state lives in memory and the session wireRecord, not the file.
|
||||||
- Never persist env overlays (`__kimi_env__` / `__kimi_env_model__` / shell API key / experimental env); overlays live only in `effective` / `Memory`.
|
- Never persist env overlays (`__kimi_env__` / `__kimi_env_model__` / shell API key / experimental env); overlays live only in `effective` / `Memory`.
|
||||||
- Runtime contribution (a `ConfigSectionContribution` record from a unit at any scope) is fine — the late-registration mechanism keeps validation correct; the static channel needs no eager bootstrap (import = register, drained at `ConfigRegistry` construction).
|
- Registering from an Agent-scope service is fine — the late-registration mechanism keeps validation correct; do not add an eager bootstrap.
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,6 @@ The three mechanisms above are also where a domain accepts new behavior without
|
||||||
| Step into an operation in order / veto | a **hook** (`onWill`/`onDid`, `OrderedHookSlot`) | the owning scope |
|
| Step into an operation in order / veto | a **hook** (`onWill`/`onDid`, `OrderedHookSlot`) | the owning scope |
|
||||||
| Swap a backend (File ↔ DB ↔ S3) | a **Store / Storage token** at the byte layer (see persistence.md) | `App` (composition root) |
|
| Swap a backend (File ↔ DB ↔ S3) | a **Store / Storage token** at the byte layer (see persistence.md) | `App` (composition root) |
|
||||||
|
|
||||||
The standard shape of a "registry / catalog the domain queries" row is an L3 contribution point: the target domain owns a `collection<T>` token, contributors call `this.provide(token, record)` from a unit, and a fold service in the target domain injects the `CollectionView` (incremental `onDidChange`; provider death withdraws the record). The four in-repo seams are `ConfigSectionContribution` → `ConfigRegistry`, `AgentToolContribution` → `AgentToolActivationService`, `AgentProfileContribution` → `IAgentProfileRegistry`, and `WireModelContribution` → `WireService` (file-level pointers: `packages/agent-core-v2/AGENTS.md` §Units and contribution points).
|
|
||||||
|
|
||||||
Closed-for-modification means: the domain's own file is not where new scenarios branch. If a new scenario forces an edit here, an extension point is missing or misplaced.
|
Closed-for-modification means: the domain's own file is not where new scenarios branch. If a new scenario forces an edit here, an extension point is missing or misplaced.
|
||||||
|
|
||||||
## 5. Dependency direction
|
## 5. Dependency direction
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,9 @@ Read = `GET`, write = `POST`. `sid` = `session_id`, `aid` = `agent_id`.
|
||||||
|
|
||||||
| resource | action | Service.method | verb |
|
| resource | action | Service.method | verb |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `sessions` | `listRecent` | ISessionIndex.listRecent | GET |
|
| `sessions` | `list` | ISessionIndex.list | GET |
|
||||||
| `sessions` | `get` | ISessionIndex.get | GET |
|
| `sessions` | `get` | ISessionIndex.get | GET |
|
||||||
| `sessions` | `count` | ISessionIndex.count | GET |
|
| `sessions` | `countActive` | ISessionIndex.countActive | GET |
|
||||||
| `workspaces` | `list` | IWorkspaceService.list | GET |
|
| `workspaces` | `list` | IWorkspaceService.list | GET |
|
||||||
| `workspaces` | `get` | IWorkspaceService.get | GET |
|
| `workspaces` | `get` | IWorkspaceService.get | GET |
|
||||||
| `workspaces` | `createOrTouch` | IWorkspaceService.createOrTouch | POST |
|
| `workspaces` | `createOrTouch` | IWorkspaceService.createOrTouch | POST |
|
||||||
|
|
@ -105,7 +105,7 @@ Read = `GET`, write = `POST`. `sid` = `session_id`, `aid` = `agent_id`.
|
||||||
| `tasks` | `list` / `get` / `readOutput` | IBackgroundService.* | GET |
|
| `tasks` | `list` / `get` / `readOutput` | IBackgroundService.* | GET |
|
||||||
| `tasks` | `stop` / `detach` | IBackgroundService.* | POST |
|
| `tasks` | `stop` / `detach` | IBackgroundService.* | POST |
|
||||||
| `usage` | `status` | IUsageService.status | GET |
|
| `usage` | `status` | IUsageService.status | GET |
|
||||||
| `context` | `status` | IAgentTokenCountingService.get | GET |
|
| `context` | `status` | IAgentContextSizeService.get | GET |
|
||||||
| `swarm` | `isActive` | ISwarmService.isActive | GET |
|
| `swarm` | `isActive` | ISwarmService.isActive | GET |
|
||||||
| `swarm` | `enter` / `exit` | ISwarmService.* | POST |
|
| `swarm` | `enter` / `exit` | ISwarmService.* | POST |
|
||||||
| `permission` | `getMode` | IPermissionModeService.mode | GET |
|
| `permission` | `getMode` | IPermissionModeService.mode | GET |
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ Gate not-yet-public features behind `IFlagService.enabled(id)`, per the reposito
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `src/app/flag/flagRegistry.ts` — `IFlagRegistry` token + `FlagDefinitionInput` / `FlagId` / `FlagSurface` types + `registerFlagDefinition` / `getContributedFlags` (import-time contribution queue).
|
- `src/flag/flagRegistry.ts` — `IFlagRegistry` token + `FlagDefinitionInput` / `FlagId` / `FlagSurface` types + `registerFlagDefinition` / `getContributedFlags` (import-time contribution queue).
|
||||||
- `src/app/flag/flagRegistryService.ts` — `FlagRegistryService` impl; in-memory catalog seeded from import-time contributions; App scope.
|
- `src/flag/flagRegistryService.ts` — `FlagRegistryService` impl; in-memory catalog seeded from import-time contributions; App scope.
|
||||||
- `src/app/flag/flag.ts` — `IFlagService` token + resolver types (`ExperimentalFlagMap`, `ExperimentalFlagConfig`, `ExperimentalFlagSource`, `ExperimentalFeatureState`) + `EXPERIMENTAL_SECTION` (`experimental`) / `ExperimentalConfigSchema` (zod) + the module-level `registerConfigSection(EXPERIMENTAL_SECTION, …)` call that owns the section.
|
- `src/flag/flag.ts` — `IFlagService` token + resolver types (`ExperimentalFlagMap`, `ExperimentalFlagConfig`, `ExperimentalFlagSource`, `ExperimentalFeatureState`) + `ExperimentalConfigSchema` / `ExperimentalConfig` (zod).
|
||||||
- `src/app/flag/flagService.ts` — `FlagService` impl + `MASTER_ENV` (`KIMI_CODE_EXPERIMENTAL_FLAG`); reads definitions from `IFlagRegistry` and overrides from `IConfigService`; self-registers at App scope.
|
- `src/flag/flagService.ts` — `FlagService` impl + `MASTER_ENV` (`KIMI_CODE_EXPERIMENTAL_FLAG`) + `EXPERIMENTAL_SECTION` (`experimental`); reads definitions from `IFlagRegistry`; self-registers at App scope.
|
||||||
- `src/app/flag/index.ts` — **removed (no barrel)**; `src/index.ts` imports the `flag` leafs precisely instead (e.g. `import './app/flag/flagService'`).
|
- `src/flag/index.ts` — **removed (no barrel)**; `src/index.ts` imports the `flag` leafs precisely instead (e.g. `import './flag/flagService'`).
|
||||||
- `src/<domain>/flag.ts` — each domain that owns a flag declares it here and calls `registerFlagDefinition` at the module top level (e.g. `src/agent/toolSelect/flag.ts`). The directory already names the domain, so the file is just `flag.ts`.
|
- `src/<domain>/flag.ts` — each domain that owns a flag declares it here and calls `registerFlagDefinition` at the module top level (e.g. `src/agent/toolSelect/flag.ts`). The directory already names the domain, so the file is just `flag.ts`.
|
||||||
|
|
||||||
## Public surface
|
## Public surface
|
||||||
|
|
@ -33,9 +33,9 @@ Highest wins; env is read live on every call (nothing cached):
|
||||||
|
|
||||||
## Config integration
|
## Config integration
|
||||||
|
|
||||||
- The flag domain owns the `[experimental]` section: `src/app/flag/flag.ts` registers it at module load via `registerConfigSection(EXPERIMENTAL_SECTION, ExperimentalConfigSchema, { fromToml, toToml })` (import = register, drained by `ConfigRegistry` at construction); `FlagService` reads overrides from `IConfigService`.
|
- `FlagService` registers the `[experimental]` section into `IConfigRegistry` at construction (`registerSection('experimental', ExperimentalConfigSchema)`) and reads overrides from `IConfigService`.
|
||||||
- It subscribes `IConfigService.onDidChange` and refreshes overrides whenever the `experimental` domain changes, so config edits apply live.
|
- It subscribes `IConfigService.onDidChange` and refreshes overrides whenever the `experimental` domain changes, so config edits apply live.
|
||||||
- `ConfigRegistry.registerSection` throws if a domain is registered twice — `experimental` is owned exclusively by the flag domain.
|
- `IConfigRegistry.registerSection` throws if a domain is registered twice — `experimental` is owned exclusively by `FlagService`.
|
||||||
- `setConfigOverrides(overrides)` is an imperative escape hatch for tests and hosts without an `IConfigService`; hosts on `IConfigService` should set the `[experimental]` section instead.
|
- `setConfigOverrides(overrides)` is an imperative escape hatch for tests and hosts without an `IConfigService`; hosts on `IConfigService` should set the `[experimental]` section instead.
|
||||||
|
|
||||||
Config shape:
|
Config shape:
|
||||||
|
|
@ -54,7 +54,7 @@ Declare the definition in the owning domain's `flag.ts` and call `registerFlagDe
|
||||||
`src/<domain>/flag.ts`:
|
`src/<domain>/flag.ts`:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { type FlagDefinitionInput, registerFlagDefinition } from '#/app/flag/flagRegistry';
|
import { type FlagDefinitionInput, registerFlagDefinition } from '#/flag';
|
||||||
|
|
||||||
export const myFeatureFlag: FlagDefinitionInput = {
|
export const myFeatureFlag: FlagDefinitionInput = {
|
||||||
id: 'my_feature',
|
id: 'my_feature',
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ export const IGreeter: ServiceIdentifier<IGreeter> = createDecorator<IGreeter>('
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// greet/greetService.ts
|
// greet/greetService.ts
|
||||||
import { LifecycleScope } from '#/app/scopes';
|
import { LifecycleScope, registerScopedService, ScopeActivation } from '#/_base/di/scope';
|
||||||
import { registerScopedService, ScopeActivation } from '#/_base/di/scope';
|
|
||||||
import { IGreeter } from './greet';
|
import { IGreeter } from './greet';
|
||||||
|
|
||||||
export class Greeter implements IGreeter {
|
export class Greeter implements IGreeter {
|
||||||
|
|
@ -128,8 +127,7 @@ export class WSBroadcastService extends Disposable implements IWSBroadcastServic
|
||||||
|
|
||||||
- Extend `Disposable`, collect any `IDisposable` with `this._register(d)` (event subscriptions, `toDisposable(fn)`, etc.).
|
- Extend `Disposable`, collect any `IDisposable` with `this._register(d)` (event subscriptions, `toDisposable(fn)`, etc.).
|
||||||
- The container calls `dispose()` automatically when the service is torn down; child resources release in turn.
|
- The container calls `dispose()` automatically when the service is torn down; child resources release in turn.
|
||||||
- Disposal order is deterministic (orient.md): child scopes first; within a scope the Ledger (`src/_base/lifecycle/`) tears entries down in strict reverse registration order, serially — `Disposable` / `DisposableStore` delegate to it.
|
- Disposal order is deterministic (orient.md): child scopes first, then reverse construction order within a scope.
|
||||||
- Extend `Service` (from `#/_base/di/service`) instead when the unit needs capability calls on `this` (`provide` / `effect` / `on` / `get` / `ref`) — e.g. contributing a record to a `collection` token. `Service` extends `Disposable` (so `_register` is unchanged) and adds the two-phase construction protocol: `provide` / `on` / `effect` calls inside the constructor are buffered and flushed by the kernel after `Reflect.construct`; `get` / `ref` throw inside the constructor — dependencies stay constructor parameters. A manually `new`ed `Service` has no capabilities: every capability call throws.
|
|
||||||
|
|
||||||
## §5 Scope activation
|
## §5 Scope activation
|
||||||
|
|
||||||
|
|
@ -162,7 +160,7 @@ registerScopedService(
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`ScopeActivation.OnScopeCreated` is the default fourth argument. Scope creation activates every registration using this mode, after constructing its dependencies. An eager constructor failure no longer fails scope creation: the unit lands in sticky `Failed` — scope creation succeeds, resolving the unit rethrows its error, and an explicit `update()` reloads it (see the bootstrap note below). Use it for ordinary services and for constructor side effects that must exist when the scope becomes ready.
|
`ScopeActivation.OnScopeCreated` is the default fourth argument. Scope creation constructs every registration using this mode, after constructing its dependencies. If any constructor fails, scope creation fails. Use it for ordinary services and for constructor side effects that must exist when the scope becomes ready.
|
||||||
|
|
||||||
`ScopeActivation.OnDemand` stores the descriptor without constructing the service. The first `get()` constructs and caches the real instance directly; later `get()` calls return that same instance. Use it only when construction should wait until the service is actually requested.
|
`ScopeActivation.OnDemand` stores the descriptor without constructing the service. The first `get()` constructs and caches the real instance directly; later `get()` calls return that same instance. Use it only when construction should wait until the service is actually requested.
|
||||||
|
|
||||||
|
|
@ -170,8 +168,6 @@ Both modes use the same dependency graph and reject cycles with `CyclicDependenc
|
||||||
|
|
||||||
The complete registration signature is `registerScopedService(scope, id, ctor, activation = ScopeActivation.OnScopeCreated, domain?)`: activation is the fourth argument and domain is the fifth.
|
The complete registration signature is `registerScopedService(scope, id, ctor, activation = ScopeActivation.OnScopeCreated, domain?)`: activation is the fourth argument and domain is the fifth.
|
||||||
|
|
||||||
**Bootstrap shares the dynamic provide path.** Scope creation (`Scope.createApp` / `Scope.createChild` / `createScopedChildHandle` in `src/_base/di/scope.ts`) submits the scope kind's entire `registerScopedService` batch as ONE cascade transaction via `provideAll`: every token registers before the activation wave runs, so **registration order never matters**, and untracked transitive `createInstance` resolutions succeed inside the batch. A seed occupying a token (the `extra` tuple in `ScopeOptions`) overrides the static registration for that token. `activateScopeServices` is gone — there is no separate static activation path.
|
|
||||||
|
|
||||||
## §6 Using a service inside a plain function (`invokeFunction`)
|
## §6 Using a service inside a plain function (`invokeFunction`)
|
||||||
|
|
||||||
When you do not want a new class and just need a service once, or when you expose a `ServicesAccessor` to the outside:
|
When you do not want a new class and just need a service once, or when you expose a `ServicesAccessor` to the outside:
|
||||||
|
|
@ -202,7 +198,7 @@ class TurnRunner {
|
||||||
const runner = instantiation.createInstance(TurnRunner, 'hello', 1);
|
const runner = instantiation.createInstance(TurnRunner, 'hello', 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
Static params come first (you pass them), service params follow (the container fills them), then `Reflect.construct` builds the instance. This object is **not** placed in any scope's singleton cache — every call is a fresh instance — and it is not tracked as a cascade unit either: `createInstance` products are cascade-exempt leaves that no cascade tears down or rebuilds; their owner disposes them.
|
Static params come first (you pass them), service params follow (the container fills them), then `Reflect.construct` builds the instance. This object is **not** placed in any scope's singleton cache — every call is a fresh instance.
|
||||||
|
|
||||||
> This is why service params must follow static params **for `createInstance`**: the container sorts by the parameter positions recorded via `@IX`. `_serviceBrand` lets the compiler tell the two kinds apart. Scoped services built by `registerScopedService` follow a different convention (`@IX` params first, optional static params after) — see service-authoring.md §constructor-conventions.
|
> This is why service params must follow static params **for `createInstance`**: the container sorts by the parameter positions recorded via `@IX`. `_serviceBrand` lets the compiler tell the two kinds apart. Scoped services built by `registerScopedService` follow a different convention (`@IX` params first, optional static params after) — see service-authoring.md §constructor-conventions.
|
||||||
|
|
||||||
|
|
@ -238,7 +234,7 @@ Key points:
|
||||||
- `instantiation.createChild(collection)` builds a child container whose parent pointer is the current container — so the child resolves upward to `App` services (the visibility rule).
|
- `instantiation.createChild(collection)` builds a child container whose parent pointer is the current container — so the child resolves upward to `App` services (the visibility rule).
|
||||||
- Expose the child to the outside by wrapping it in a `ServicesAccessor` via `invokeFunction` (§6).
|
- Expose the child to the outside by wrapping it in a `ServicesAccessor` via `invokeFunction` (§6).
|
||||||
|
|
||||||
> Higher-level code usually calls `Scope.createChild(kind, id)` (it does the "filter descriptors + build child" for you, then submits the whole batch through `provideAll` as one cascade transaction — see §5). Drop to the manual `ServiceCollection` form only when you need explicit control; to change bindings on an already-created container, prefer `provide` / `unprovide` / `update` over rebuilding a collection. Before the static batch lands, the scope-creation point runs the kernel's `ScopeUnits` fold (`_base/di/scopeUnits.ts` — materializes the recipes contributed to `ScopeUnits(kind)` as per-scope units) and then the `ScopeOptions.assemble` hook — the session domain uses the hook to construct its seed-adapter units (`session/sessionSeed/sessionSeedAdapters.ts`) so their provided tokens exist before the session services activate.
|
> Higher-level code usually calls `Scope.createChild(kind, id)` (it does the "filter descriptors + build child" for you). Drop to the manual `ServiceCollection` form only when you need explicit control.
|
||||||
|
|
||||||
## §9 Cyclic dependencies (forbidden — refactor)
|
## §9 Cyclic dependencies (forbidden — refactor)
|
||||||
|
|
||||||
|
|
@ -280,8 +276,6 @@ Both `ScopeActivation.OnScopeCreated` and `ScopeActivation.OnDemand` construct t
|
||||||
| `Disposable` / `DisposableStore` / `IDisposable` | §4 | resource management and disposal |
|
| `Disposable` / `DisposableStore` / `IDisposable` | §4 | resource management and disposal |
|
||||||
| `Scope` / `LifecycleScope` | §3, §8 | the lifetime tree |
|
| `Scope` / `LifecycleScope` | §3, §8 | the lifetime tree |
|
||||||
| `ScopeActivation` | §3, §5 | choose scope-created or first-`get()` construction |
|
| `ScopeActivation` | §3, §5 | choose scope-created or first-`get()` construction |
|
||||||
| `Service` (`_base/di/service`) | §4 | unit base class — `this.provide/effect/on/get/ref` capabilities, two-phase construction |
|
|
||||||
| `collection<T>(name)` / `CollectionView<T>` (`_base/di/collection`) | §4 | contribution-point token + the fold's live view (provider death withdraws the record) |
|
|
||||||
| `SyncDescriptor` | (tests / low-level) | package a constructor + static args into a pending descriptor |
|
| `SyncDescriptor` | (tests / low-level) | package a constructor + static args into a pending descriptor |
|
||||||
|
|
||||||
> Legacy export (not used in v2, just recognize it): `refineServiceDecorator` is a VS Code leftover DI helper. v2 src/test has zero references; always use `registerScopedService`.
|
> Legacy export (not used in v2, just recognize it): `refineServiceDecorator` is a VS Code leftover DI helper. v2 src/test has zero references; always use `registerScopedService`.
|
||||||
|
|
|
||||||
|
|
@ -17,26 +17,24 @@ Classes talk only to interfaces and never care how an implementation is construc
|
||||||
Lifetimes form a tree, from longest to shortest:
|
Lifetimes form a tree, from longest to shortest:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
App process-wide, single global instance
|
App (0) process-wide, single global instance
|
||||||
└── Workspace one workspace handler (a materialized workspace root)
|
└── Workspace (1) one workspace handler (a materialized workspace root)
|
||||||
└── Session one session
|
└── Session (2) one session
|
||||||
└── Agent one agent
|
└── Agent (3) one agent
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/app/scopes.ts — the business layer declares the tiers and their order;
|
|
||||||
// the DI kernel only knows opaque string kinds plus the declared topology.
|
|
||||||
export enum LifecycleScope {
|
export enum LifecycleScope {
|
||||||
App = 'app',
|
App = 0,
|
||||||
Workspace = 'workspace',
|
Workspace = 1,
|
||||||
Session = 'session',
|
Session = 2,
|
||||||
Agent = 'agent',
|
Agent = 3,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- Later in the topology = shorter life = closer to a leaf.
|
- A larger number = shorter life = closer to a leaf.
|
||||||
- "Singleton" means **one per scope**: `ILogService` is global once; each `Session` scope has its own `ISessionMetadata`.
|
- "Singleton" means **one per scope**: `ILogService` is global once; each `Session` scope has its own `ISessionMetadata`.
|
||||||
- `kind` must advance along the declared topology in the parent→child direction.
|
- `kind` strictly increases along the parent→child direction.
|
||||||
|
|
||||||
### Visibility rule
|
### Visibility rule
|
||||||
|
|
||||||
|
|
@ -49,15 +47,7 @@ A child scope sees its ancestors; a parent never sees its children. Resolution w
|
||||||
|
|
||||||
### Disposal order
|
### Disposal order
|
||||||
|
|
||||||
Deterministic: **child scopes die first; within one scope, teardown runs in strict reverse registration order, one entry at a time.** The mechanism is the Ledger (`src/_base/lifecycle/`): ordered effect bookkeeping, dual-track (sync + async disposers), serial reverse-order teardown (never parallel), with the teardown reason (`'scope-close' | 'cascade' | 'unload'`) passed through to every disposer. `Disposable` / `DisposableStore` (`src/_base/di/lifecycle.ts`) delegate to it — "reverse construction order" is a Ledger property, not a container convention. Business code declares which tier it lives in and never disposes by hand.
|
Deterministic: **child scopes die first; within one scope, instances dispose in reverse construction order** (last constructed, first disposed). Business code declares which tier it lives in and never disposes by hand.
|
||||||
|
|
||||||
## Dynamic DI: units and cascades
|
|
||||||
|
|
||||||
Registration is not the end of the story. Every unit a container tracks — static registrations and runtime `provide`s alike — lives in a small state machine owned by the scope's cascade engine (`src/_base/di/cascadeEngine.ts`, one per scope container, orchestrating tree-wide). Vocabulary you will meet in errors, tests, and the debug surface:
|
|
||||||
|
|
||||||
- **Unit states** — `Pending → Activating → Active`, plus `Unloading` during teardown and a sticky `Failed`. A construction failure parks the unit in `Failed` with no auto-retry: resolving it rethrows its error; an explicit `update()` reloads it.
|
|
||||||
- **Waiting area** — a unit whose declared dependencies are missing sits `Pending` and auto-activates when they arrive, including cross-scope wake-up when an ancestor gains the token. An `ondemand` unit counts as available: consumers pull it transitively at materialization.
|
|
||||||
- **Cascade transaction** — every `provide` / `unprovide` / `update` runs as one tree-wide transaction: contagion set from the persistent dependency graph (instance edges, child→parent across scopes) → abort hook → global reverse-topo teardown → apply the change → waiting-area recheck fixpoint → history ring. Static bootstrap shares this path: scope creation submits the kind's whole registration batch as one `provideAll`, so registration order never matters.
|
|
||||||
|
|
||||||
## Import boundaries
|
## Import boundaries
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,7 @@ export const IAgentPromptService: ServiceIdentifier<IAgentPromptService> =
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// promptService.ts — impl delegates to the native v2 Service
|
// promptService.ts — impl delegates to the native v2 Service
|
||||||
import { LifecycleScope } from '#/app/scopes';
|
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
|
||||||
|
|
||||||
constructor(@IAgentPromptService private readonly prompt: IAgentPromptService /*, ... */) {}
|
constructor(@IAgentPromptService private readonly prompt: IAgentPromptService /*, ... */) {}
|
||||||
// submit() builds v2-native input, calls the native Service, projects the result
|
// submit() builds v2-native input, calls the native Service, projects the result
|
||||||
|
|
|
||||||
|
|
@ -137,8 +137,7 @@ Holds the concrete class(es) and the top-level registration. A typical impl:
|
||||||
* … collaborators as roles ("logs through `log`") … Bound at App scope.
|
* … collaborators as roles ("logs through `log`") … Bound at App scope.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LifecycleScope } from '#/app/scopes';
|
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
|
||||||
import { ILogService } from '#/log';
|
import { ILogService } from '#/log';
|
||||||
|
|
||||||
import { type Greeting, IGreeter } from './greet';
|
import { type Greeting, IGreeter } from './greet';
|
||||||
|
|
@ -164,8 +163,6 @@ What belongs here:
|
||||||
- **Helper classes / functions** used only by this impl (e.g. a built-in writer, an `extractError` helper) — co-located in the same file.
|
- **Helper classes / functions** used only by this impl (e.g. a built-in writer, an `extractError` helper) — co-located in the same file.
|
||||||
- **Top-level `registerScopedService(...)`** — one per Service the file owns; importing the impl file runs the registration.
|
- **Top-level `registerScopedService(...)`** — one per Service the file owns; importing the impl file runs the registration.
|
||||||
|
|
||||||
Base class: extend `Service` (from `#/_base/di/service`) when the unit needs capability calls on `this` — `provide` / `effect` / `on` / `get` / `ref` (e.g. contributing a record to a `collection` token). `Service` extends `Disposable`, so `_register` keeps working; constructor-time `provide` / `on` / `effect` calls are buffered and flushed by the kernel after construction, while `get` / `ref` throw inside the constructor (dependencies stay constructor parameters). Otherwise extend `Disposable` — both are full DI units; a service whose own members collide with the `Service` vocabulary (`name` / `state` / `config` / `get`) must stay on `Disposable` (leave a NOTE comment saying so).
|
|
||||||
|
|
||||||
## Constructor conventions
|
## Constructor conventions
|
||||||
|
|
||||||
- Declare every dependency with `@IX` on a constructor parameter.
|
- Declare every dependency with `@IX` on a constructor parameter.
|
||||||
|
|
@ -320,8 +317,7 @@ export const IGreeter: ServiceIdentifier<IGreeter> = createDecorator<IGreeter>('
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// greet/greetService.ts
|
// greet/greetService.ts
|
||||||
import { LifecycleScope } from '#/app/scopes';
|
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
|
||||||
import { type Greeting, IGreeter } from './greet';
|
import { type Greeting, IGreeter } from './greet';
|
||||||
|
|
||||||
export class Greeter implements IGreeter {
|
export class Greeter implements IGreeter {
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,8 @@ Reach for this only when *which layer a service lives in* is itself the thing be
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { beforeEach, describe, expect, it } from 'vitest';
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
import { LifecycleScope } from '#/app/scopes';
|
|
||||||
import {
|
import {
|
||||||
|
LifecycleScope,
|
||||||
ScopeActivation,
|
ScopeActivation,
|
||||||
_clearScopedRegistryForTests,
|
_clearScopedRegistryForTests,
|
||||||
registerScopedService,
|
registerScopedService,
|
||||||
|
|
@ -224,14 +224,6 @@ Do **not** add the system-under-test itself to the store. `TestInstantiationServ
|
||||||
|
|
||||||
Scope-host tests call `host.dispose()` in `afterEach` (or at the end of the `it`). Route teardown through the store so ordering is deterministic and nothing leaks when a test fails mid-way.
|
Scope-host tests call `host.dispose()` in `afterEach` (or at the end of the `it`). Route teardown through the store so ordering is deterministic and nothing leaks when a test fails mid-way.
|
||||||
|
|
||||||
## Cascade: asserting unit state
|
|
||||||
|
|
||||||
The cascade engine's test vocabulary lives in two files: `test/_base/di/cascade.test.ts` (the mechanism matrix, including cross-scope orchestration) and `test/_base/di/provide.test.ts` (provide/unprovide semantics).
|
|
||||||
|
|
||||||
- **Assert unit states, not internals.** Every container exposes its engine as `container.cascade`: `stateOf(IX)` → `'Pending' | 'Activating' | 'Active' | 'Unloading' | 'Failed'`; `failureOf(IX)` → the sticky error of a `Failed` unit; `pendingSnapshot()` → the waiting-area contents.
|
|
||||||
- **The waiting area parks units with unregistered dependencies** — a unit whose declared deps are missing stays `Pending` (no throw), so a test must seed the full dependency chain. Example: a root→agent chain with no session container must seed the session-scope dependency explicitly — `ix.set(ISessionStateService, new SessionStateService())` in `test/session/agentLifecycle/agentLifecycle.test.ts` — or the dependent unit never activates.
|
|
||||||
- **Eager activation failure is sticky `Failed`, not a scope-creation throw.** Assert state + rethrow: `expect(ix.cascade.stateOf(IX)).toBe('Failed')`, then `expect(() => ix.invokeFunction((a) => a.get(IX))).toThrow(…)`. Do not expect scope/host creation itself to throw for a failing eager constructor.
|
|
||||||
|
|
||||||
## Assertions and naming
|
## Assertions and naming
|
||||||
|
|
||||||
- One behavior per `it`; describe observable behavior (`child shadows parent registration`), not implementation (`calls _getOrCreateServiceInstance`).
|
- One behavior per `it`; describe observable behavior (`child shadows parent registration`), not implementation (`calls _getOrCreateServiceInstance`).
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,17 @@ All other `@moonshot-ai/*` packages are treated as internal packages, including
|
||||||
|
|
||||||
`@moonshot-ai/pi-tui` is a special internal package: it is a private fork (`private: true`) that is never published, but it keeps its own changelog through changesets. It is an exception to Core Rule 4 — see the dedicated section below.
|
`@moonshot-ai/pi-tui` is a special internal package: it is a private fork (`private: true`) that is never published, but it keeps its own changelog through changesets. It is an exception to Core Rule 4 — see the dedicated section below.
|
||||||
|
|
||||||
Only the CLI changelog gets a curated, user-facing presentation (the docs-site changelog sync). The SDK and other internal package changelogs are raw changesets output kept for version history — nobody curates them, so write those entries honestly and technically; their wording does not need to suit end users.
|
|
||||||
|
|
||||||
## Core Rules
|
## Core Rules
|
||||||
|
|
||||||
1. **Inspect the actual changes first.** Use `git status` / `git diff --name-only` to identify which packages were actually changed.
|
1. **Inspect the actual changes first.** Use `git status` / `git diff --name-only` to identify which packages were actually changed.
|
||||||
2. **List packages that changesets can release.** If a changed package is ignored in `.changeset/config.json`, do not put that ignored package in frontmatter together with a non-ignored package; changesets rejects mixed ignored/non-ignored frontmatter.
|
2. **List packages that changesets can release.** If a changed package is ignored in `.changeset/config.json`, do not put that ignored package in frontmatter together with a non-ignored package; changesets rejects mixed ignored/non-ignored frontmatter.
|
||||||
3. **Map ignored internal changes to the affected released package.** If an ignored internal package changes CLI output or behavior, list `@moonshot-ai/kimi-code` and describe the actual user-visible or release-artifact change in the changelog text.
|
3. **Map ignored internal changes to the affected released package.** If an ignored internal package changes CLI output or behavior, list `@moonshot-ai/kimi-code` and describe the actual user-visible or release-artifact change in the changelog text.
|
||||||
4. **Internal package source changes that enter the CLI bundle must manually list the CLI — when they get a changeset at all.** `@moonshot-ai/kimi-code` inline-bundles `@moonshot-ai/*` source, but those internal packages are devDependencies from the CLI's perspective, so changesets will not automatically propagate bumps. If a change enters the CLI output and is user-perceivable, list `@moonshot-ai/kimi-code`. See rule 6 for when to skip the changeset entirely.
|
4. **Internal package source changes that enter the CLI bundle must manually list the CLI — when they get a changeset at all.** `@moonshot-ai/kimi-code` inline-bundles `@moonshot-ai/*` source, but those internal packages are devDependencies from the CLI's perspective, so changesets will not automatically propagate bumps. If a change enters the CLI output and is user-perceivable, list `@moonshot-ai/kimi-code`. See rule 6 for when to skip the changeset entirely.
|
||||||
|
- **Web app (`@moonshot-ai/kimi-web`) changes always enter the CLI bundle.** `@moonshot-ai/kimi-web` is ignored by changesets (see `.changeset/config.json`) and cannot be mixed with `@moonshot-ai/kimi-code` in one changeset frontmatter. Describe the web change in the changelog text, but list `@moonshot-ai/kimi-code` so the CLI release carries the bundled `dist-web` output.
|
||||||
5. **Docs-only and tests-only changes usually do not need a changeset.** README, internal docs, and `test/` changes that do not enter package output do not trigger a CLI bump.
|
5. **Docs-only and tests-only changes usually do not need a changeset.** README, internal docs, and `test/` changes that do not enter package output do not trigger a CLI bump.
|
||||||
6. **Skip changes users cannot perceive — write no changeset at all.** The CLI changelog is user-facing; a changeset is a changelog entry, not a shipping gate. Internal changes merged to `main` still ship in the next release triggered by any user-facing changeset, so skipping the changeset loses nothing. Do not write changesets for:
|
6. **Skip changes users cannot perceive — write no changeset at all.** The CLI changelog is user-facing; a changeset is a changelog entry, not a shipping gate. Internal changes merged to `main` still ship in the next release triggered by any user-facing changeset, so skipping the changeset loses nothing. Do not write changesets for:
|
||||||
- `agent-core-v2` internal architecture: new services, refactors, config-persistence or journal/wire mechanisms.
|
- `agent-core-v2` internal architecture: new services, refactors, config-persistence or journal/wire mechanisms.
|
||||||
- `kap-server` WebSocket / REST protocol changes consumed only by the bundled web UI, kimi-inspect, or other dev tooling (new endpoints, subscribe protocols, stream baselines).
|
- `kap-server` WebSocket / REST protocol changes consumed only by the bundled web UI, kimi-inspect, or other dev tooling (new endpoints, subscribe protocols, stream baselines). A web-facing feature they back gets its own `web:` entry instead.
|
||||||
- Behavior that only takes effect on the experimental engine (e.g. experimental `kimi -p`), unless it exposes documented user configuration such as a `config.toml` section or env vars that also work on a shipped surface (TUI or `kimi web`).
|
- Behavior that only takes effect on the experimental engine (e.g. experimental `kimi -p`), unless it exposes documented user configuration such as a `config.toml` section or env vars that also work on a shipped surface (TUI or `kimi web`).
|
||||||
- When unsure whether users can perceive a change, ask before writing.
|
- When unsure whether users can perceive a change, ask before writing.
|
||||||
7. `@moonshot-ai/vis` / `vis-server` / `vis-web` are ignored by changesets and should not be handled. `@moonshot-ai/kimi-inspect` (a private dev app that never ships) is likewise ignored and must never appear in a changeset frontmatter.
|
7. `@moonshot-ai/vis` / `vis-server` / `vis-web` are ignored by changesets and should not be handled. `@moonshot-ai/kimi-inspect` (a private dev app that never ships) is likewise ignored and must never appear in a changeset frontmatter.
|
||||||
|
|
@ -154,6 +153,36 @@ Only SDK source changed, and the CLI does not use it:
|
||||||
Clarify session status typing for internal SDK callers.
|
Clarify session status typing for internal SDK callers.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Web app changes
|
||||||
|
|
||||||
|
`@moonshot-ai/kimi-web` is ignored by changesets and must **never** appear in a changeset frontmatter. Because the web app is bundled into the CLI release artifact, any web change that ships must list `@moonshot-ai/kimi-code` instead and describe the actual web-facing change in the text.
|
||||||
|
|
||||||
|
- Prefix the changelog entry text with `web: ` (for example `web: Fix the chat not scrolling to the bottom after sending a message.`) so the synced docs changelog can mark web UI entries. Apply this whenever the change is to the web project (`@moonshot-ai/kimi-web`).
|
||||||
|
- If a PR ships a web UI feature backed by server API changes that exist solely to power that feature, prefer a single `web:` entry describing what the web user gets. Do not add a separate server-API changeset unless the API has independent user value (a public endpoint that SDK or server consumers call directly). The docs changelog sync also deduplicates this pattern, but catching it here avoids duplicate changesets.
|
||||||
|
- Do not enumerate every micro-tweak; keep it to one sentence that captures what the web user gets.
|
||||||
|
|
||||||
|
Web-only fix:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
"@moonshot-ai/kimi-code": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
web: Fix the chat not scrolling to the bottom after sending a message.
|
||||||
|
```
|
||||||
|
|
||||||
|
Web UI plus backing server APIs in the same PR (prefer a single `web:` entry; the API is plumbing):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
"@moonshot-ai/kimi-code": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
web: Add the server-hosted web UI, including chat layout and session list behaviors.
|
||||||
|
```
|
||||||
|
|
||||||
|
Split into two changesets only when the API has independent user value on its own (for example, a public endpoint SDK consumers call directly). In that case add the web entry above plus a separate one such as `Add a public REST API to list archived sessions for SDK consumers.`
|
||||||
|
|
||||||
## `@moonshot-ai/pi-tui` changes
|
## `@moonshot-ai/pi-tui` changes
|
||||||
|
|
||||||
`@moonshot-ai/pi-tui` is a vendored fork that lives in `packages/pi-tui`. It is `private: true` and is never published, but it is **not** ignored by changesets: changesets versions it and writes `packages/pi-tui/CHANGELOG.md` so the fork keeps its own history. Because it is bundled into the CLI like other internal packages, it is an exception to Core Rule 4 — do **not** list `@moonshot-ai/kimi-code` for a change that only touches pi-tui.
|
`@moonshot-ai/pi-tui` is a vendored fork that lives in `packages/pi-tui`. It is `private: true` and is never published, but it is **not** ignored by changesets: changesets versions it and writes `packages/pi-tui/CHANGELOG.md` so the fork keeps its own history. Because it is bundled into the CLI like other internal packages, it is an exception to Core Rule 4 — do **not** list `@moonshot-ai/kimi-code` for a change that only touches pi-tui.
|
||||||
|
|
@ -204,3 +233,5 @@ Fix the transcript jumping to the top when scrolling up through history during s
|
||||||
- The CLI wording mentions internal package names, class names, or PR numbers.
|
- The CLI wording mentions internal package names, class names, or PR numbers.
|
||||||
- The entry includes real internal identifiers instead of neutral placeholders.
|
- The entry includes real internal identifiers instead of neutral placeholders.
|
||||||
- A change that only touches `@moonshot-ai/pi-tui` lists `@moonshot-ai/kimi-code` instead of `@moonshot-ai/pi-tui`, or mixes both packages in one frontmatter.
|
- A change that only touches `@moonshot-ai/pi-tui` lists `@moonshot-ai/kimi-code` instead of `@moonshot-ai/pi-tui`, or mixes both packages in one frontmatter.
|
||||||
|
- A web app change entry is missing the `web: ` prefix.
|
||||||
|
- A server/API changeset exists only to back a web feature that a `web:` changeset already describes (use one `web:` entry instead, unless the API has independent user value).
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,8 @@ If the CLI changelog is not in the diff (for example an SDK-only release), stop
|
||||||
|
|
||||||
Process the version block exactly as `sync-changelog` does for the docs site, but only in memory:
|
Process the version block exactly as `sync-changelog` does for the docs site, but only in memory:
|
||||||
|
|
||||||
- **Strip** (`sync-changelog` step 3): drop the H1, the `### Patch Changes` / `### Minor Changes` / `### Major Changes` subheadings, PR links, and commit-hash links; keep only each entry's body text. The `Thanks [@user](...)!` credit (including the multi-author form) must be removed every time. Within each entry, drop SDK-only and provider-internal sentences (SDK capability mapping / API exposure, provider wire-format mechanics, internal XML markers, hook/event payload mechanics such as what an event reports or carries) and keep only the user-facing effect and required constraints.
|
- **Strip** (`sync-changelog` step 3): drop the H1, the `### Patch Changes` / `### Minor Changes` / `### Major Changes` subheadings, PR links, and commit-hash links; keep only each entry's body text. The `Thanks [@user](...)!` credit (including the multi-author form) must be removed every time. Within each entry, drop SDK-only and provider-internal sentences (SDK capability mapping / API exposure, provider wire-format mechanics, internal XML markers) and keep only the user-facing effect and required constraints.
|
||||||
- **Merge and deduplicate** (`sync-changelog` step 4): merge micro-tweaks to the same surface into one higher-level entry; when three or more fixes target the same UI area or the same class of problem, merge them into one higher-level fix entry (do not merge broad or genuinely distinct fixes); and drop a server/API entry that only backs a web feature already listed.
|
- **Merge and deduplicate** (`sync-changelog` step 4): merge micro-tweaks to the same surface into one higher-level entry; when three or more fixes target the same UI area or the same class of problem, merge them into one higher-level fix entry (do not merge broad or genuinely distinct fixes); and drop a server/API entry that only backs a web feature already listed.
|
||||||
- **Collapse low-signal entries** (`sync-changelog` step 4): keep standalone only entries that pass both gates — the reader-action test (the reader must do or re-evaluate something) and the channel test (the product cannot push it into the user's path: hidden controls, habit invalidations, capabilities users would not know to seek — a control merely sitting in the UI is not surfacing, users do not explore). Polish keeps only must-react items; experiences the product shows at the moment of need (recovery cards, post-install guidance) fold. Fixes keep only behavior-change entries (readers must update a habit, config, or workaround); loud failures fold (the fix itself notifies the victim), and silent past damage folds too — the changelog does not repair the past, and a notice that names no locatable instance and no realistic action is noise, not diligence. Section sizes follow density defaults (about 2 polish, 3 fixes) that yield to genuinely qualifying entries — flag the overflow for the reviewer instead of folding to hit the number. Fold everything else into one catch-all line placed last under 修复 — `修复了一些已知问题。` (or `修复了一些已知问题,并做了若干细节优化。` when non-fix entries were also collapsed; when nothing folded is a fix, place it under 优化 instead as `做了若干细节优化和内部改进。`), followed by a separate pointer sentence: `更详细的变更记录见 [GitHub](https://github.com/MoonshotAI/kimi-code/blob/main/apps/kimi-code/CHANGELOG.md)。` (file link, no version anchor; before the release PR merges, the target does not yet contain this version's block — expected for a preview).
|
|
||||||
- **Classify** (`sync-changelog` step 4): bucket into Features / Bug Fixes / Polish / Refactors / Other; order within each section by reader value (in Polish, user-visible improvements before protocol/internal adjustments).
|
- **Classify** (`sync-changelog` step 4): bucket into Features / Bug Fixes / Polish / Refactors / Other; order within each section by reader value (in Polish, user-visible improvements before protocol/internal adjustments).
|
||||||
- **Translate** (`sync-changelog` step 6): translate entry bodies to Chinese; keep one sentence per entry with a parallel rhythm within a section; section headings become 新功能 / 修复 / 优化 / 重构 / 其他.
|
- **Translate** (`sync-changelog` step 6): translate entry bodies to Chinese; keep one sentence per entry with a parallel rhythm within a section; section headings become 新功能 / 修复 / 优化 / 重构 / 其他.
|
||||||
|
|
||||||
|
|
@ -49,10 +48,6 @@ If an upstream entry is not in English, flag it and stop (changeset entries must
|
||||||
|
|
||||||
Print the preview directly. Use `<version>(预览)` as the heading because the version is not released yet. Write `无` for empty sections. Do not write any file.
|
Print the preview directly. Use `<version>(预览)` as the heading because the version is not released yet. Write `无` for empty sections. Do not write any file.
|
||||||
|
|
||||||
After the preview block, append a reviewer-only section titled `### 审稿参考(不进入文档)`: list every entry folded into the catch-all (short English title, one line each), note any section that exceeds the density defaults, and flag borderline calls for the reviewer to confirm. This breakdown is how reviewers see what was folded — before merge, the catch-all pointer's target does not yet contain the version's block. Never write this section into the docs pages.
|
|
||||||
|
|
||||||
The preview is pasted into chat tools (for example Lark), where relative docs links do not resolve. Rewrite every docs link to its absolute published URL: map `../<path>.md[#anchor]` to `https://moonshotai.github.io/kimi-code/zh/<path>.html[#anchor]` — for example `../configuration/config-files.md#loop-control` → `https://moonshotai.github.io/kimi-code/zh/configuration/config-files.html#loop-control`. Never emit raw relative paths, and never wrap a link in backticks; code-style the link text inside the brackets instead ([`loop_control`](...)).
|
|
||||||
|
|
||||||
```
|
```
|
||||||
发版 PR: <url>
|
发版 PR: <url>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,11 +115,18 @@ Drop SDK-only and provider-internal detail. This changelog serves `@moonshot-ai/
|
||||||
|
|
||||||
- Drop sentences about how the SDK maps a capability, builds model aliases, or exposes a flag through an API such as `getExperimentalFeatures()` — that belongs in the SDK changelog, not here.
|
- Drop sentences about how the SDK maps a capability, builds model aliases, or exposes a flag through an API such as `getExperimentalFeatures()` — that belongs in the SDK changelog, not here.
|
||||||
- Drop provider / wire-format implementation mechanics (XML markers like `<tools_added>`, protocol field explanations, "the wire protocol is unchanged", cache-hit mechanics) unless they are the behavior a user perceives.
|
- Drop provider / wire-format implementation mechanics (XML markers like `<tools_added>`, protocol field explanations, "the wire protocol is unchanged", cache-hit mechanics) unless they are the behavior a user perceives.
|
||||||
- Drop hook/event payload mechanics — clauses about what extra fields an event payload carries or what an event reports in a specific case (for example "enrich hook payloads with the session title and client type", "`SessionEnd` reports `archive` when a session is archived"). Keep the new events or capability itself and how to configure it.
|
|
||||||
- Keep the user-facing effect and any constraints users must follow (for example "question texts must be unique").
|
- Keep the user-facing effect and any constraints users must follow (for example "question texts must be unique").
|
||||||
|
|
||||||
Do not change facts or drop a real user-facing behavior — only trim the internal-only scaffolding. For over-long, internal-heavy entries, this trim applies on the English page too, not only in translation.
|
Do not change facts or drop a real user-facing behavior — only trim the internal-only scaffolding. For over-long, internal-heavy entries, this trim applies on the English page too, not only in translation.
|
||||||
|
|
||||||
|
Web UI prefix: if the entry is a web UI change, prefix the body text with `web: ` so readers can tell it affects the web UI:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
- web: <body text>
|
||||||
|
```
|
||||||
|
|
||||||
|
An entry counts as a web UI change when its upstream commit touches `apps/kimi-web/`. Check with `git show --name-only <hash>` (the commit hash is the one stripped above). `gen-changesets` writes this prefix for web changes, so it is usually already present in upstream — preserve it when it is there, and add it when a web entry lacks it. When a commit touches both web and non-web code, use `web:` only if the user-facing change described by the entry is in the web UI. Keep the `web:` prefix on the Chinese page too — it is a scope marker, not translated text.
|
||||||
|
|
||||||
Upstream language rule: `gen-changesets` requires changelog entries to be English. If the upstream CLI changelog contains a non-English entry, stop and report it to the user. Do not silently rewrite it while syncing docs.
|
Upstream language rule: `gen-changesets` requires changelog entries to be English. If the upstream CLI changelog contains a non-English entry, stop and report it to the user. Do not silently rewrite it while syncing docs.
|
||||||
|
|
||||||
Public-text rule: do not copy real internal endpoints, key names, account names, or service names into docs changelogs. Replace examples with neutral placeholders such as `example.com`, `example.test`, or `YOUR_API_KEY` while preserving the user-visible meaning.
|
Public-text rule: do not copy real internal endpoints, key names, account names, or service names into docs changelogs. Replace examples with neutral placeholders such as `example.com`, `example.test`, or `YOUR_API_KEY` while preserving the user-visible meaning.
|
||||||
|
|
@ -128,21 +135,13 @@ Public-text rule: do not copy real internal endpoints, key names, account names,
|
||||||
|
|
||||||
Before classifying, merge related entries and drop redundant ones from the user-facing changelog:
|
Before classifying, merge related entries and drop redundant ones from the user-facing changelog:
|
||||||
|
|
||||||
- **Curate for end users: collapse low-signal entries into one catch-all line.** The docs changelog is the only curated, user-facing outlet; the full entry list always remains in the upstream package changelog, so hiding detail here loses nothing. Apply two gates to every candidate entry. Gate 1, the reader-action test: **after reading this, is there something the reader must do, or something they must re-evaluate?** Gate 2, the channel test: **is the changelog the only channel that can deliver this?** The changelog is the channel of last resort — when the product itself surfaces the information in context, at the moment of need, to exactly the affected users, the entry is redundant no matter how real the improvement is. "Surfaced" means pushed into the user's path, not merely present on screen: an event-triggered card, prompt, or post-install screen forces the encounter, while a toggle, menu item, command, or settings page only waits to be found. Users do not explore — a capability that lives only in ambient UI is effectively undiscoverable, so the changelog must announce it. What in-product surfacing cannot deliver: hidden controls (env vars, config keys, opt-out flags nobody would find unprompted), invalidations of existing habits or expectations (in-product discovery comes as confusion), and capabilities users would not know to seek. An entry that fails either gate folds. Anchor both gates to the changelog's reader, never to the bug's victim: someone who hit a loud failure does not need the changelog to confirm the fix — the product working again is the notification — and a reader who never hit it gets nothing from the entry.
|
- **Merge micro-tweaks to the same surface.** Collapse several small tweaks to the same UI area or feature into one concise entry at the higher level. For example, "change the composer's default height" and "change the composer's default font" merge into "Polish the composer's default styling." Use the most specific common ancestor (composer, settings page, tool card, and so on). Classify the merged entry by its combined effect, and keep the `web:` prefix if the combined change is still web-facing.
|
||||||
- `Features`: keep when users would try it or must react to it — new capabilities create demand readers did not know to seek. Collapse only behavior that takes effect solely behind an experimental flag.
|
|
||||||
- `Polish`: keep only must-react items — a notification users may want to turn off, a behavior change to a command they already use, a default flip with an opt-out. Fold improved experiences the product surfaces in context (recovery cards, post-install guidance, progress or status displays): they are discovered at the moment of need, and pre-reading about them helps nobody. Also fold subtle or transient tweaks (status wording, spacing, animations) and internal-behavior adjustments — nobody acts on them.
|
|
||||||
- `Bug Fixes`: keep only **behavior-change** fixes — the fix changes how something works going forward, so readers must update a habit, a config, or a widely-adopted workaround. Everything else folds, for one of two opposite reasons. Loud failures (crashes, refusals, interrupted runs): the fix itself notifies whoever was hit — announcement value falls as bug visibility rises. Silent past damage (dropped data, wrong results the user never noticed): the changelog cannot repair the past, and in this product the notice names no locatable instance and no realistic action — users cannot enumerate which old sessions were affected, and they do not audit finished sessions; a "some past outputs may be wrong" line is anxiety without an outlet, not diligence. The rare exception is a retrospective notice with a concrete, locatable action (for example rotating a token after a credential-handling flaw); keep those. Never keep a fix merely because it was severe, and never keep one because the bug class feels important.
|
|
||||||
- Do not grade entries by engineering importance. Severity and effort are already represented upstream; the curated changelog is not a credit ledger — its only job is to change what the reader does or knows.
|
|
||||||
- **Density, not quota.** Standalone sections stay short so the changelog actually gets read — as a default, expect about 2 Polish and 3 Bug Fixes entries per version, while `Features` is gated by the test alone and has no count. The defaults yield whenever more entries genuinely pass the reader-action test: keep them and flag the overflow for the human reviewer; never fold a qualifying entry just to hit the number, and never pad a section to reach it. The reviewer owns the final cutoff — the curator's job is to surface the borderline calls, not to resolve them silently.
|
|
||||||
- Everything else collapses into a single catch-all bullet placed last under `Bug Fixes`: `Fix several known issues.` When entries beyond fixes were also collapsed, use `Fix several known issues and make various refinements.` instead (Chinese: `修复了一些已知问题。` / `修复了一些已知问题,并做了若干细节优化。`). End the catch-all line with a pointer to the upstream file so folded entries stay reachable, phrased as a separate short sentence — `See the [changelog on GitHub](https://github.com/MoonshotAI/kimi-code/blob/main/apps/kimi-code/CHANGELOG.md) for more technical entries.` (Chinese: `更详细的变更记录见 [GitHub](https://github.com/MoonshotAI/kimi-code/blob/main/apps/kimi-code/CHANGELOG.md)。`). Link the file itself, never a per-version anchor — GitHub's generated heading anchors are fragile. Keep the pointer wording restrained ("more technical entries"): upstream only contains changes that received a changeset, so never claim the list is complete.
|
|
||||||
- If no fix survives, the `Bug Fixes` section is the catch-all line alone; if the whole version has no user-facing change, the version block is a single section with that line. Match the catch-all to what was folded — never claim fixes that did not happen: when the folded entries include fixes, use the forms above under `Bug Fixes`; when everything folded is polish or internal work, place the catch-all under `Polish` as `Make several refinements and internal improvements.` (Chinese: `做了若干细节优化和内部改进。`).
|
|
||||||
- **Merge micro-tweaks to the same surface.** Collapse several small tweaks to the same UI area or feature into one concise entry at the higher level. For example, "change the composer's default height" and "change the composer's default font" merge into "Polish the composer's default styling." Use the most specific common ancestor (composer, settings page, tool card, and so on). Classify the merged entry by its combined effect
|
|
||||||
- **Merge same-surface or same-kind fixes when you have three or more.** The `Bug Fixes` section tends to accumulate many narrow UI/polish fixes that read as noise when listed one by one. When three or more fixes target the same area (for example several tool cards in the TUI, or the web session/conversation surface) or the same class of problem (for example several "jumping/flickering/collapsing during streaming" fixes), merge them into one higher-level entry. Examples:
|
- **Merge same-surface or same-kind fixes when you have three or more.** The `Bug Fixes` section tends to accumulate many narrow UI/polish fixes that read as noise when listed one by one. When three or more fixes target the same area (for example several tool cards in the TUI, or the web session/conversation surface) or the same class of problem (for example several "jumping/flickering/collapsing during streaming" fixes), merge them into one higher-level entry. Examples:
|
||||||
- "Fix the Bash tool card collapsing...", "Fix the Edit tool card jumping in height...", "Fix the Edit tool card flickering while its result streams in" → "Fix several TUI tool cards jumping, flickering, or collapsing in height when results stream in or end with short output."
|
- "Fix the Bash tool card collapsing...", "Fix the Edit tool card jumping in height...", "Fix the Edit tool card flickering while its result streams in" → "Fix several TUI tool cards jumping, flickering, or collapsing in height when results stream in or end with short output."
|
||||||
- "Fix the collapsed sidebar not hiding...", "Stop the chat history from replaying its entrance animation...", "Fix tool components jumping the conversation when expanded/collapsed" → "Fix several layout and display glitches when switching sessions, including the collapsed sidebar not hiding, the chat history replaying its entrance animation, and tool components jumping the conversation."
|
- "Fix the collapsed sidebar not hiding...", "Stop the chat history from replaying its entrance animation...", "Fix tool components jumping the conversation when expanded/collapsed" → "web: Fix several layout and display glitches when switching sessions, including the collapsed sidebar not hiding, the chat history replaying its entrance animation, and tool components jumping the conversation."
|
||||||
- Classify the merged fixes as `Bug Fixes`.
|
- Keep `web:` if the merged fixes are all web-facing. Classify as `Bug Fixes`.
|
||||||
- **Do not over-merge.** Leave a fix standalone when it is broad, high-value, or genuinely distinct (for example model/provider tool-calling bugs, session-list corruption, file-completion gaps). Merging is for low-reader-value, similar-shape fixes that read as a wall of similar bullets. A merged fix entry must still pass the standalone test from the catch-all rule above; if the merged group is low-signal too, fold it into the catch-all line instead of listing it.
|
- **Do not over-merge.** Leave a fix standalone when it is broad, high-value, or genuinely distinct (for example model/provider tool-calling bugs, session-list corruption, file-completion gaps). Merging is for low-reader-value, similar-shape fixes that read as a wall of similar bullets.
|
||||||
- **Drop server/API plumbing covered by a web entry.** If one entry adds a web UI feature (for example, an Archived sessions page) and another entry only adds the server or REST/WebSocket endpoints that exist solely to power that web feature, keep the web UI entry and drop the API entry. CLI and web users perceive the web page; the backing API is implementation detail with no independent user value on this changelog. Keep the API entry only when it has independent user value — a new public endpoint that SDK or server consumers call directly, or a capability usable outside the web feature. When unsure, keep both and let the reviewer decide.
|
- **Drop server/API plumbing covered by a web entry.** If one entry adds a web UI feature (for example, an Archived sessions page) and another entry only adds the server or REST/WebSocket endpoints that exist solely to power that web feature, keep the `web:` entry and drop the API entry. CLI and web users perceive the web page; the backing API is implementation detail with no independent user value on this changelog. Keep the API entry only when it has independent user value — a new public endpoint that SDK or server consumers call directly, or a capability usable outside the web feature. When unsure, keep both and let the reviewer decide.
|
||||||
|
|
||||||
The docs changelog uses five section types:
|
The docs changelog uses five section types:
|
||||||
|
|
||||||
|
|
@ -154,8 +153,6 @@ The docs changelog uses five section types:
|
||||||
| `### Refactors` | `### 重构` | Internal changes with no user-visible behavior change, including build, CI, tests, dependency cleanup, and internal renames |
|
| `### Refactors` | `### 重构` | Internal changes with no user-visible behavior change, including build, CI, tests, dependency cleanup, and internal renames |
|
||||||
| `### Other` | `### 其他` | Anything that does not fit above, such as CDN/endpoint swaps and docs-related artifacts |
|
| `### Other` | `### 其他` | Anything that does not fit above, such as CDN/endpoint swaps and docs-related artifacts |
|
||||||
|
|
||||||
With the catch-all rule above, `Refactors` and `Other` rarely appear in newly synced versions: entries with no user-perceivable effect fold into the catch-all, and an entry that does change user-perceivable default behavior (for example an engine default flip with an opt-out flag) is classified by that effect, usually `Polish`. Reserve `Other` for genuinely unclassifiable but user-facing entries. Older versions keep whatever sections they already have — do not rewrite history.
|
|
||||||
|
|
||||||
Classification process:
|
Classification process:
|
||||||
|
|
||||||
1. Classify from the stripped entry text first.
|
1. Classify from the stripped entry text first.
|
||||||
|
|
@ -232,8 +229,6 @@ Example:
|
||||||
- Update the native release workflow to use current GitHub artifact actions.
|
- Update the native release workflow to use current GitHub artifact actions.
|
||||||
```
|
```
|
||||||
|
|
||||||
Doc links: an entry that changes a documented config surface may end with a pointer to the docs page — `see [X](...) for details` (Chinese: `详见 [X](...)。`). Keep it a real Markdown link into the docs tree with a relative path (for example `../configuration/config-files.md#loop-control`). When the link text is a config key or another identifier, code-style the text inside the brackets: [`loop_control`](../configuration/config-files.md#loop-control). Never wrap the whole link in backticks — `` `[loop_control](...)` `` renders as raw inline code that exposes the relative path instead of a clickable link.
|
|
||||||
|
|
||||||
### 6. Translate The Increment Into Chinese
|
### 6. Translate The Increment Into Chinese
|
||||||
|
|
||||||
After updating the English page, translate only the newly added English content into `docs/zh/release-notes/changelog.md`.
|
After updating the English page, translate only the newly added English content into `docs/zh/release-notes/changelog.md`.
|
||||||
|
|
@ -286,7 +281,7 @@ Guidelines:
|
||||||
- **Keep usage hints to one short clause**.
|
- **Keep usage hints to one short clause**.
|
||||||
- Bad: `传入 --allowed-host 以允许额外的 host。例如 ... (多句展开)`
|
- Bad: `传入 --allowed-host 以允许额外的 host。例如 ... (多句展开)`
|
||||||
- Better: `例如 kimi web --allowed-host example.com。`
|
- Better: `例如 kimi web --allowed-host example.com。`
|
||||||
- **Do not translate technical identifiers**: keep command names, flag names, file names, env vars, config keys as-is.
|
- **Do not translate technical identifiers**: keep command names, flag names, file names, env vars, config keys, and the `web:` scope prefix as-is.
|
||||||
- **Keep parallel rhythm within a section.** When several entries fix similar web surfaces (layout, animation, sizing), phrase them with a consistent structure (for example 修复 <问题>,现 <行为>) so the section reads as a tidy list rather than a mix of shapes.
|
- **Keep parallel rhythm within a section.** When several entries fix similar web surfaces (layout, animation, sizing), phrase them with a consistent structure (for example 修复 <问题>,现 <行为>) so the section reads as a tidy list rather than a mix of shapes.
|
||||||
|
|
||||||
Example — translating a feature entry:
|
Example — translating a feature entry:
|
||||||
|
|
@ -324,11 +319,9 @@ Check:
|
||||||
- Each version has the same section set and order on both pages.
|
- Each version has the same section set and order on both pages.
|
||||||
- Each section has the same number of entries on both pages.
|
- Each section has the same number of entries on both pages.
|
||||||
- Within each section, the most valuable, obvious, and larger entries appear before smaller or narrower entries.
|
- Within each section, the most valuable, obvious, and larger entries appear before smaller or narrower entries.
|
||||||
- Low-signal entries were collapsed into the single catch-all line, placed last under `Bug Fixes` — or under `Polish` when nothing folded is a fix (both the reader-action test and the channel test applied); the catch-all wording matches what was folded and never claims fixes that did not happen; section sizes stay within the density defaults (about 2 Polish, 3 Bug Fixes) unless extra qualifying entries were deliberately kept and flagged for review. The catch-all line ends with the upstream changelog pointer (file link, no version anchor).
|
|
||||||
- PR links and commit hashes were stripped.
|
- PR links and commit hashes were stripped.
|
||||||
- No `Thanks ...!` credit remains (remove it every time).
|
- No `Thanks ...!` credit remains (remove it every time).
|
||||||
- Real internal identifiers were replaced with neutral placeholders.
|
- Real internal identifiers were replaced with neutral placeholders.
|
||||||
- Doc links are real Markdown links (code-styled text inside the brackets when needed), never wrapped in backticks.
|
|
||||||
- There are no empty sections.
|
- There are no empty sections.
|
||||||
- Markdown indentation and blank lines are intact.
|
- Markdown indentation and blank lines are intact.
|
||||||
|
|
||||||
|
|
@ -353,7 +346,7 @@ If the user chooses review:
|
||||||
git diff docs/en/release-notes/changelog.md docs/zh/release-notes/changelog.md
|
git diff docs/en/release-notes/changelog.md docs/zh/release-notes/changelog.md
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Summarize synced versions, section counts, and anything that needed manual classification. List every entry folded into a catch-all line (short titles, one line each), any section that exceeds the density defaults, and every borderline call flagged during curation — the reviewer cannot own a cutoff they cannot see.
|
2. Summarize synced versions, section counts, and anything that needed manual classification.
|
||||||
3. Tell the user to reply when they are done reviewing, or to ask for edits.
|
3. Tell the user to reply when they are done reviewing, or to ask for edits.
|
||||||
4. Do **not** commit, push, or open a PR until the user explicitly says review is complete, or asks to proceed.
|
4. Do **not** commit, push, or open a PR until the user explicitly says review is complete, or asks to proceed.
|
||||||
|
|
||||||
|
|
@ -433,6 +426,7 @@ Return the PR URL to the user when done.
|
||||||
- The English docs changelog is the source of truth.
|
- The English docs changelog is the source of truth.
|
||||||
- Never edit upstream `apps/kimi-code/CHANGELOG.md`.
|
- Never edit upstream `apps/kimi-code/CHANGELOG.md`.
|
||||||
- Do not backfill unreleased `.changeset/*.md` drafts into the docs site.
|
- Do not backfill unreleased `.changeset/*.md` drafts into the docs site.
|
||||||
|
- Prefix web UI entries with `web: ` (when the upstream commit touches `apps/kimi-web/`), and keep the prefix on both the English and Chinese pages.
|
||||||
- If upstream wording is wrong, leave upstream alone and fix it in a future changeset.
|
- If upstream wording is wrong, leave upstream alone and fix it in a future changeset.
|
||||||
- Always sync on a `docs/changelog-sync-*` branch and open a PR; never push changelog docs sync directly to `main`.
|
- Always sync on a `docs/changelog-sync-*` branch and open a PR; never push changelog docs sync directly to `main`.
|
||||||
- Wait for the human review checkpoint before committing, pushing, or opening a PR.
|
- Wait for the human review checkpoint before committing, pushing, or opening a PR.
|
||||||
|
|
@ -446,15 +440,7 @@ Return the PR URL to the user when done.
|
||||||
| Leaving the `Thanks ...!` credit in docs | Remove it every time, including the multi-author form |
|
| Leaving the `Thanks ...!` credit in docs | Remove it every time, including the multi-author form |
|
||||||
| Leaving near-duplicate micro-tweaks as separate bullets | Merge small tweaks to the same surface into one higher-level entry (e.g. composer height + font → composer's default styling) |
|
| Leaving near-duplicate micro-tweaks as separate bullets | Merge small tweaks to the same surface into one higher-level entry (e.g. composer height + font → composer's default styling) |
|
||||||
| Listing many narrow fixes to the same surface as separate bullets | When three or more fixes target the same UI area or the same class of problem, merge them into one higher-level fix entry; keep genuinely distinct or high-value fixes standalone |
|
| Listing many narrow fixes to the same surface as separate bullets | When three or more fixes target the same UI area or the same class of problem, merge them into one higher-level fix entry; keep genuinely distinct or high-value fixes standalone |
|
||||||
| Listing low-signal fixes or internal changes as standalone bullets | Collapse them into the single catch-all line (`Fix several known issues.`) placed last under Bug Fixes; treat the section-size defaults (about 2 Polish, 3 Bug Fixes) as a density guard, not a quota |
|
| Listing a server/API entry that only backs a web feature already listed | Drop the API entry and keep the `web:` entry, unless the API has independent user value |
|
||||||
| Folding a qualifying entry just to hit the section-size default | The defaults are density guards; keep entries that genuinely pass the reader-action test and flag the overflow for the human reviewer |
|
|
||||||
| Keeping a fix because it was severe or hard-won | Severity makes the announcement redundant — the fix itself notifies whoever was hit; keep only behavior-change fixes and retrospective notices with a concrete, locatable action |
|
|
||||||
| Keeping an improvement the product surfaces in context (recovery cards, post-install guidance, progress displays) | The product is the better channel — right users, moment of need; fold it (channel test) |
|
|
||||||
| Folding a new capability because its control is visible somewhere in the UI | Visible is not discoverable — users do not explore; a toggle, menu item, or settings page that only waits to be found needs the changelog announcement |
|
|
||||||
| Keeping a silent-impact fix out of diligence (dropped data, wrong results the user never noticed) | The changelog does not repair the past; if the notice names no locatable instance and no realistic action, it is anxiety without an outlet — fold it |
|
|
||||||
| Overstating the catch-all pointer (for example claiming the upstream changelog is complete) | Keep the pointer restrained — `See the [changelog on GitHub](...) for more technical entries.`; upstream only contains changes that received a changeset |
|
|
||||||
| Writing `Fix several known issues.` when nothing folded is a fix | Never claim fixes that did not happen; all-polish/internal folds go under Polish as `Make several refinements and internal improvements.` |
|
|
||||||
| Listing a server/API entry that only backs a web feature already listed | Drop the API entry and keep the web UI entry, unless the API has independent user value |
|
|
||||||
| Rewording upstream English entries | Upstream is frozen; copy the body text unless the user explicitly asks otherwise |
|
| Rewording upstream English entries | Upstream is frozen; copy the body text unless the user explicitly asks otherwise |
|
||||||
| Leaving English text untranslated in the Chinese page | The Chinese page must be fully Chinese except preserved technical terms |
|
| Leaving English text untranslated in the Chinese page | The Chinese page must be fully Chinese except preserved technical terms |
|
||||||
| Editing upstream changelog text | Do not edit upstream |
|
| Editing upstream changelog text | Do not edit upstream |
|
||||||
|
|
@ -468,13 +454,12 @@ Return the PR URL to the user when done.
|
||||||
| Leaving empty sections | Delete sections with no entries |
|
| Leaving empty sections | Delete sections with no entries |
|
||||||
| Putting everything under Other for convenience | Classify what can be classified first |
|
| Putting everything under Other for convenience | Classify what can be classified first |
|
||||||
| Translating tool names, command names, or config keys | Keep them as written |
|
| Translating tool names, command names, or config keys | Keep them as written |
|
||||||
| Wrapping a whole doc link in backticks | Code-style the link text inside the brackets instead, so the link stays clickable: [`loop_control`](...) |
|
|
||||||
| Keeping hook/event payload-mechanics clauses | Drop what an event reports or carries; keep the new capability and how to configure it |
|
|
||||||
| Creating a changeset for docs sync | Do not create one |
|
| Creating a changeset for docs sync | Do not create one |
|
||||||
| Committing or pushing directly on `main` | Create `docs/changelog-sync-<version>`, commit there, then open a PR |
|
| Committing or pushing directly on `main` | Create `docs/changelog-sync-<version>`, commit there, then open a PR |
|
||||||
| Committing or opening a PR before the user skips review or confirms review is done | Wait at the human review checkpoint |
|
| Committing or opening a PR before the user skips review or confirms review is done | Wait at the human review checkpoint |
|
||||||
| Using curly quotes or half-width Chinese punctuation | Follow `docs/AGENTS.md` |
|
| Using curly quotes or half-width Chinese punctuation | Follow `docs/AGENTS.md` |
|
||||||
| Omitting the release date from a version heading, or guessing it | Add ` (YYYY-MM-DD)` (full-width `()` in Chinese) taken from the published tag |
|
| Omitting the release date from a version heading, or guessing it | Add ` (YYYY-MM-DD)` (full-width `()` in Chinese) taken from the published tag |
|
||||||
|
| Forgetting or translating the `web:` prefix on web UI entries | Prefix web UI entries (commit touches `apps/kimi-web/`) with `web: ` on both pages; keep the prefix as-is when translating |
|
||||||
|
|
||||||
## Stop Signals
|
## Stop Signals
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ All other workspace packages are private internal packages, are not published to
|
||||||
- `@moonshot-ai/kaos`
|
- `@moonshot-ai/kaos`
|
||||||
- `@moonshot-ai/kimi-code-oauth`
|
- `@moonshot-ai/kimi-code-oauth`
|
||||||
- `@moonshot-ai/kimi-telemetry`
|
- `@moonshot-ai/kimi-telemetry`
|
||||||
|
- `@moonshot-ai/kimi-web`
|
||||||
- `@moonshot-ai/kosong`
|
- `@moonshot-ai/kosong`
|
||||||
- `@moonshot-ai/migration-legacy`
|
- `@moonshot-ai/migration-legacy`
|
||||||
- `@moonshot-ai/protocol`
|
- `@moonshot-ai/protocol`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
"@moonshot-ai/kimi-code": patch
|
|
||||||
"@moonshot-ai/kimi-code-sdk": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Detect MCP servers that require OAuth by reusing the existing connection-time authorization check.
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
"@moonshot-ai/kimi-code": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Fix the token counts reported after compaction reading far below the real context size: the before/after stats and the context gauge now include the system prompt and tool definitions, matching the numbers shown while the session runs.
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
"@moonshot-ai/kimi-code": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Fix multi-second typing and rendering freezes at startup or while idle when a large search index loads, replays, or rebuilds.
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
"@moonshot-ai/kimi-code-sdk": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Expose persisted MCP authorization status without starting an OAuth flow.
|
|
||||||
8
.github/workflows/_native-build.yml
vendored
8
.github/workflows/_native-build.yml
vendored
|
|
@ -86,9 +86,11 @@ jobs:
|
||||||
echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV"
|
echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Build Kimi web assets
|
- name: Build Kimi web assets
|
||||||
# The SEA blob step embeds apps/kimi-code/dist-web. The bundle is
|
# The SEA blob step embeds apps/kimi-code/dist-web; build the web app
|
||||||
# committed (synced from the code-app repo) — just verify it is in place.
|
# and stage its assets before producing the native executable.
|
||||||
run: node apps/kimi-code/scripts/check-web-assets.mjs
|
run: |
|
||||||
|
pnpm --filter @moonshot-ai/kimi-web run build
|
||||||
|
node apps/kimi-code/scripts/copy-web-assets.mjs
|
||||||
|
|
||||||
- name: Build native executable (release profile, macOS signed)
|
- name: Build native executable (release profile, macOS signed)
|
||||||
if: runner.os == 'macOS' && inputs.sign-macos
|
if: runner.os == 'macOS' && inputs.sign-macos
|
||||||
|
|
|
||||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -127,6 +127,8 @@ jobs:
|
||||||
done
|
done
|
||||||
- name: Typecheck VS Code extension
|
- name: Typecheck VS Code extension
|
||||||
run: pnpm --filter kimi-code run typecheck
|
run: pnpm --filter kimi-code run typecheck
|
||||||
|
- name: Typecheck kimi-web (vue-tsc)
|
||||||
|
run: pnpm --filter @moonshot-ai/kimi-web run typecheck
|
||||||
- name: Typecheck vis-server
|
- name: Typecheck vis-server
|
||||||
run: pnpm --filter @moonshot-ai/vis-server run typecheck
|
run: pnpm --filter @moonshot-ai/vis-server run typecheck
|
||||||
- name: Typecheck vis-web
|
- name: Typecheck vis-web
|
||||||
|
|
|
||||||
3
.github/workflows/pkg-pr-new.yml
vendored
3
.github/workflows/pkg-pr-new.yml
vendored
|
|
@ -36,6 +36,9 @@ jobs:
|
||||||
- name: Build package dependencies
|
- name: Build package dependencies
|
||||||
run: pnpm run build:packages
|
run: pnpm run build:packages
|
||||||
|
|
||||||
|
- name: Build Kimi web assets
|
||||||
|
run: pnpm --filter @moonshot-ai/kimi-web run build
|
||||||
|
|
||||||
- name: Generate Kimi Code built-in catalog
|
- name: Generate Kimi Code built-in catalog
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
|
dist-web/
|
||||||
dist-single/
|
dist-single/
|
||||||
dist-native/
|
dist-native/
|
||||||
.tmp-api-extractor/
|
.tmp-api-extractor/
|
||||||
|
|
|
||||||
|
|
@ -90,30 +90,6 @@
|
||||||
"eslint/no-console": "off"
|
"eslint/no-console": "off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// The worker closures: these modules (and everything
|
|
||||||
// packages/minidb/src/worker/ and
|
|
||||||
// packages/kap-server/src/search/worker/ pull in) are loaded by a bare
|
|
||||||
// node:worker_threads Worker under Node's native type stripping with
|
|
||||||
// `execArgv: ['--experimental-transform-types']`, which requires
|
|
||||||
// explicit `.ts` import specifiers (the strip loader does not remap
|
|
||||||
// `.js` -> `.ts`). Keep the exception scoped to exactly those closures.
|
|
||||||
"files": [
|
|
||||||
"packages/minidb/src/worker/**/*.ts",
|
|
||||||
"packages/minidb/src/codec.ts",
|
|
||||||
"packages/minidb/src/crc32.ts",
|
|
||||||
"packages/minidb/src/trigram.ts",
|
|
||||||
"packages/minidb/src/text-postings.ts",
|
|
||||||
"packages/minidb/src/text-index/tokenize.ts",
|
|
||||||
"packages/minidb/src/gen-codec.ts",
|
|
||||||
"packages/kap-server/src/search/worker/**/*.ts",
|
|
||||||
"packages/kap-server/src/search/indexCore.ts",
|
|
||||||
"packages/kap-server/src/search/match.ts"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"import/extensions": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"files": ["packages/kosong/src/providers/**/*.ts"],
|
"files": ["packages/kosong/src/providers/**/*.ts"],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
|
@ -170,7 +146,6 @@
|
||||||
],
|
],
|
||||||
"ignorePatterns": [
|
"ignorePatterns": [
|
||||||
"dist/",
|
"dist/",
|
||||||
"dist-web/",
|
|
||||||
"coverage/",
|
"coverage/",
|
||||||
"node_modules/",
|
"node_modules/",
|
||||||
"apps/*/scripts/",
|
"apps/*/scripts/",
|
||||||
|
|
|
||||||
27
AGENTS.md
27
AGENTS.md
File diff suppressed because one or more lines are too long
2
apps/kimi-code/.gitignore
vendored
2
apps/kimi-code/.gitignore
vendored
|
|
@ -8,4 +8,4 @@ agents/
|
||||||
src/generated/vis-web-asset.ts
|
src/generated/vis-web-asset.ts
|
||||||
|
|
||||||
# Copied from packages/pi-tui/native at build time by scripts/copy-native-assets.mjs
|
# Copied from packages/pi-tui/native at build time by scripts/copy-native-assets.mjs
|
||||||
/native/
|
native/
|
||||||
|
|
|
||||||
|
|
@ -1,127 +1,5 @@
|
||||||
# @moonshot-ai/kimi-code
|
# @moonshot-ai/kimi-code
|
||||||
|
|
||||||
## 0.34.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#2646](https://github.com/MoonshotAI/kimi-code/pull/2646) [`3c75a27`](https://github.com/MoonshotAI/kimi-code/commit/3c75a27da66e522ae670ec8ce9093ea71d091d27) Thanks [@liruifengv](https://github.com/liruifengv)! - Show a cache-expiry reminder when resuming a long-idle session or submitting after a long idle stretch.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: When a model request fails and interrupts a conversation, a persistent failure card now stays in the session with one-click resume.
|
|
||||||
|
|
||||||
- [#2652](https://github.com/MoonshotAI/kimi-code/pull/2652) [`68ba740`](https://github.com/MoonshotAI/kimi-code/commit/68ba740ebfb3e32ad9abdb8607f48d4387cf6f69) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Add Windows support for the built-in Kimi Computer Use capability and show the underlying error when capability setup fails. Install it from `/plugins` on Windows x64.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Add a flat view to the sidebar session list.
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#2648](https://github.com/MoonshotAI/kimi-code/pull/2648) [`d1ded01`](https://github.com/MoonshotAI/kimi-code/commit/d1ded01b7c50c9847440f4645fe13f588becdc66) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Restore how the last turn ended (completed, cancelled, or failed) when a session is resumed after a server restart, so clients can still surface a previously failed turn instead of the session looking silently stopped.
|
|
||||||
|
|
||||||
- [#2666](https://github.com/MoonshotAI/kimi-code/pull/2666) [`335588e`](https://github.com/MoonshotAI/kimi-code/commit/335588e2594a61a767ce258b34b4049a32b18fe5) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Session listings keep how the last turn ended (completed, cancelled, or failed) across server restarts, so clients can mark previously failed sessions before they are opened.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix the model picker overflowing the screen when many models are available, leaving the bottom options unreachable.
|
|
||||||
|
|
||||||
- [#2639](https://github.com/MoonshotAI/kimi-code/pull/2639) [`8588121`](https://github.com/MoonshotAI/kimi-code/commit/858812193a267fcb9382e351137f892646ef79aa) Thanks [@7Sageer](https://github.com/7Sageer)! - /feedback now works for any signed-in user regardless of the active model; signed-out users are shown the sign-up page and GitHub Issues links instead.
|
|
||||||
|
|
||||||
- [#2675](https://github.com/MoonshotAI/kimi-code/pull/2675) [`34c4181`](https://github.com/MoonshotAI/kimi-code/commit/34c418143759a9e80cdda97e95e609c5a993916d) Thanks [@sailist](https://github.com/sailist)! - Fix kimi -p exiting right after the main turn instead of waiting for background tasks and subagents to finish.
|
|
||||||
|
|
||||||
- [#2694](https://github.com/MoonshotAI/kimi-code/pull/2694) [`02c026d`](https://github.com/MoonshotAI/kimi-code/commit/02c026d4871a14cd5e7b4b0e0ec71ba815f643df) Thanks [@sailist](https://github.com/sailist)! - Keep live sessions stable when an MCP server is removed from the workspace config or uninstalled with its plugin: its tools stay registered in open sessions but calls fail with a removal notice, and the MCP panel shows the removed status. Servers added mid-session — by a plugin install or a config edit — are not registered in open sessions; they take effect in new sessions or after `/new` or `/reload`.
|
|
||||||
|
|
||||||
- [#2647](https://github.com/MoonshotAI/kimi-code/pull/2647) [`7bd3fd9`](https://github.com/MoonshotAI/kimi-code/commit/7bd3fd9f6e6c10f88d33b85760631ad6212b5f58) Thanks [@sailist](https://github.com/sailist)! - Read UTF-16 LE/BE text files (with or without a BOM) by transcoding them to UTF-8 instead of refusing them as binary; the web UI file viewer displays them as text as well.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: The sidebar error marker now only appears when the last turn failed; manually cancelled sessions are no longer flagged.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix attachments being silently dropped when sent together with a skill command.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix a manually chosen thinking level being reset to the model default when the first message of a new session is a skill command.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix session renaming during IME composition — Enter no longer submits mid-composition and Esc no longer exits the editor while composing.
|
|
||||||
|
|
||||||
- [#2686](https://github.com/MoonshotAI/kimi-code/pull/2686) [`ef61084`](https://github.com/MoonshotAI/kimi-code/commit/ef610840098a57819d62d407f33256e14b512c77) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Use a compatible PowerShell for Windows Kimi Computer Use installation, provide actionable recovery for locked plugin files, and keep its marketplace name consistent after installation.
|
|
||||||
|
|
||||||
- [#2679](https://github.com/MoonshotAI/kimi-code/pull/2679) [`7b2784b`](https://github.com/MoonshotAI/kimi-code/commit/7b2784b9b7bf4749058da48923ecbbc8019eb7af) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Subagent tasks now show the model and thinking level they use.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix text selection while renaming a session or workspace — dragging no longer moves the whole list item.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix the chevron direction on the "show less" button of the changed-files summary card.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: During automatic retries after a failed model request, the working status now shows retry progress (attempt N of M) instead of looking unresponsive.
|
|
||||||
|
|
||||||
- [#2677](https://github.com/MoonshotAI/kimi-code/pull/2677) [`713bf1a`](https://github.com/MoonshotAI/kimi-code/commit/713bf1a5a2b388e4c5f9d3f471a728b8edbf5811) Thanks [@liruifengv](https://github.com/liruifengv)! - Fix resumed sessions rendering background task completion notifications as raw protocol text instead of a task status card.
|
|
||||||
|
|
||||||
- [#2692](https://github.com/MoonshotAI/kimi-code/pull/2692) [`03aa66c`](https://github.com/MoonshotAI/kimi-code/commit/03aa66ca0cca5880dc3a4a89e4f46d09acbe47ae) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Show browser extension links and activation steps after installing Kimi WebBridge.
|
|
||||||
|
|
||||||
- [#2645](https://github.com/MoonshotAI/kimi-code/pull/2645) [`2b89373`](https://github.com/MoonshotAI/kimi-code/commit/2b893733f9853dc0aaeb775d9670d277db8e0381) Thanks [@sailist](https://github.com/sailist)! - Fix the web UI opening the Documents folder instead of the requested file on Windows when the file path contains spaces.
|
|
||||||
|
|
||||||
- [#2697](https://github.com/MoonshotAI/kimi-code/pull/2697) [`e6e4ba2`](https://github.com/MoonshotAI/kimi-code/commit/e6e4ba2357cc659ebd0fd44c9492b498adc33d0e) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Fix the background-tasks and todos pills being pushed to the top of the window when the plan approval dialog expands.
|
|
||||||
|
|
||||||
## 0.33.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#2407](https://github.com/MoonshotAI/kimi-code/pull/2407) [`0abcd00`](https://github.com/MoonshotAI/kimi-code/commit/0abcd00f7fd3e3cbf087509ffef1c54a6f8d396d) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Add Kimi Computer Use and Kimi WebBridge as built-in official marketplace entries in the v2 CLI. Installing from `/plugins` sets up the latest managed runtime and plugin together, reports incomplete manual steps, and supports retrying interrupted setup.
|
|
||||||
|
|
||||||
- [#2627](https://github.com/MoonshotAI/kimi-code/pull/2627) [`f881cdd`](https://github.com/MoonshotAI/kimi-code/commit/f881cdd97073475c43272ec5734bbc39290dd399) Thanks [@sailist](https://github.com/sailist)! - Run the CLI surfaces (interactive TUI, `kimi -p`, `kimi acp`, `kimi export`, `kimi provider`) on the agent-core-v2 engine by default. Set `KIMI_CODE_LEGACY_FLAG=1` to fall back to the legacy engine.
|
|
||||||
|
|
||||||
- [#2565](https://github.com/MoonshotAI/kimi-code/pull/2565) [`54c04bf`](https://github.com/MoonshotAI/kimi-code/commit/54c04bf03ddbeb46d02b2edb460ea091ae194509) Thanks [@7Sageer](https://github.com/7Sageer)! - `/fork` no longer switches to the forked session: the current session stays active and its background tasks keep running. Find the fork in `/sessions`.
|
|
||||||
|
|
||||||
- [#2630](https://github.com/MoonshotAI/kimi-code/pull/2630) [`3bd098b`](https://github.com/MoonshotAI/kimi-code/commit/3bd098b80643c99eabdc602b767dbc53fc47cedd) Thanks [@liruifengv](https://github.com/liruifengv)! - Ask whether to trust the current folder on startup.
|
|
||||||
|
|
||||||
- [#2630](https://github.com/MoonshotAI/kimi-code/pull/2630) [`3bd098b`](https://github.com/MoonshotAI/kimi-code/commit/3bd098b80643c99eabdc602b767dbc53fc47cedd) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Add and manage custom providers in settings.
|
|
||||||
|
|
||||||
- [#2599](https://github.com/MoonshotAI/kimi-code/pull/2599) [`541ddd2`](https://github.com/MoonshotAI/kimi-code/commit/541ddd2d898c4880a312874b1c539f85888bf0c1) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Overhaul the UI/UX and fix known issues.
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#2601](https://github.com/MoonshotAI/kimi-code/pull/2601) [`75fe068`](https://github.com/MoonshotAI/kimi-code/commit/75fe068a01261ff6b34f176530b338ec6a24918e) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Fix built-in capability availability and installed status in `/plugins`, preserve legacy WebBridge skills as backups during updates, and prevent Computer Use updates from duplicating or disconnecting MCP servers.
|
|
||||||
|
|
||||||
- [#2635](https://github.com/MoonshotAI/kimi-code/pull/2635) [`2b3e9a9`](https://github.com/MoonshotAI/kimi-code/commit/2b3e9a9f7910b0bb8050380068fa122c2c2cee91) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Rename the partner plugin marketplace tab to Curated and clarify that it contains third-party plugins from Kimi partners.
|
|
||||||
|
|
||||||
- [#2614](https://github.com/MoonshotAI/kimi-code/pull/2614) [`8db7d42`](https://github.com/MoonshotAI/kimi-code/commit/8db7d42f23472a692eb389a0e0e5a3e18aa1b94d) Thanks [@RealKai42](https://github.com/RealKai42)! - Add /bug as an alias for the /feedback slash command. Type /bug to submit feedback.
|
|
||||||
|
|
||||||
- [#2586](https://github.com/MoonshotAI/kimi-code/pull/2586) [`278b6af`](https://github.com/MoonshotAI/kimi-code/commit/278b6af19d8708ec0f3eb2696d62a8d8209d497d) Thanks [@7Sageer](https://github.com/7Sageer)! - Ensure the first request waits for MCP startup to finish while the interface still opens immediately.
|
|
||||||
|
|
||||||
- [#2620](https://github.com/MoonshotAI/kimi-code/pull/2620) [`2ee6e43`](https://github.com/MoonshotAI/kimi-code/commit/2ee6e431240a4a31034e0a403011dd6b2bfef9df) Thanks [@xpzouying](https://github.com/xpzouying)! - Fixed MCP OAuth re-authorization always failing with "Invalid redirect URI": the OAuth callback listener binds a random port per flow, but the dynamic client registration recorded the first flow's port, so every later interactive authorization was rejected at the authorization endpoint. A stale registration is now dropped automatically and the flow re-registers with the current callback URI.
|
|
||||||
|
|
||||||
- [#2596](https://github.com/MoonshotAI/kimi-code/pull/2596) [`c32e661`](https://github.com/MoonshotAI/kimi-code/commit/c32e661faa931df9fdc72e63230f3ebebc00dce5) Thanks [@xpzouying](https://github.com/xpzouying)! - MCP tool results now surface the spec-defined `structuredContent` field and `_meta` server metadata to the model as a serialized `<mcp-structured-result>` block, instead of silently dropping them. Servers that return their machine-readable contract in these fields work the same as on other MCP hosts.
|
|
||||||
|
|
||||||
- [#2612](https://github.com/MoonshotAI/kimi-code/pull/2612) [`e357028`](https://github.com/MoonshotAI/kimi-code/commit/e3570280bde775a153ee04388393506da7ac4cc1) Thanks [@7Sageer](https://github.com/7Sageer)! - Fix all tool calls failing with spawn EBADF on macOS when a skill folder contains a very large file tree.
|
|
||||||
|
|
||||||
- [#2630](https://github.com/MoonshotAI/kimi-code/pull/2630) [`3bd098b`](https://github.com/MoonshotAI/kimi-code/commit/3bd098b80643c99eabdc602b767dbc53fc47cedd) Thanks [@liruifengv](https://github.com/liruifengv)! - Start the interactive TUI without creating a session.
|
|
||||||
|
|
||||||
- [#2630](https://github.com/MoonshotAI/kimi-code/pull/2630) [`3bd098b`](https://github.com/MoonshotAI/kimi-code/commit/3bd098b80643c99eabdc602b767dbc53fc47cedd) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Show the signed-in account and plan usage.
|
|
||||||
|
|
||||||
- [#2630](https://github.com/MoonshotAI/kimi-code/pull/2630) [`3bd098b`](https://github.com/MoonshotAI/kimi-code/commit/3bd098b80643c99eabdc602b767dbc53fc47cedd) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Set an emoji for the session title.
|
|
||||||
|
|
||||||
- [#2630](https://github.com/MoonshotAI/kimi-code/pull/2630) [`3bd098b`](https://github.com/MoonshotAI/kimi-code/commit/3bd098b80643c99eabdc602b767dbc53fc47cedd) Thanks [@liruifengv](https://github.com/liruifengv)! - web: Pin sessions to the top of the sidebar.
|
|
||||||
|
|
||||||
## 0.32.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#2558](https://github.com/MoonshotAI/kimi-code/pull/2558) [`75395f6`](https://github.com/MoonshotAI/kimi-code/commit/75395f6abb17f83f30d16b51f4e060a639f43622) Thanks [@sailist](https://github.com/sailist)! - Add the TurnStarted, UserPromptQueued, TaskStarted, and SessionHeartbeat hook events, enrich hook payloads with the session title and client type, include the model and profile in SessionStart, and report SessionEnd as archive when a session is archived instead of exited. Configure the new events under [[hooks]] in config.toml.
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#2416](https://github.com/MoonshotAI/kimi-code/pull/2416) [`eaab2b6`](https://github.com/MoonshotAI/kimi-code/commit/eaab2b6f28c0b958edf8ab5ae5e78a4c0426af26) Thanks [@mangeshraut712](https://github.com/mangeshraut712)! - Fall back to the built-in models.dev catalog snapshot when the public catalog is unreachable, so Known third-party provider import still works offline or in blocked networks.
|
|
||||||
|
|
||||||
- [#2083](https://github.com/MoonshotAI/kimi-code/pull/2083) [`bfa0080`](https://github.com/MoonshotAI/kimi-code/commit/bfa00807c975fdc5b84dda32d47b16b09e8d42c1) Thanks [@StaR4y](https://github.com/StaR4y)! - web: Fix dark-mode monochrome controls and align the chat composer corner radius with the design system.
|
|
||||||
|
|
||||||
- [#2559](https://github.com/MoonshotAI/kimi-code/pull/2559) [`dfc55a5`](https://github.com/MoonshotAI/kimi-code/commit/dfc55a5c977dbff657e1da74ff5c2b9d488807be) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Render the "/login" already-logged-in confirmation in the success color instead of dim text, so the "Already logged in. Model configuration refreshed." message is clearly visible.
|
|
||||||
|
|
||||||
- [#2572](https://github.com/MoonshotAI/kimi-code/pull/2572) [`6ba75a1`](https://github.com/MoonshotAI/kimi-code/commit/6ba75a173b595904bc70d0d7161de2f9b964c961) Thanks [@sailist](https://github.com/sailist)! - Rename the `[loop_control] max_retries_per_step` config key to `max_attempts_per_step` and `max_steps_per_run` to `max_steps_per_turn`: on the v2 engine the old keys no longer take effect and a startup warning prompts the rename in `config.toml`. The `KIMI_LOOP_MAX_RETRIES_PER_STEP` env var is likewise deprecated in favor of `KIMI_LOOP_MAX_ATTEMPTS_PER_STEP` but keeps working with a warning.
|
|
||||||
|
|
||||||
- [#2585](https://github.com/MoonshotAI/kimi-code/pull/2585) [`c396873`](https://github.com/MoonshotAI/kimi-code/commit/c39687318c64bf8a305a10bf9ca86ef6ef2c6656) Thanks [@sailist](https://github.com/sailist)! - Fix submitting answers to interactive question prompts being rejected when the model provider returns tool call IDs containing colons (some OpenAI-compatible gateways).
|
|
||||||
|
|
||||||
- [#2562](https://github.com/MoonshotAI/kimi-code/pull/2562) [`071b6a5`](https://github.com/MoonshotAI/kimi-code/commit/071b6a50d9c2ce9c4b45dc4d58dac1101b8c4f52) Thanks [@sailist](https://github.com/sailist)! - Serve v1 message history from the server layer and drop the engine-side legacy message adapter; the /api/v1 message contract is unchanged.
|
|
||||||
|
|
||||||
- [#2562](https://github.com/MoonshotAI/kimi-code/pull/2562) [`071b6a5`](https://github.com/MoonshotAI/kimi-code/commit/071b6a50d9c2ce9c4b45dc4d58dac1101b8c4f52) Thanks [@sailist](https://github.com/sailist)! - Assemble the session snapshot endpoint from the engine's services for both cold and live sessions, and remove the KIMI_SNAPSHOT_READER, KIMI_SNAPSHOT_TIMEOUT_MS, and KIMI_SNAPSHOT_CACHE_LIMIT environment knobs.
|
|
||||||
|
|
||||||
- [#2563](https://github.com/MoonshotAI/kimi-code/pull/2563) [`2118544`](https://github.com/MoonshotAI/kimi-code/commit/21185447fe0f04dbe342bebb6c6d0b364fd43daa) Thanks [@sailist](https://github.com/sailist)! - Fix the context window limit showing as 0 in session status updates when no model is bound yet or the configured model no longer resolves; the limit now falls back to the default model or is omitted when unknown.
|
|
||||||
|
|
||||||
- [#2563](https://github.com/MoonshotAI/kimi-code/pull/2563) [`2118544`](https://github.com/MoonshotAI/kimi-code/commit/21185447fe0f04dbe342bebb6c6d0b364fd43daa) Thanks [@sailist](https://github.com/sailist)! - The `[token_counting]` strategy now only selects the reported context size: `estimated` keeps provider-reported usage out of the context-size display, and `measured` no longer gets stuck retrying an oversized compaction request until it fails.
|
|
||||||
|
|
||||||
- [#2563](https://github.com/MoonshotAI/kimi-code/pull/2563) [`2118544`](https://github.com/MoonshotAI/kimi-code/commit/21185447fe0f04dbe342bebb6c6d0b364fd43daa) Thanks [@sailist](https://github.com/sailist)! - Add a `[token_counting]` config section to choose how context token counts are derived: `measured+estimated` (default), `measured` (provider usage only), or `estimated` (heuristic only, for providers without usage reporting). Set `strategy` under `[token_counting]` in config.toml (or `KIMI_TOKEN_COUNTING_STRATEGY`) to switch.
|
|
||||||
|
|
||||||
## 0.31.1
|
## 0.31.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
||||||
import{bQ as A,M as H,aU as b,bE as V,az as J,aL as O,s as Q,v as R,I as F,bJ as G,bL as K,aw as L,H as W,bb as Z,bB as ee,g as te,au as le,T as ae,as as B,bR as ne}from"./index-HRJ6xRtC.js";var k=(h,E,e)=>new Promise((o,p)=>{var i=a=>{try{d(e.next(a))}catch(c){p(c)}},y=a=>{try{d(e.throw(a))}catch(c){p(c)}},d=a=>a.done?o(a.value):Promise.resolve(a.value).then(i,y);d((e=e.apply(h,E)).next())});const oe=["id"],ie=["data-placement"],ue=A(H({__name:"Tooltip",props:{visible:{type:Boolean},anchorEl:{},content:{},placement:{},offset:{},originX:{},originY:{},id:{},isDark:{type:[Boolean,null]}},setup(h){var E;const e=h,o=b(null),p=b(null),i=b({transform:"translate3d(0px, 0px, 0px)",left:"0px",top:"0px"}),y=b({}),d=b((E=e.placement)!=null?E:"top"),a=b(!1);let c=null,$=null,T=null,C=null,w=null,s=0;function X(){return C?Promise.resolve(C):(w||(w=ne(()=>import("./floating-ui.dom-xGUaHE3m.js"),[]).then(l=>(C=l,l)).catch(l=>{throw w=null,l})),w)}function D(){c&&(c(),c=null),$=null,T=null}function P(l){return k(this,null,function*(){const t=e.anchorEl,n=o.value;if(!e.visible||!t||!n||$===t&&T===n)return;const{autoUpdate:r}=yield X();l()&&e.visible&&e.anchorEl===t&&o.value===n&&(D(),$=t,T=n,c=r(t,n,()=>{N().catch(()=>{_()})}))})}function N(){return k(this,null,function*(){var l,t;const n=e.anchorEl,r=o.value;if(!e.visible||!n||!r)return!1;const{arrow:u,computePosition:m,flip:v,offset:f,shift:x}=yield X();if(!e.visible||e.anchorEl!==n||o.value!==r)return!1;const g=[f((l=e.offset)!=null?l:6),v(),x({padding:6}),...p.value?[u({element:p.value,padding:4})]:[]],{x:S,y:j,placement:Y,middlewareData:z}=yield m(n,r,{placement:(t=e.placement)!=null?t:"top",middleware:g,strategy:"fixed"});if(!e.visible||e.anchorEl!==n||o.value!==r)return!1;if(i.value.transform=`translate3d(${Math.round(S)}px, ${Math.round(j)}px, 0)`,i.value.left="0px",i.value.top="0px",d.value=Y,z.arrow&&p.value){const{x:I,y:U}=z.arrow,q={top:"bottom",bottom:"top",left:"right",right:"left"}[Y.split("-")[0]];y.value={left:I!=null?`${I}px`:"",top:U!=null?`${U}px`:"",[q]:"-3px"}}return!0})}function _(){var l,t;const n=e.anchorEl,r=o.value;if(!n||!r)return!1;const u=n.getBoundingClientRect(),m=r.getBoundingClientRect(),v=(l=e.offset)!=null?l:6,f=(t=e.placement)!=null?t:"top";let x=u.left,g=u.top;return f==="bottom"?g=u.bottom+v:f==="left"?x=u.left-m.width-v:f==="right"?x=u.right+v:g=u.top-m.height-v,i.value.transform=`translate3d(${Math.round(Math.max(0,x))}px, ${Math.round(Math.max(0,g))}px, 0)`,i.value.left="0px",i.value.top="0px",d.value=f,y.value={},!0}V(()=>e.visible,l=>k(null,null,function*(){const t=++s;if(l){if(a.value=!1,yield B(),t!==s||!e.visible)return;if(e.anchorEl&&o.value)try{const n=e.anchorEl,r=o.value,u=n.getBoundingClientRect();if(!(yield N())||t!==s||!e.visible||e.anchorEl!==n||o.value!==r)return;const m=i.value.transform;if(e.originX!=null&&e.originY!=null){const v=Math.abs(Number(e.originX)-u.left),f=Math.abs(Number(e.originY)-u.top);if(Math.hypot(v,f)>120){if(i.value.transform=`translate3d(${Math.round(e.originX)}px, ${Math.round(e.originY)}px, 0)`,yield B(),t!==s||!e.visible||(a.value=!0,yield B(),t!==s||!e.visible))return;i.value.transform=m}else a.value=!0}else a.value=!0;yield P(()=>t===s)}catch{if(t!==s||!e.visible)return;if(a.value=_(),e.anchorEl&&o.value)try{yield P(()=>t===s)}catch{}}else a.value=!0}else a.value=!1,D()}));let M=0;return V([()=>e.anchorEl,()=>e.placement,()=>e.content],()=>k(null,null,function*(){const l=++M;if(e.visible&&e.anchorEl&&o.value){if(yield B(),l!==M||!e.visible||!e.anchorEl||!o.value)return;try{const t=yield N();if(l!==M||!e.visible||!e.anchorEl||!o.value)return;t||_()}catch{_()}yield P(()=>l===M)}})),J(()=>{s+=1,D()}),(l,t)=>(O(),Q(ae,{to:"body"},[R("div",{class:le(["markstream-vue",{dark:h.isDark}])},[F(te,{name:"tooltip",appear:""},{default:G(()=>[K(R("div",{id:e.id,ref_key:"tooltip",ref:o,style:L({position:"fixed",left:i.value.left,top:i.value.top,transform:i.value.transform,visibility:a.value?"visible":"hidden",pointerEvents:a.value?void 0:"none"}),class:"tooltip-element",role:"tooltip"},[W(Z(h.content)+" ",1),R("div",{ref_key:"arrowEl",ref:p,class:"tooltip-arrow","data-placement":d.value,style:L(y.value)},null,12,ie)],12,oe),[[ee,h.visible]])]),_:1})],2)]))}}),[["__scopeId","data-v-c606ee4c"]]);export{ue as default};
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}export{e as g};
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
||||||
import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-Dk056XM2.js";import{p as f}from"./chunk-JWPE2WC7-K16PVern.js";import{_ as n,l as o}from"./mermaidParser.worker-BFSlSHEW.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-C-EfYT07.js";var v=d().RailroadAbnf.parser.LangiumParser,l=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),i=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:i,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return l(e.element);case"AbnfOptionalGroup":return{type:"optional",element:l(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:l(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},w={parser:R,db:a,renderer:u,styles:p};export{w as diagram};
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-hIDvr-8C.js";import{p as f}from"./chunk-JWPE2WC7-DTx-f56M.js";import{_ as n,l as o}from"./mermaid.core-Cahi9cr1.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-C5gNr-Q4.js";import"./index-HRJ6xRtC.js";import"./_commonjsHelpers-CqkleIqs.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},F={parser:R,db:a,renderer:u,styles:p};export{F as diagram};
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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