mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-06 15:26:26 +00:00
Compare commits
127 commits
@moonshot-
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9ec566e51 | ||
|
|
51ef78b8c9 | ||
|
|
f0614c53e5 | ||
|
|
794714ebef | ||
|
|
fa3325404b | ||
|
|
03aa66ca0c | ||
|
|
335588e259 | ||
|
|
e6e4ba2357 | ||
|
|
02c026d487 | ||
|
|
cfd14a1fe2 | ||
|
|
4d39f4fa6f | ||
|
|
8c766a6c30 | ||
|
|
ef61084009 | ||
|
|
7b2784b9b7 | ||
|
|
013203421d | ||
|
|
3c75a27da6 | ||
|
|
713bf1a5a2 | ||
|
|
34c4181437 | ||
|
|
7bd3fd9f6e | ||
|
|
d1ded01b7c | ||
|
|
68ba740ebf | ||
|
|
2b893733f9 | ||
|
|
510fbe7ec5 | ||
|
|
6f1cd7ca22 | ||
|
|
858812193a | ||
|
|
7c919f0376 | ||
|
|
53c832dfdf | ||
|
|
2b3e9a9f79 | ||
|
|
7a631522fb | ||
|
|
421e8f8065 | ||
|
|
3bd098b806 | ||
|
|
75fe068a01 | ||
|
|
f881cdd970 | ||
|
|
e3570280bd | ||
|
|
2a4990182d | ||
|
|
4e5f36aa66 | ||
|
|
541ddd2d89 | ||
|
|
e7d5a0aee7 | ||
|
|
2ee6e43124 | ||
|
|
8db7d42f23 | ||
|
|
98ee35afd2 | ||
|
|
119a33f7f1 | ||
|
|
74c321e4c6 | ||
|
|
96f77fe392 | ||
|
|
3126422757 | ||
|
|
aec755fad6 | ||
|
|
c32e661faa | ||
|
|
0abcd00f7f | ||
|
|
da6646bf57 | ||
|
|
278b6af19d | ||
|
|
85e4cf0346 | ||
|
|
c2e53aef6c | ||
|
|
2c3c5a5879 | ||
|
|
af43c5226d | ||
|
|
54c04bf03d | ||
|
|
4ac7240fff | ||
|
|
6cb615cd37 | ||
|
|
c39687318c | ||
|
|
f412e105b3 | ||
|
|
1328b32037 | ||
|
|
21185447fe | ||
|
|
c27a9f93a6 | ||
|
|
98ef0f0b2f | ||
|
|
6ba75a173b | ||
|
|
071b6a50d9 | ||
|
|
75395f6abb | ||
|
|
dfc55a5c97 | ||
|
|
29c9e2ab20 | ||
|
|
e6a655e101 | ||
|
|
3e425212b6 | ||
|
|
e22479a62e | ||
|
|
a5960b3905 | ||
|
|
bfa00807c9 | ||
|
|
7648874730 | ||
|
|
eaab2b6f28 | ||
|
|
6b56c11697 | ||
|
|
326e1fb6ce | ||
|
|
1f3f5dadaa | ||
|
|
302b2cd680 | ||
|
|
44d34bbd56 | ||
|
|
4c4df1bb05 | ||
|
|
32d693f644 | ||
|
|
071d56940f | ||
|
|
e111c878fd | ||
|
|
95a656ca61 | ||
|
|
ed7a4cc095 | ||
|
|
bb2919eb81 | ||
|
|
17dfd49768 | ||
|
|
5c0ec2938a | ||
|
|
f1a3475ad5 | ||
|
|
d8f455d694 | ||
|
|
479403e701 | ||
|
|
0f3b106c42 | ||
|
|
ea81c9a3c5 | ||
|
|
bc28e9d802 | ||
|
|
6d0a046488 | ||
|
|
d36f4c58f6 | ||
|
|
d10b1c1308 | ||
|
|
40172c7ca9 | ||
|
|
691ec4679e | ||
|
|
fa2c5ce18b | ||
|
|
1896d1a13a | ||
|
|
02d77b20d9 | ||
|
|
dbb69a2678 | ||
|
|
f8ec3d1656 | ||
|
|
b850c5f8f5 | ||
|
|
37d9bdc585 | ||
|
|
efac96c8a9 | ||
|
|
16c7189bd5 | ||
|
|
973e2a008c | ||
|
|
67dd03149f | ||
|
|
ceaa96942b | ||
|
|
f79fde2b90 | ||
|
|
d88b3775c9 | ||
|
|
de0ba9d065 | ||
|
|
d03a4886fd | ||
|
|
b0f43aea28 | ||
|
|
cdbd33c13c | ||
|
|
e556088458 | ||
|
|
425cfdf53f | ||
|
|
7e30add445 | ||
|
|
77618e38c3 | ||
|
|
29783e471a | ||
|
|
a77ee03829 | ||
|
|
086769bfad | ||
|
|
3b017821cf | ||
|
|
a9af42e698 |
2637 changed files with 152878 additions and 92758 deletions
|
|
@ -14,7 +14,7 @@ description: Use when developing in packages/agent-core-v2 (the DI × Scope agen
|
|||
```text
|
||||
Orient → Design → Implement → Test → Verify
|
||||
│ │ │ │ │
|
||||
│ │ │ │ └─ lint:domain · typecheck · test · dep graph · red lines
|
||||
│ │ │ │ └─ lint:imports · typecheck · test · dep graph · red lines
|
||||
│ │ │ └─ test.md
|
||||
│ │ └─ implement.md (+ errors.md · flags.md · permission.md)
|
||||
│ └─ design.md
|
||||
|
|
@ -46,7 +46,7 @@ End-to-end procedures that span the stages. Reach for these before reading the s
|
|||
- Topic: [Permission](permission.md) — risk-only chain-of-responsibility kernel, harness constraints and product reviews as domain `onBeforeExecuteTool` veto listeners (`veto` / `allow` / `pass` / cold `waitUntil` factories), shared `toolApproval` round-trip, policy registry + composer, `modes`/`agentTypes` metadata, `resolveExecution`/`accesses`.
|
||||
- Topic: [Telemetry](telemetry.md) — emitting events via `ITelemetryService`, context propagation, and appender destinations (`ConsoleAppender` / `CloudAppender`).
|
||||
- [Stage 4 — Test](test.md): resolve the system under test by interface, pick `TestInstantiationService` vs `createScopedTestHost`, shared stubs, service groups, teardown.
|
||||
- [Stage 5 — Verify & submit](verify.md): `lint:domain`, `typecheck`, `test`, and the pre-submit checklist.
|
||||
- [Stage 5 — Verify & submit](verify.md): `lint:imports`, `typecheck`, `test`, and the pre-submit checklist.
|
||||
|
||||
## How to use this skill
|
||||
|
||||
|
|
@ -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)
|
||||
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)
|
||||
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` (kept domain-agnostic — never add cron/flags/model state); 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 `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)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ v1 is a **VSCode-style singleton container**: services self-register with `regis
|
|||
|---|---|---|
|
||||
| Registration | `registerSingleton(IX, X, InstantiationType.Delayed)` | `registerScopedService(LifecycleScope.X, IX, X, ScopeActivation.OnDemand, 'domain')` |
|
||||
| DI import | `from '../../di'` | `from '#/_base/di/scope'` / `'#/_base/di/instantiation'` / `'#/_base/di/lifecycle'` |
|
||||
| Lifetime | implicit singleton-per-container | explicit `LifecycleScope` (App/Session/Agent) — see orient.md |
|
||||
| Lifetime | implicit singleton-per-container | explicit `LifecycleScope` (App/Workspace/Session/Agent) — see orient.md |
|
||||
| Domain granularity | coarse (`session`, `tool`, `loop`) | fine, split by scope + responsibility |
|
||||
| Test import | `from '@moonshot-ai/agent-core/di/test'` | `from '#/_base/di/test'` |
|
||||
| Resolve SUT in tests | `ix.createInstance(Impl)` (common) | `ix.get(IX)` by interface — see test.md |
|
||||
|
|
@ -63,7 +63,7 @@ Worked example — v1 `ISessionService` (one class, ~600 lines) holds:
|
|||
- this session's metadata → **per-session** unit → v2 `sessionMetaStore` (`ISessionMetaStore`, Session);
|
||||
- this session's activity / status → **per-session** unit → v2 `sessionActivity`;
|
||||
- this session's context projection → **per-session** unit → v2 `sessionContext`;
|
||||
- child-agent lifecycle driven by a session → **per-session** unit → v2 `agentLifecycle`; create/close/archive/fork of the session itself → **global** unit → v2 `sessionLifecycle` (App).
|
||||
- child-agent lifecycle driven by a session → **per-session** unit → v2 `agentLifecycle`; create/close/archive/fork of the session itself → **per-workspace** unit → v2 `sessionLifecycle` (Workspace, one per live workspace handler).
|
||||
|
||||
A v1 class that maps cleanly to one v1 decorator often becomes **three to five** v2 Services. That is expected and correct — do not try to keep the v1 class shape.
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ Re-wire the dependencies you inventoried in step 1, now across the new v2 Servic
|
|||
- **Domain direction** — foundational layers must not know upstream ones. A cycle means a v1 relative import is now pointing the wrong way; extract a third Service or invert the notification into an event.
|
||||
- **Durable facts** — state changes that must be recorded / replayed / projected across agents go on the wire (`wireRecord`), not a direct call alone.
|
||||
|
||||
Run `lint:domain` (verify.md) as soon as the dependencies compile — it catches direction violations early.
|
||||
Run `lint:imports` (verify.md) as soon as the dependencies compile — it catches v1 imports and kosong boundary violations early.
|
||||
|
||||
### 7. Port the business logic
|
||||
|
||||
|
|
@ -157,7 +157,8 @@ import { InstantiationType, registerSingleton } from '../../di';
|
|||
registerSingleton(IXxxService, XxxService, InstantiationType.Delayed);
|
||||
|
||||
// v2
|
||||
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
import { LifecycleScope } from '#/app/scopes';
|
||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
registerScopedService(LifecycleScope.Session, IXxxService, XxxService, ScopeActivation.OnDemand, 'xxx');
|
||||
```
|
||||
|
||||
|
|
@ -188,7 +189,7 @@ import { KimiError, type ErrorCode } from '#/_base/errors';
|
|||
Red lines:
|
||||
|
||||
- Do not copy a v1 file and "fix imports". Re-split first (steps 2–6); a straight copy carries v1's implicit-singleton assumptions into v2 and creates the `Map<sessionId, …>`-at-`App` anti-pattern.
|
||||
- Do not leave v1 relative imports (`from '../x/...'`) in v2 — use the `#/...` alias and respect the domain layers.
|
||||
- Do not leave v1 relative imports (`from '../x/...'`) in v2 — use the `#/...` alias.
|
||||
- Do not preserve a v1 behavior just because it exists; if the split reveals it was a workaround for the missing scope tree, drop it.
|
||||
|
||||
### 8. Port the tests
|
||||
|
|
@ -218,7 +219,7 @@ const svc = ix.get(IXxxService);
|
|||
Before submitting a port:
|
||||
|
||||
- [ ] Every piece of v1 state landed in a v2 Service whose scope matches its identity (no `Map<sessionId, …>` at `App`).
|
||||
- [ ] Each v1 dependency now points in the right scope and domain direction; `lint:domain` passes.
|
||||
- [ ] Each v1 dependency now points in the right scope direction; `lint:imports` passes.
|
||||
- [ ] Registrations use `registerScopedService` with an explicit scope and domain name; no `registerSingleton` remains.
|
||||
- [ ] Imports use the `#/...` alias; no v1 relative (`../../di`, `../../errors`) imports remain.
|
||||
- [ ] Errors are co-located coded errors; flags go through `IFlagService`.
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Keep the recommendation to the commit's footprint. If it keeps growing, that is
|
|||
|
||||
### 6. Verify
|
||||
|
||||
Point at the checks that cover the fix, per [verify.md](verify.md): `lint:domain`, `typecheck`, and the relevant `test`. Note the expected outcome rather than asserting you ran it if you did not.
|
||||
Point at the checks that cover the fix, per [verify.md](verify.md): `lint:imports`, `typecheck`, and the relevant `test`. Note the expected outcome rather than asserting you ran it if you did not.
|
||||
|
||||
## Output shape
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## What belongs in Config
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ A value belongs in Config **iff** it satisfies all of:
|
|||
If it fails any rule, it is not Config:
|
||||
|
||||
- **Fact** (CI, platform, proxy, `HOME`) → a structured fact on
|
||||
`IBootstrapService` (the L1 startup snapshot), not Config.
|
||||
`IBootstrapService` (the startup snapshot), not Config.
|
||||
- **Derived convention** (`configPath`, `logsDir`) → `IBootstrapService` / code.
|
||||
- **Session runtime state** (active model, plan mode) → a Session-scoped
|
||||
service in the owning domain (e.g. `IProfileService`), not `config`.
|
||||
|
|
@ -42,9 +42,16 @@ If it fails any rule, it is not Config:
|
|||
|
||||
**`IBootstrapService` is domain-agnostic.** It holds only generic facts shared by
|
||||
all domains — the env bag, resolved paths, and host facts (`platform`, `arch`,
|
||||
`cwd`, `osHomeDir`, `isCI`, …). It must **never** hold state tied to a specific
|
||||
upper domain (no `cron`, no `flags`, no feature-specific fields): that couples
|
||||
the foundational layer to an upstream one.
|
||||
`cwd`, `osHomeDir`, `isCI`, …) — plus the host's process-level invocation
|
||||
arguments in `args` (explicit `agentFiles` / `skillDirs`, `requestHeaders`,
|
||||
prompt identity). `args` mirrors VS Code's `NativeParsedArgs` on the
|
||||
environment service: the host states them once via `BootstrapInput.args` at
|
||||
the composition root, and downstream services read them from
|
||||
`IBootstrapService.args` instead of through per-domain runtime-options
|
||||
services (do not add new `IXxxRuntimeOptions` services or seed functions for
|
||||
host parameters). What must **never** land on `IBootstrapService` is state
|
||||
tied to a specific upper domain (no `cron`, no `flags`, no feature-specific
|
||||
fields): that couples the foundational layer to an upstream one.
|
||||
|
||||
Any value that belongs to a specific domain — including env-only operational
|
||||
toggles (`KIMI_CRON_*`, `KIMI_CODE_EXPERIMENTAL_*`), model parameters, or feature
|
||||
|
|
@ -86,13 +93,15 @@ pass `ConfigTarget.Memory` for a per-run override that is never written to disk.
|
|||
|
||||
## Layout
|
||||
|
||||
- `src/config/config.ts` — `IConfigRegistry` / `IConfigService` tokens, `ConfigSection`, `ConfigEffectiveOverlay`, event types.
|
||||
- `src/config/configService.ts` — `ConfigRegistry` + `ConfigService` impl; self-registers at App scope.
|
||||
- `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/profile/thinking.ts` (owner domain, not `config`) — the `resolveThinkingEffort` helper; uses the authoritative `ThinkingConfig` from `configSection.ts`.
|
||||
- `src/config/configPure.ts` — `isPlainObject`, `deepMerge`, `omitUndefined`, `describeUnknownError`.
|
||||
- `src/app/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/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/app/config/configOverlayContributions.ts` — the module-level `registerConfigOverlay` collector for `ConfigEffectiveOverlay`s (drained at construction like the sections).
|
||||
- `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/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/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`).
|
||||
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`).
|
||||
|
||||
## Scope
|
||||
|
||||
|
|
@ -110,10 +119,15 @@ 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).
|
||||
- `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:
|
||||
|
||||
- **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` (L2) from importing higher domains: `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.
|
||||
- **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).
|
||||
- **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.
|
||||
|
||||
## Env bindings
|
||||
|
|
@ -124,7 +138,7 @@ Declare the bindings with `envBindings(schema, { … })` — the field names are
|
|||
type-checked against the schema (no magic strings), and nested schemas recurse:
|
||||
|
||||
```ts
|
||||
registerSection('thinking', ThinkingConfigSchema, {
|
||||
registerConfigSection('thinking', ThinkingConfigSchema, {
|
||||
env: envBindings(ThinkingConfigSchema, {
|
||||
effort: 'KIMI_MODEL_THINKING_EFFORT',
|
||||
}),
|
||||
|
|
@ -132,7 +146,7 @@ registerSection('thinking', ThinkingConfigSchema, {
|
|||
|
||||
// nested / record section — outer key is a runtime constant, inner fields are
|
||||
// checked against the value schema:
|
||||
registerSection('providers', ProvidersSectionSchema, {
|
||||
registerConfigSection('providers', ProvidersSectionSchema, {
|
||||
env: envBindings(ProvidersSectionSchema, {
|
||||
[ENV_MODEL_PROVIDER_KEY]: envBindings(ProviderConfigSchema, {
|
||||
apiKey: 'KIMI_MODEL_API_KEY',
|
||||
|
|
@ -145,15 +159,18 @@ registerSection('providers', ProvidersSectionSchema, {
|
|||
```
|
||||
|
||||
Each field is an `EnvBinding` — a string (env var name) or
|
||||
`{ env, parse?, default? }`. IConfig resolves every field by
|
||||
`{ env, deprecatedEnv?, parse?, default? }`. IConfig resolves every field by
|
||||
`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
|
||||
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`
|
||||
persists, so env overrides never leak into `config.toml`. `raw` is the section's
|
||||
env-free camelCase base (already `fromToml`-normalized, so legacy key renames
|
||||
are honored), and `getEnv` reads the live env bag. For fields that are **both
|
||||
env-free camelCase base (already `fromToml`-normalized), and `getEnv` reads the
|
||||
live env bag. For fields that are **both
|
||||
user-persistable and env-overridable**, register
|
||||
`stripEnv: stripEnvBoundFields(sectionEnvBindings)` (from `#/app/config/config`)
|
||||
— it derives the guard from the same bindings the read path uses: while a
|
||||
|
|
@ -174,21 +191,27 @@ never write their own env-merge logic.
|
|||
export const MySectionSchema = z.object({ /* ... */ });
|
||||
export type MySection = z.infer<typeof MySectionSchema>;
|
||||
```
|
||||
2. In the domain's service constructor, inject `IConfigRegistry` and register:
|
||||
2. Register it at the top level of the same module (import = register):
|
||||
```ts
|
||||
constructor(@IConfigRegistry registry: IConfigRegistry) {
|
||||
registry.registerSection(MY_SECTION, MySectionSchema, { defaultValue: {} });
|
||||
}
|
||||
// src/<domain>/configSection.ts
|
||||
import { registerConfigSection } from '#/app/config/configSectionContributions';
|
||||
|
||||
registerConfigSection(MY_SECTION, MySectionSchema, { defaultValue: {} });
|
||||
```
|
||||
Pick a service whose scope matches when the config is first needed. Registering from an Agent-scope service is fine — see "Late registration".
|
||||
3. Read it anywhere via `IConfigService`:
|
||||
`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.
|
||||
3. (Runtime variant) a dynamically loaded unit (e.g. one assembled through `IFeatureManager`) contributes the section as a collection record instead:
|
||||
```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
|
||||
constructor(@IConfigService private readonly config: IConfigService) {}
|
||||
// ...
|
||||
const value = this.config.get<MySection>(MY_SECTION);
|
||||
```
|
||||
4. React to edits by subscribing `IConfigService.onDidChange` and filtering on `e.domain === MY_SECTION` (see `FlagService`).
|
||||
5. Write it only through `IConfigService.set(domain, patch)` (merge) or `.replace(domain, value)` (wholesale). Never write `config.toml` directly.
|
||||
5. 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.
|
||||
|
||||
## Reads vs writes
|
||||
|
||||
|
|
@ -212,11 +235,11 @@ So `configure(...)` never overwrites the local file. Treat `config.toml` as the
|
|||
|
||||
## Late registration
|
||||
|
||||
`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:
|
||||
`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:
|
||||
|
||||
- `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.
|
||||
- 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`.
|
||||
- `IConfigRegistry` emits `onDidRegisterSection` whenever a section is registered (and `onDidUnregisterSection` when a runtime record is withdrawn).
|
||||
- `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.
|
||||
- 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`.
|
||||
|
||||
This means registration order is never a correctness concern — you do not need an eager bootstrap.
|
||||
|
||||
|
|
@ -224,7 +247,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:
|
||||
|
||||
- **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.
|
||||
- **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.
|
||||
- **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:
|
||||
|
|
@ -234,13 +257,30 @@ 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.
|
||||
- `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
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## 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 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.
|
||||
`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.
|
||||
|
||||
## Ownership map (generated)
|
||||
|
||||
|
|
@ -251,22 +291,22 @@ The authoritative, always-current list of registered sections — rendered in th
|
|||
|
||||
`config` must not import from any of these owner domains; that is the whole reason the schemas, TOML normalization, and env overlays live with their owners.
|
||||
|
||||
## Layering & scope
|
||||
## Scope & dependencies
|
||||
|
||||
- `config` is **L2**. Domains that own sections import `config` (for `IConfigRegistry` / `IConfigService`) and must be at L2 or higher; lower layers need an entry in `ALLOWED_EXCEPTIONS` (e.g. `kosong>config`, `kosong>provider`).
|
||||
- Cross-domain type sharing for a config type may need an exception too (e.g. `plugin>mcp` for `McpServerConfig`). Prefer importing the type from the owning domain over re-declaring it.
|
||||
- `config` is a low-level capability: domains that own sections import `config` (for `IConfigRegistry` / `IConfigService`), never the reverse — section schemas live in the owning domain.
|
||||
- Cross-domain type sharing for a config type: prefer importing the type from the owning domain over re-declaring it (e.g. `plugin` imports `McpServerConfig` from the MCP config schema).
|
||||
- `IConfigRegistry` / `IConfigService` are **App**. Agent scope services may inject App services via ancestor lookup.
|
||||
- `config` never imports a higher domain and holds no section schemas of its own; if a section needs a type from another domain, that schema lives in that domain.
|
||||
|
||||
## Red lines (this topic)
|
||||
|
||||
- One owner per section; `registerSection` throws on duplicate domains.
|
||||
- `config` (L2) never imports a higher domain — keep section schemas in the owning domain.
|
||||
- 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.
|
||||
- `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.
|
||||
- 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: never add state tied to a specific upper domain (cron, flags, model params, …). Domain-specific config goes through `registerSection` + `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 `registerConfigSection` + `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.
|
||||
- `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.
|
||||
- Never persist env overlays (`__kimi_env__` / `__kimi_env_model__` / shell API key / experimental env); overlays live only in `effective` / `Memory`.
|
||||
- Registering from an Agent-scope service is fine — the late-registration mechanism keeps validation correct; do not add an eager bootstrap.
|
||||
- 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).
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ A Service = a bundle of **state** + a set of **behaviors**, bound to a **lifetim
|
|||
| Scope | State identity (keyed by) | Lifetime |
|
||||
|---|---|---|
|
||||
| `App` | none (single global instance) | the process |
|
||||
| `Workspace` | `workspaceId` | one workspace handler (materialized once per workspace, never closed — dies with the process) |
|
||||
| `Session` | `sessionId` | one session |
|
||||
| `Agent` | `agentId` | one agent |
|
||||
|
||||
|
|
@ -33,6 +34,7 @@ A Service = a bundle of **state** + a set of **behaviors**, bound to a **lifetim
|
|||
**Q2. What is the identity of that state?**
|
||||
|
||||
- one global instance → **`App`**
|
||||
- one per workspace (shared by every session of that workspace) → **`Workspace`**
|
||||
- one per session → **`Session`**
|
||||
- one per agent → **`Agent`**
|
||||
- a mix (a global registry *and* per-instance state) → **split it** (see §3).
|
||||
|
|
@ -70,7 +72,7 @@ The standard split is "global registry / factory" + "per-instance":
|
|||
| Tier | Role | Naming tends to |
|
||||
|---|---|---|
|
||||
| `App` | global registry / catalog / factory — knows "all of them" and how to create one | `XxxStore` / `XxxRegistry` / `XxxCatalog` |
|
||||
| `Session` / `Agent` | one instance — only the state of "this one" | `XxxService` / `ISessionXxx` / `IAgentXxx` |
|
||||
| `Workspace` / `Session` / `Agent` | one instance — only the state of "this one" | `XxxService` / `IWorkspaceXxx` / `ISessionXxx` / `IAgentXxx` |
|
||||
|
||||
Canonical splits in the codebase:
|
||||
|
||||
|
|
@ -128,6 +130,8 @@ 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 |
|
||||
| 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.
|
||||
|
||||
## 5. Dependency direction
|
||||
|
|
@ -145,25 +149,17 @@ Add one anti-rot heuristic to keep the graph from collapsing into a clique:
|
|||
|
||||
Once a foundational component knows about an upstream scenario, it can no longer be reused by other scenarios and will almost always create a cycle.
|
||||
|
||||
### The natural layers of this repo
|
||||
### The boundaries of this repo
|
||||
|
||||
`agent-core-v2` is stratified into eight dependency layers, **L0–L7** (the `Ln` number in file headers — see orient.md for the full table and the representative domains). A domain at layer `L` may import only domains at layer `<= L`; lower layers never reach upward. `lint:domain` enforces this from the `DOMAIN_LAYER` map in `scripts/check-domain-layers.mjs`.
|
||||
`agent-core-v2` has no mechanical domain-layer numbering — dependency direction is the judgment rule above, applied per domain. What remains enforceable is a small set of specific boundaries (`lint:imports`, `scripts/check-import-boundaries.mjs`):
|
||||
|
||||
The tiers, from lowest to highest:
|
||||
- v2 never imports v1 (`@moonshot-ai/agent-core`).
|
||||
- The kosong subtree keeps its strict internal order (`contract ← protocol ← provider/model`, purity bans, the `provider/bases` registration boundary).
|
||||
|
||||
- **L0 — base infrastructure** (`_base`, errors, wire types).
|
||||
- **L1 — bridges & low-level capabilities** (logging, telemetry, event bus, environment, storage).
|
||||
- **L2 — data & cross-cutting capabilities** (records, config, providers, auth, workspace registry).
|
||||
- **L3 — registries & capabilities** (tools, permissions, flags, skills, plugins).
|
||||
- **L4 — agent behaviour** (turn, loop, prompt, profile, context, goal, plan, swarm).
|
||||
- **L5 — async lifecycle** (background, MCP, cron, sub-agent tools).
|
||||
- **L6 — coordination** (session, agent/session lifecycle, interactions, terminal).
|
||||
- **L7 — boundary / edge** (`gateway`, `rpc`, approval/question, the `*Legacy` v1 adapters).
|
||||
Two standing red lines on top of that:
|
||||
|
||||
Red lines:
|
||||
|
||||
- The **L0/L1 substrate** never imports a higher business layer.
|
||||
- Business logic never depends on the **L7 edge** layer — business code should not know REST / WebSocket exist.
|
||||
- The **base substrate** (`_base`, errors, wire types) never depends on any business domain.
|
||||
- Business logic never depends on the **edge** (`gateway`, `rpc`, the `*Legacy` v1 adapters) — business code should not know REST / WebSocket exist.
|
||||
- A cycle means knowledge was placed backwards: extract a third, more foundational Service, or invert the "notification" half into an event.
|
||||
|
||||
> Capability → orchestrator (e.g. `prompt → turn`) is allowed and present in this repo; the real red line is *inverted reuse* — a foundational / lower Service depending on a specific / upper one.
|
||||
|
|
@ -189,8 +185,9 @@ domain: `<name>` (owning scope: <Scope>)
|
|||
│ └─ (accessor) <ConsumerDomain> @<Scope> — <what they use me for>
|
||||
├─ exposes (interfaces I provide, by scope)
|
||||
│ ├─ App : <IXxxRegistry> — <role>
|
||||
│ ├─ Session : <ISessionXxx> — <role>
|
||||
│ └─ Agent : <IAgentXxx> — <role>
|
||||
│ ├─ Workspace : <IWorkspaceXxx> — <role>
|
||||
│ ├─ Session : <ISessionXxx> — <role>
|
||||
│ └─ Agent : <IAgentXxx> — <role>
|
||||
└─ depends (what I inject) tag = calling style
|
||||
└─ <DepDomain> @<Scope> direct/event/hook — <what for>
|
||||
```
|
||||
|
|
@ -228,42 +225,49 @@ Read it as:
|
|||
Worked example — `sessionLifecycle`:
|
||||
|
||||
```text
|
||||
domain: `sessionLifecycle` (owning scope: App)
|
||||
domain: `sessionLifecycle` (owning scope: Workspace)
|
||||
├─ serves (who uses me)
|
||||
│ ├─ (inject) — (none yet)
|
||||
│ ├─ (inject) — (none)
|
||||
│ └─ (accessor)
|
||||
│ ├─ sessionLegacy @App(edge) — v1-compatible create/fork/archive/…
|
||||
│ └─ gateway / rpc @App(edge) — native v2 session lifecycle actions
|
||||
├─ exposes (interfaces I provide, by scope)
|
||||
│ ├─ App : ISessionLifecycleService — owns the live session scope tree
|
||||
│ ├─ Workspace : ISessionLifecycleService — owns this workspace's live session scope tree
|
||||
│ ├─ Session : — — (per-session state lives in sessionMetadata / agentLifecycle / …)
|
||||
│ └─ Agent : — — (per-agent state lives in agentLifecycle)
|
||||
└─ depends (what I inject)
|
||||
├─ bootstrap @App direct — addresses session storage
|
||||
├─ hostEnvironment @App direct — gates scope creation on the probe
|
||||
├─ sessionIndex @App direct — persisted read model for cold resumes
|
||||
├─ storage @App direct — atomic docs + append logs
|
||||
├─ workspace @App direct — resolves a session's workspace
|
||||
└─ event @App direct — broadcasts session-level facts (e.g. archived)
|
||||
├─ workspaceContext @Workspace seed — handler identity + persistence scope
|
||||
├─ bootstrap @App direct — addresses session storage
|
||||
├─ hostEnvironment @App direct — gates scope creation on the probe
|
||||
├─ sessionIndex @App direct — persisted read model for cold resumes
|
||||
├─ storage @App direct — atomic docs + append logs
|
||||
├─ workspaceDirs / workspaceSkillCatalog / workspaceMcp / …
|
||||
│ @Workspace direct — the handler's shared resource services
|
||||
└─ event @App direct — broadcasts session-level facts (e.g. archived)
|
||||
```
|
||||
|
||||
Cross-scope borrow for `sessionLifecycle`:
|
||||
|
||||
```text
|
||||
App scope
|
||||
SessionLifecycleService ──holds──┐
|
||||
GatewayService ───────────holds──┼──► IScopeHandle(sessionId)
|
||||
│
|
||||
│ accessor.get(ISessionMetadata) …
|
||||
│ └── resolve runs inside the Session scope
|
||||
▼
|
||||
Session scope (sessionId)
|
||||
sessionMetadata / agentLifecycle / … ← per-session services live here
|
||||
WorkspaceLifecycleService ──holds──► IScopeHandle(workspaceId) (one per live handler)
|
||||
│
|
||||
│ accessor.get(ISessionLifecycleService)
|
||||
│ └── resolve runs inside the Workspace scope
|
||||
▼
|
||||
Workspace scope (workspaceId)
|
||||
SessionLifecycleService ──holds──► IScopeHandle(sessionId)
|
||||
│
|
||||
│ accessor.get(ISessionMetadata) …
|
||||
│ └── resolve runs inside the Session scope
|
||||
▼
|
||||
Session scope (sessionId)
|
||||
sessionMetadata / agentLifecycle / … ← per-session services live here
|
||||
```
|
||||
|
||||
How the three lenses shaped it:
|
||||
|
||||
- **Scope (§2)** → the live registry of session scopes is process-wide, so it is App-scoped; per-session data stays in Session-scoped services, reached through the handle's `accessor`.
|
||||
- **Scope (§2)** → the live registry of one workspace's session scopes is per-handler, so it is Workspace-scoped; the process-wide handler registry lives in the App-scoped `workspaceLifecycle`; per-session data stays in Session-scoped services, reached through the handle's `accessor`.
|
||||
- **Dependency direction (§5)** → `sessionLifecycle` is consumed by the edge via `accessor` borrows; it never imports the edge. Every downward arrow lands on a peer or a more foundational Service.
|
||||
- **Extension points (§4)** → new per-session behavior plugs into the Session-scoped services (`sessionMetadata`, `agentLifecycle`, `sessionActivity`); new transports stay at the edge. Neither edits `sessionLifecycle`.
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ The `session` domain owns only Session-level identity, metadata, lifecycle comma
|
|||
|---|---|---|
|
||||
| `sessionId`, `workspaceId`, `sessionDir`, `metaScope` | `sessionContext` | Seeded facts; no IO |
|
||||
| `SessionMeta` | `sessionMetadata` | Durable atomic document; entity-like |
|
||||
| Open session scope registry | `sessionLifecycle` | App-scope live handles; not the persisted entity table |
|
||||
| Open session scope registry | `sessionLifecycle` | Workspace-scope live handles, one registry per workspace handler (the process-wide handler registry is `workspaceLifecycle`); not the persisted entity table |
|
||||
| Session commands such as `archive()` | `session` | Orchestrates metadata, agent teardown, and events |
|
||||
| Persisted session list / get / count | `sessionIndex` | Backend-neutral read model |
|
||||
| Running / idle / awaiting status | `sessionActivity` | Derived from interactions and active turns; owns no state |
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ The transport (`/api/v2` over HTTP + WS) lives in the **edge** layer (`gateway`/
|
|||
|
||||
## 1. The edge model
|
||||
|
||||
Three scopes, three URL shapes, one dispatcher:
|
||||
Four scopes, four URL shapes, one dispatcher:
|
||||
|
||||
```text
|
||||
GET|POST /api/v2/:sa Core
|
||||
GET|POST /api/v2/workspace/:workspace_id/:sa Workspace
|
||||
GET|POST /api/v2/session/:session_id/:sa Session
|
||||
GET|POST /api/v2/session/:session_id/agent/:agent_id/:sa Agent
|
||||
```
|
||||
|
|
@ -26,9 +27,10 @@ GET|POST /api/v2/session/:session_id/agent/:agent_id/:sa Agent
|
|||
```ts
|
||||
// actionMap — the allowlist; hides internal domain names.
|
||||
const actionMap = {
|
||||
core: { 'sessions:list': { service: ISessionIndex, method: 'list' }, ... },
|
||||
session: { 'session:read': { service: ISessionMetadata, method: 'read' }, ... },
|
||||
agent: { 'profile:getModel': { service: IProfileService, method: 'getModel' }, ... },
|
||||
core: { 'sessions:list': { service: ISessionIndex, method: 'list' }, ... },
|
||||
workspace: { 'skills:list': { service: IWorkspaceSkillCatalog, method: 'list' }, ... },
|
||||
session: { 'session:read': { service: ISessionMetadata, method: 'read' }, ... },
|
||||
agent: { 'profile:getModel': { service: IProfileService, method: 'getModel' }, ... },
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -53,9 +55,9 @@ Read = `GET`, write = `POST`. `sid` = `session_id`, `aid` = `agent_id`.
|
|||
|
||||
| resource | action | Service.method | verb |
|
||||
|---|---|---|---|
|
||||
| `sessions` | `list` | ISessionIndex.list | GET |
|
||||
| `sessions` | `listRecent` | ISessionIndex.listRecent | GET |
|
||||
| `sessions` | `get` | ISessionIndex.get | GET |
|
||||
| `sessions` | `countActive` | ISessionIndex.countActive | GET |
|
||||
| `sessions` | `count` | ISessionIndex.count | GET |
|
||||
| `workspaces` | `list` | IWorkspaceService.list | GET |
|
||||
| `workspaces` | `get` | IWorkspaceService.get | GET |
|
||||
| `workspaces` | `createOrTouch` | IWorkspaceService.createOrTouch | POST |
|
||||
|
|
@ -90,7 +92,7 @@ Read = `GET`, write = `POST`. `sid` = `session_id`, `aid` = `agent_id`.
|
|||
| `questions` | `answer` | IQuestionService.answer | POST |
|
||||
| `interactions` | `listPending` | IInteractionService.listPending | GET |
|
||||
| `interactions` | `respond` | IInteractionService.respond | POST |
|
||||
| `workspace` | `setWorkDir` / `addAdditionalDir` / `removeAdditionalDir` / `resolve` | IWorkspaceContext.* | GET/POST |
|
||||
| `workspace` | `workDir` / `additionalDirs` / `resolve` | ISessionWorkspaceContext.* | GET |
|
||||
|
||||
### Agent (`/api/v2/session/:sid/agent/:aid/:resource:action`)
|
||||
|
||||
|
|
@ -103,7 +105,7 @@ Read = `GET`, write = `POST`. `sid` = `session_id`, `aid` = `agent_id`.
|
|||
| `tasks` | `list` / `get` / `readOutput` | IBackgroundService.* | GET |
|
||||
| `tasks` | `stop` / `detach` | IBackgroundService.* | POST |
|
||||
| `usage` | `status` | IUsageService.status | GET |
|
||||
| `context` | `status` | IAgentContextSizeService.get | GET |
|
||||
| `context` | `status` | IAgentTokenCountingService.get | GET |
|
||||
| `swarm` | `isActive` | ISwarmService.isActive | GET |
|
||||
| `swarm` | `enter` / `exit` | ISwarmService.* | POST |
|
||||
| `permission` | `getMode` | IPermissionModeService.mode | GET |
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ Gate not-yet-public features behind `IFlagService.enabled(id)`, per the reposito
|
|||
|
||||
## Layout
|
||||
|
||||
- `src/flag/flagRegistry.ts` — `IFlagRegistry` token + `FlagDefinitionInput` / `FlagId` / `FlagSurface` types + `registerFlagDefinition` / `getContributedFlags` (import-time contribution queue).
|
||||
- `src/flag/flagRegistryService.ts` — `FlagRegistryService` impl; in-memory catalog seeded from import-time contributions; App scope.
|
||||
- `src/flag/flag.ts` — `IFlagService` token + resolver types (`ExperimentalFlagMap`, `ExperimentalFlagConfig`, `ExperimentalFlagSource`, `ExperimentalFeatureState`) + `ExperimentalConfigSchema` / `ExperimentalConfig` (zod).
|
||||
- `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/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` or `src/agent/faultInjection/flag.ts`). The directory already names the domain, so the file is just `flag.ts`.
|
||||
- `src/app/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/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/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/app/flag/index.ts` — **removed (no barrel)**; `src/index.ts` imports the `flag` leafs precisely instead (e.g. `import './app/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`.
|
||||
|
||||
## Public surface
|
||||
|
||||
|
|
@ -33,9 +33,9 @@ Highest wins; env is read live on every call (nothing cached):
|
|||
|
||||
## Config integration
|
||||
|
||||
- `FlagService` registers the `[experimental]` section into `IConfigRegistry` at construction (`registerSection('experimental', ExperimentalConfigSchema)`) and reads overrides from `IConfigService`.
|
||||
- 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`.
|
||||
- It subscribes `IConfigService.onDidChange` and refreshes overrides whenever the `experimental` domain changes, so config edits apply live.
|
||||
- `IConfigRegistry.registerSection` throws if a domain is registered twice — `experimental` is owned exclusively by `FlagService`.
|
||||
- `ConfigRegistry.registerSection` throws if a domain is registered twice — `experimental` is owned exclusively by the flag domain.
|
||||
- `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:
|
||||
|
|
@ -54,7 +54,7 @@ Declare the definition in the owning domain's `flag.ts` and call `registerFlagDe
|
|||
`src/<domain>/flag.ts`:
|
||||
|
||||
```ts
|
||||
import { type FlagDefinitionInput, registerFlagDefinition } from '#/flag';
|
||||
import { type FlagDefinitionInput, registerFlagDefinition } from '#/app/flag/flagRegistry';
|
||||
|
||||
export const myFeatureFlag: FlagDefinitionInput = {
|
||||
id: 'my_feature',
|
||||
|
|
@ -94,8 +94,8 @@ if (!this.flags.enabled('my_feature')) return;
|
|||
|
||||
## Layering & scope
|
||||
|
||||
- Domain `flag` is registered at **L3**. It imports only `config` (L2) downward.
|
||||
- It cannot live in `_base` (L0): registering/reading the config section requires importing `config`, and L0 must not import L2.
|
||||
- Domain `flag` imports only `config` downward.
|
||||
- It cannot live in `_base`: registering/reading the config section requires importing `config`, and `_base` is pure infrastructure that must not know any business domain.
|
||||
- Scope: `IFlagRegistry` and `IFlagService` are both `App`. Env + config are process-global inputs, so there is no per-session/agent state. Flag definitions are contributed at **import time** (top-level `registerFlagDefinition` calls), so they are queued before any scope is created and drained when `FlagRegistryService` is first instantiated — before `IFlagService` is first resolved.
|
||||
- Tests build `FlagService` + `FlagRegistryService` directly with a real `ConfigRegistry`/`ConfigService` and an injected env map, then `register` the flags they exercise.
|
||||
|
||||
|
|
@ -105,4 +105,4 @@ if (!this.flags.enabled('my_feature')) return;
|
|||
- Contribute each flag from the **owning domain's** `flag.ts` (`src/<domain>/flag.ts`) via a top-level `registerFlagDefinition` call; there is no central catalog to edit. The directory names the domain, so the file is just `flag.ts`.
|
||||
- `env` must start with `KIMI_CODE_EXPERIMENTAL_`, be unique, and not equal `KIMI_CODE_EXPERIMENTAL_FLAG`; `id` must not be `flag`.
|
||||
- `FlagId` is `string` (decentralized registration) — do not reintroduce a central `FLAG_DEFINITIONS` array or a derived literal union.
|
||||
- `flag` lives at L3 and `App` scope — never in `_base`, never per-session.
|
||||
- `flag` lives at `App` scope — never in `_base`, never per-session.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ export const IGreeter: ServiceIdentifier<IGreeter> = createDecorator<IGreeter>('
|
|||
|
||||
```ts
|
||||
// greet/greetService.ts
|
||||
import { LifecycleScope, registerScopedService, ScopeActivation } from '#/_base/di/scope';
|
||||
import { LifecycleScope } from '#/app/scopes';
|
||||
import { registerScopedService, ScopeActivation } from '#/_base/di/scope';
|
||||
import { IGreeter } from './greet';
|
||||
|
||||
export class Greeter implements IGreeter {
|
||||
|
|
@ -127,7 +128,8 @@ export class WSBroadcastService extends Disposable implements IWSBroadcastServic
|
|||
|
||||
- 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.
|
||||
- Disposal order is deterministic (orient.md): child scopes first, then reverse construction order within a scope.
|
||||
- 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.
|
||||
- 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
|
||||
|
||||
|
|
@ -160,7 +162,7 @@ registerScopedService(
|
|||
);
|
||||
```
|
||||
|
||||
`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.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.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.
|
||||
|
||||
|
|
@ -168,6 +170,8 @@ 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.
|
||||
|
||||
**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`)
|
||||
|
||||
When you do not want a new class and just need a service once, or when you expose a `ServicesAccessor` to the outside:
|
||||
|
|
@ -198,7 +202,7 @@ class TurnRunner {
|
|||
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.
|
||||
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.
|
||||
|
||||
> 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.
|
||||
|
||||
|
|
@ -234,7 +238,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).
|
||||
- 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). Drop to the manual `ServiceCollection` form only when you need explicit control.
|
||||
> 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.
|
||||
|
||||
## §9 Cyclic dependencies (forbidden — refactor)
|
||||
|
||||
|
|
@ -246,7 +250,7 @@ If A needs B while being created and B needs A while being created, the containe
|
|||
|
||||
### Why cycles are disallowed
|
||||
|
||||
- Scope layering makes normal dependencies a DAG (Agent → Session → App, resolving upward); a cycle is almost always a design smell.
|
||||
- Scope layering makes normal dependencies a DAG (Agent → Session → Workspace → App, resolving upward); a cycle is almost always a design smell.
|
||||
- "Making the cycle happen to work" turns construction order into an implicit contract — hard to debug.
|
||||
|
||||
v2's stance: **the dependency graph must be acyclic.**
|
||||
|
|
@ -276,6 +280,8 @@ Both `ScopeActivation.OnScopeCreated` and `ScopeActivation.OnDemand` construct t
|
|||
| `Disposable` / `DisposableStore` / `IDisposable` | §4 | resource management and disposal |
|
||||
| `Scope` / `LifecycleScope` | §3, §8 | the lifetime tree |
|
||||
| `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 |
|
||||
|
||||
> 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`.
|
||||
|
|
|
|||
|
|
@ -12,27 +12,31 @@ When writing business code you declare three things; the container handles the r
|
|||
|
||||
Classes talk only to interfaces and never care how an implementation is constructed.
|
||||
|
||||
## The three `LifecycleScope` tiers
|
||||
## The four `LifecycleScope` tiers
|
||||
|
||||
Lifetimes form a tree, from longest to shortest:
|
||||
|
||||
```text
|
||||
App (0) process-wide, single global instance
|
||||
└── Session (1) one session
|
||||
└── Agent (2) one agent
|
||||
App process-wide, single global instance
|
||||
└── Workspace one workspace handler (a materialized workspace root)
|
||||
└── Session one session
|
||||
└── Agent one agent
|
||||
```
|
||||
|
||||
```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 {
|
||||
App = 0,
|
||||
Session = 1,
|
||||
Agent = 2,
|
||||
App = 'app',
|
||||
Workspace = 'workspace',
|
||||
Session = 'session',
|
||||
Agent = 'agent',
|
||||
}
|
||||
```
|
||||
|
||||
- A larger number = shorter life = closer to a leaf.
|
||||
- Later in the topology = shorter life = closer to a leaf.
|
||||
- "Singleton" means **one per scope**: `ILogService` is global once; each `Session` scope has its own `ISessionMetadata`.
|
||||
- `kind` strictly increases along the parent→child direction.
|
||||
- `kind` must advance along the declared topology in the parent→child direction.
|
||||
|
||||
### Visibility rule
|
||||
|
||||
|
|
@ -45,35 +49,30 @@ A child scope sees its ancestors; a parent never sees its children. Resolution w
|
|||
|
||||
### Disposal order
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## The `(Ln)` layer number in headers
|
||||
## Dynamic DI: units and cascades
|
||||
|
||||
The `Ln` in a file-header identity line is the domain's **dependency layer** (L0–L7), **not** its `LifecycleScope`. They are easy to confuse because both are small integers, but they answer different questions:
|
||||
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:
|
||||
|
||||
- `LifecycleScope` (App=0 / Session=1 / Agent=2) — **lifetime & visibility** (this stage).
|
||||
- Dependency layer `Ln` (L0–L7) — **who may import whom**: a domain at layer `L` may import only domains at layer `<= L`. Enforced by `lint:domain` from the authoritative `DOMAIN_LAYER` map in `scripts/check-domain-layers.mjs`.
|
||||
- **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.
|
||||
|
||||
So a Session-scoped service is not "L1" — e.g. `session` is Session-scoped but lives at **L6**. When you write the header, read the number from the layer map, not from the scope.
|
||||
## Import boundaries
|
||||
|
||||
| Layer | Role | Representative domains |
|
||||
|---|---|---|
|
||||
| L0 | base infrastructure | `_base`, `errors`, `llmProtocol` |
|
||||
| L1 | bridges & low-level capabilities | `log`, `telemetry`, `event`, `environment`, `bootstrap`, `storage` |
|
||||
| L2 | data & cross-cutting capabilities | `records`, `wireRecord`, `config`, `provider`, `auth`, `workspace` |
|
||||
| L3 | registries & capabilities | `tool`, `toolRegistry`, `permission*`, `flag`, `skill`, `plugin` |
|
||||
| L4 | agent behaviour | `turn`, `loop`, `prompt`, `profile`, `contextMemory`, `goal`, `plan`, `swarm` |
|
||||
| L5 | async lifecycle | `background`, `mcp`, `cron`, `agentTool` |
|
||||
| L6 | coordination | `session`, `agentLifecycle`, `sessionMetadata`, `interaction`, `terminal`, `undo` |
|
||||
| L7 | boundary / edge | `gateway`, `rpc`, `approval`, `question`, `*Legacy` |
|
||||
There is no domain-layer numbering — a domain may import any other domain, guided by the dependency-direction judgment in design.md. The only mechanically enforced import boundaries are (`lint:imports`, `scripts/check-import-boundaries.mjs`):
|
||||
|
||||
- v2 never imports v1 (`@moonshot-ai/agent-core` or any subpath).
|
||||
- The kosong subtree (`src/kosong/{contract,protocol,provider,model}`) keeps its strict internal order (`contract ← protocol ← provider/model`), purity bans (no SDKs in `contract`/`protocol`), and the `provider/bases` registration boundary.
|
||||
|
||||
## File-header comment convention
|
||||
|
||||
`packages/agent-core-v2/AGENTS.md` mandates a header-only comment style:
|
||||
|
||||
- **Header only.** Comments live solely in the top-of-file `/** */` block — never beside functions, methods, or statements. The code is the source of truth for *how*; the header states *what the module exposes and the responsibility it owns*.
|
||||
- **Identity line first.** Start with `` `<domain>` domain (Ln) — <one-line role>. `` Keep an existing `(cross-cutting)` label as-is. Write the role as a responsibility ("drives the turn lifecycle"), not a symbol list.
|
||||
- **Scope is in the filename.** `session*.ts` = Session, `agent*.ts` = Agent, no prefix = App (see service-authoring.md). State the same scope in the header so the two never drift.
|
||||
- **Identity line first.** Start with `` `<domain>` domain — <one-line role>. `` Keep an existing `(cross-cutting)` label as-is. Write the role as a responsibility ("drives the turn lifecycle"), not a symbol list.
|
||||
- **Scope is in the filename.** `workspace*.ts` = Workspace, `session*.ts` = Session, `agent*.ts` = Agent, no prefix = App (see service-authoring.md). State the same scope in the header so the two never drift.
|
||||
- **Interface files** (`<name>.ts`) state the public contract + scope: which `IXxx` they define and what it is for.
|
||||
- **Impl files** (`<name>Service.ts`) add collaborators + scope: list every imported cross-domain collaborator as a role ("persists records through `records`"); read scope from `registerScopedService(LifecycleScope.X, …)`.
|
||||
- **Contribution files** (`<targetDomain>.ts` / `<what>.contrib.ts`) state what they register into the target domain (e.g. "registers the `log` config section into `config`").
|
||||
|
|
@ -83,7 +82,7 @@ Impl file example (`sessionMetadataService.ts`):
|
|||
|
||||
```ts
|
||||
/**
|
||||
* `sessionMetadata` domain (L6) — `ISessionMetadata` implementation.
|
||||
* `sessionMetadata` domain — `ISessionMetadata` implementation.
|
||||
*
|
||||
* Persists the session metadata document (`state.json`) through the `storage`
|
||||
* access-pattern store (`IAtomicDocumentStore`), rooted at the `metaScope`
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ export interface IAppendLogStore {
|
|||
|
||||
## Platform primitives are deployment-coupled, not core abstractions
|
||||
|
||||
`hostFs` (local filesystem) is a **platform primitive** used only by local backends (`FileStorageService`, `LocalFileSystemBackend`, `LocalSkillCatalog`, `HostFolderBrowser`). It is **not** a core abstraction and must not appear in L2/L3 dependency graphs. A server deployment swaps those backends for DB / S3 implementations and never registers `hostFs`.
|
||||
`hostFs` (local filesystem) is a **platform primitive** used only by local backends (`FileStorageService`, `LocalFileSystemBackend`, `LocalSkillCatalog`, `HostFolderBrowser`). It is **not** a core abstraction and must not appear in business-domain dependency graphs. A server deployment swaps those backends for DB / S3 implementations and never registers `hostFs`.
|
||||
|
||||
## Red lines (this topic)
|
||||
|
||||
|
|
@ -199,6 +199,6 @@ export interface IAppendLogStore {
|
|||
- Name generic Stores by access pattern (`IAppendLogStore` / `IAtomicDocumentStore` / `IBlobStore`), never by business concept (`IRecordStore` / `IConfigStore`).
|
||||
- Business-specific Stores (unique query semantics) are named after the domain (`ISessionIndex`).
|
||||
- `IFileSystemStorageService` is the filesystem byte-layer interface; non-filesystem backends implement the **Store** interfaces directly. Route backends by binding a different Store implementation at the composition root, not by overloading `scope`.
|
||||
- `hostFs` is a local-only platform primitive; L2/L3 domains must not import `node:fs` or `hostFs` directly.
|
||||
- `hostFs` is a local-only platform primitive; business domains must not import `node:fs` or `hostFs` directly.
|
||||
- Only the file-backed bootstrap (`FileBootstrapService`) and file backends import `pathe`; business domains do not.
|
||||
- Do not create a pass-through `Store` that only forwards `read/write` — a Store must hide a real access-pattern concern, or it is noise; use `IFileSystemStorageService` directly instead.
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ Resolve the v2 Service that will back the route. Two cases:
|
|||
|
||||
**Case A — the v2 native Service already matches the v1 contract.** Use it directly. Most data/command Services (`IConfigService`, `IWorkspaceService`, `IApprovalService`, `IQuestionService`, `IFileStore`, …) land here: the route is a thin adapter that resolves the scope, calls the method, and wraps the result. Examples: `routes/config.ts`, `routes/messages.ts`, `routes/questions.ts`, `routes/files.ts`.
|
||||
|
||||
**Case B — the v1 contract needs behavior that would distort the v2 domain.** Introduce a **`*LegacyService`** — an L7 edge adapter that implements the v1 contract **on top of** the v2 native Service, leaving the native Service untouched. The v2 native Service keeps serving `/api/v2`; the LegacyService serves `/api/v1`.
|
||||
**Case B — the v1 contract needs behavior that would distort the v2 domain.** Introduce a **`*LegacyService`** — an edge adapter that implements the v1 contract **on top of** the v2 native Service, leaving the native Service untouched. The v2 native Service keeps serving `/api/v2`; the LegacyService serves `/api/v1`.
|
||||
|
||||
Reach for a LegacyService when **any** hold:
|
||||
|
||||
|
|
@ -109,7 +109,8 @@ export const IAgentPromptService: ServiceIdentifier<IAgentPromptService> =
|
|||
|
||||
```ts
|
||||
// promptService.ts — impl delegates to the native v2 Service
|
||||
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
import { LifecycleScope } from '#/app/scopes';
|
||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
|
||||
constructor(@IAgentPromptService private readonly prompt: IAgentPromptService /*, ... */) {}
|
||||
// submit() builds v2-native input, calls the native Service, projects the result
|
||||
|
|
@ -127,7 +128,7 @@ registerScopedService(
|
|||
Conventions:
|
||||
|
||||
- **Name** the domain `<domain>Legacy` and the interface with the scope prefix, `I<Scope><Domain>LegacyService` (e.g. `prompt` / `IAgentPromptService`), per service-authoring.md.
|
||||
- **Header comment** must say it is an `L7 edge adapter` and name both the v1 contract it implements and the native v2 Service it leaves untouched (see `prompt.ts`).
|
||||
- **Header comment** must say it is an `edge adapter` and name both the v1 contract it implements and the native v2 Service it leaves untouched (see `prompt.ts`).
|
||||
- **Scope** = the lifetime of the *legacy* state it holds (the `prompt` queue is per-agent → `LifecycleScope.Agent`). Apply [orient.md](orient.md) / [design.md](design.md) normally — a LegacyService is not exempt from scope rules.
|
||||
- **Delegate, do not duplicate** business logic. The LegacyService translates the v1 contract into native-Service calls and translates results back; the real work stays in the native Service.
|
||||
- **Contract types come from the v1 wire schema homes** (the owning v2 domain contract or `kap-server/src/protocol`), so the interface cannot drift from the wire shape.
|
||||
|
|
@ -206,7 +207,7 @@ Where the route mirrors v1, the test is the regression guard for the schema-fide
|
|||
- `pnpm -C packages/kap-server test` — server routes green.
|
||||
- `pnpm -C packages/kap-server test` — server routes green (incl. any wire-schema guards).
|
||||
- `pnpm -C packages/agent-core-v2 test` — native + Legacy Service tests green.
|
||||
- `pnpm -C packages/agent-core-v2 run lint:domain` — a LegacyService is still inside the domain layers (edge adapter, L7); it must not pull business code into the edge or invert scope direction.
|
||||
- `pnpm -C packages/agent-core-v2 run lint:imports` — the import boundaries (v1 ban, kosong subtree) still hold for a LegacyService.
|
||||
- `pnpm -C packages/klient test` (optionally with `KIMI_SERVER_URL` for the live legacy suites) when a v1 parity scenario exists.
|
||||
|
||||
## Worked example — porting v1 `/sessions/:sid/prompts`
|
||||
|
|
@ -235,11 +236,11 @@ Before submitting a server-align change:
|
|||
- [ ] Request and response schemas come from their owning home (the `agent-core-v2` domain contract or `packages/kap-server/src/protocol`); no inline re-declaration in server-v2.
|
||||
- [ ] Existing schema fields are unchanged in name, type, and semantics; only optional fields added (if any).
|
||||
- [ ] Native v2 Service left clean; v1-only behavior isolated in a `<domain>Legacy` / `I<Domain>LegacyService` edge adapter when the semantics diverge.
|
||||
- [ ] LegacyService registered with the correct `LifecycleScope` and a header comment naming it an L7 edge adapter + the native Service it preserves.
|
||||
- [ ] LegacyService registered with the correct `LifecycleScope` and a header comment naming it an edge adapter + the native Service it preserves.
|
||||
- [ ] Domain error codes registered in `agent-core-v2`; wire codes registered in `packages/kap-server/src/protocol`; route maps them in `sendMappedError`, matching v1's status codes and idempotent envelopes.
|
||||
- [ ] Route resolves the scope from the URL by `accessor.get(IX)`; no cached scope; finishes before disposal.
|
||||
- [ ] Tests assert the wire envelope + protocol shape; wire-shape guards added/updated where the route mirrors v1.
|
||||
- [ ] `lint:domain` passes; the LegacyService did not invert scope or domain direction.
|
||||
- [ ] `lint:imports` passes; the LegacyService did not invert scope direction.
|
||||
|
||||
## Red lines (this subskill)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ One folder per domain, **camelCase**: `session/`, `sessionActivity/`, `contextMe
|
|||
```
|
||||
|
||||
- **Strictly one service per file.** An interface file holds exactly one injectable interface and exactly one `createDecorator(...)`; an impl file holds exactly one service implementation class and exactly one `registerScopedService(...)`. No exceptions for "tightly-coupled" groups: even same-scope collaborators each get their own `<name>.ts` + `<name>Service.ts` pair.
|
||||
- **Scope is in the filename.** `session*.ts` = Session, `agent*.ts` = Agent, no scope prefix = App (see [Naming](#naming)). The header comment restates the same scope.
|
||||
- **Scope is in the filename.** `workspace*.ts` = Workspace, `session*.ts` = Session, `agent*.ts` = Agent, no scope prefix = App (see [Naming](#naming)). The header comment restates the same scope.
|
||||
- A domain therefore has as many impl files as it has services (e.g. `logService.ts` for the App `ILogService`, `sessionLogService.ts` for the Session `ISessionLogService`). See [Multi-Service domains](#multi-service-domains).
|
||||
|
||||
The package entry `src/index.ts` imports and `export *`s every domain's leaf files precisely (one line per leaf), so importing the package still runs every `registerScopedService(...)` side effect — exactly as the old per-domain barrels did.
|
||||
|
|
@ -28,12 +28,12 @@ The package entry `src/index.ts` imports and `export *`s every domain's leaf fil
|
|||
|
||||
| Artifact | Rule | Example |
|
||||
|---|---|---|
|
||||
| Interface | `I` + scope prefix + PascalCase domain + role suffix. Scope prefix: `Session` / `Agent` / none (= App). Role suffix is usually `Service`. | `ISessionLogService`, `IAgentLoopService`, `ILogService` (App) |
|
||||
| Interface | `I` + scope prefix + PascalCase domain + role suffix. Scope prefix: `Workspace` / `Session` / `Agent` / none (= App). Role suffix is usually `Service`. | `IWorkspaceDirs`, `ISessionLogService`, `IAgentLoopService`, `ILogService` (App) |
|
||||
| Class | the interface name minus the leading `I`, plus `Service` if it does not already end in `Service`; `implements` the interface | `SessionLogService implements ISessionLogService`, `AppendLogStoreService implements IAppendLogStore` |
|
||||
| Decorator string | lowerCamelCase of the interface name minus the leading `I`; **globally unique and stable** (it surfaces in `CyclicDependencyError.path` and "no service registered" errors) | `createDecorator<ISessionLogService>('sessionLogService')` |
|
||||
| Model / non-service types | PascalCase, no `I` prefix | `SessionMeta`, `LogEntry`, `ConfigSection` |
|
||||
|
||||
The scope prefix makes a service's lifetime readable from its name. App services carry **no** prefix (App is the default, longest-lived tier); Session and Agent services always carry `Session` / `Agent`. The prefix applies to the interface, the class, and therefore the file names.
|
||||
The scope prefix makes a service's lifetime readable from its name. App services carry **no** prefix (App is the default, longest-lived tier); Workspace, Session and Agent services always carry `Workspace` / `Session` / `Agent`. The prefix applies to the interface, the class, and therefore the file names.
|
||||
|
||||
> Do **not** use the scope prefix to re-merge domains by lifetime. `IAgentEntityService`, `IAgentDataService`, and `ISessionEntityService` are still banned — the prefix marks lifetime, the rest of the name must still be the real owning domain (`IBackgroundTaskEntityService`, `ISessionMetadata`, `IPermissionRulesService`). See [domain-boundaries.md](domain-boundaries.md).
|
||||
|
||||
|
|
@ -137,7 +137,8 @@ Holds the concrete class(es) and the top-level registration. A typical impl:
|
|||
* … collaborators as roles ("logs through `log`") … Bound at App scope.
|
||||
*/
|
||||
|
||||
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
import { LifecycleScope } from '#/app/scopes';
|
||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
import { ILogService } from '#/log';
|
||||
|
||||
import { type Greeting, IGreeter } from './greet';
|
||||
|
|
@ -163,6 +164,8 @@ 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.
|
||||
- **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
|
||||
|
||||
- Declare every dependency with `@IX` on a constructor parameter.
|
||||
|
|
@ -204,7 +207,7 @@ A scoped Service may expose a factory method that returns a **new** instance of
|
|||
|
||||
### Runtime state goes into the per-scope state container
|
||||
|
||||
Session/Agent-scope Services register their runtime state into the scope's state container (`ISessionStateService` / `IAgentStateService`, both over `_base`'s `StateRegistry`) instead of holding it in bare instance fields, so per-scope state lives in one observable place (`snapshot()` / `onDidChange`) and dies with the scope. Reference: `session/interaction/interactionService.ts`.
|
||||
Workspace/Session/Agent-scope Services register their runtime state into the scope's state container (`IWorkspaceStateService` / `ISessionStateService` / `IAgentStateService`, all over `_base`'s `StateRegistry`) instead of holding it in bare instance fields, so per-scope state lives in one observable place (`snapshot()` / `onDidChange`) and dies with the scope. Reference: `session/interaction/interactionService.ts`.
|
||||
|
||||
- Declare keys in the domain file and export them: `export const interactionPendingKey = defineState<Map<string, Pending>>('interaction.pending', () => new Map())` — `<domain>.<field>` naming, factory initializers.
|
||||
- Inject `@ISessionStateService private readonly states` (or the Agent token) and `this.states.register(key)` per key at the top of the constructor.
|
||||
|
|
@ -317,7 +320,8 @@ export const IGreeter: ServiceIdentifier<IGreeter> = createDecorator<IGreeter>('
|
|||
|
||||
```ts
|
||||
// greet/greetService.ts
|
||||
import { LifecycleScope, ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
import { LifecycleScope } from '#/app/scopes';
|
||||
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
|
||||
import { type Greeting, IGreeter } from './greet';
|
||||
|
||||
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
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { LifecycleScope } from '#/app/scopes';
|
||||
import {
|
||||
LifecycleScope,
|
||||
ScopeActivation,
|
||||
_clearScopedRegistryForTests,
|
||||
registerScopedService,
|
||||
|
|
@ -224,6 +224,14 @@ 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.
|
||||
|
||||
## 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
|
||||
|
||||
- One behavior per `it`; describe observable behavior (`child shadows parent registration`), not implementation (`calls _getOrCreateServiceInstance`).
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Run the guards and re-scan the red lines before submitting.
|
|||
|
||||
Run from the package (or with `--filter @moonshot-ai/agent-core-v2`):
|
||||
|
||||
- `pnpm --filter @moonshot-ai/agent-core-v2 lint:domain` — domain-layer / dependency-direction guard (`scripts/check-domain-layers.mjs`). Catches a domain importing a layer it must not.
|
||||
- `pnpm --filter @moonshot-ai/agent-core-v2 lint:imports` — import-boundary guard (`scripts/check-import-boundaries.mjs`). Catches v1 imports (`@moonshot-ai/agent-core`) and kosong subtree violations.
|
||||
- `pnpm --filter @moonshot-ai/agent-core-v2 typecheck` — `tsc -p tsconfig.json --noEmit`.
|
||||
- `pnpm --filter @moonshot-ai/agent-core-v2 test` — `vitest run`.
|
||||
|
||||
|
|
@ -27,6 +27,6 @@ Then re-read the [global red lines](SKILL.md#global-red-lines) once — they cat
|
|||
|
||||
## Red lines (this stage)
|
||||
|
||||
- Do not skip `lint:domain` — it is the only automated check for the dependency-direction rules.
|
||||
- Do not skip `lint:imports` — it is the only automated check for the v1-import ban and the kosong subtree rules.
|
||||
- Do not list internal packages in a changeset when the change enters the CLI bundle — list `@moonshot-ai/kimi-code` and describe the real change.
|
||||
- Never write a `major` changeset without explicit user confirmation.
|
||||
|
|
|
|||
|
|
@ -19,11 +19,10 @@ All other `@moonshot-ai/*` packages are treated as internal packages, including
|
|||
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.
|
||||
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.
|
||||
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.
|
||||
- `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.
|
||||
- `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).
|
||||
- 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.
|
||||
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.
|
||||
|
|
@ -153,36 +152,6 @@ Only SDK source changed, and the CLI does not use it:
|
|||
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` 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.
|
||||
|
|
@ -233,5 +202,3 @@ 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 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 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,7 +37,7 @@ 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:
|
||||
|
||||
- **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.
|
||||
- **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.
|
||||
- **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.
|
||||
- **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 新功能 / 修复 / 优化 / 重构 / 其他.
|
||||
|
|
@ -48,6 +48,8 @@ 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.
|
||||
|
||||
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>
|
||||
|
||||
|
|
|
|||
|
|
@ -115,18 +115,11 @@ 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 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").
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
|
@ -135,13 +128,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:
|
||||
|
||||
- **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.
|
||||
- **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:
|
||||
- "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" → "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."
|
||||
- Keep `web:` if the merged fixes are all web-facing. Classify as `Bug Fixes`.
|
||||
- "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."
|
||||
- Classify the merged fixes 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.
|
||||
- **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.
|
||||
- **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.
|
||||
|
||||
The docs changelog uses five section types:
|
||||
|
||||
|
|
@ -229,6 +222,8 @@ Example:
|
|||
- 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
|
||||
|
||||
After updating the English page, translate only the newly added English content into `docs/zh/release-notes/changelog.md`.
|
||||
|
|
@ -281,7 +276,7 @@ Guidelines:
|
|||
- **Keep usage hints to one short clause**.
|
||||
- Bad: `传入 --allowed-host 以允许额外的 host。例如 ... (多句展开)`
|
||||
- Better: `例如 kimi web --allowed-host example.com。`
|
||||
- **Do not translate technical identifiers**: keep command names, flag names, file names, env vars, config keys, and the `web:` scope prefix as-is.
|
||||
- **Do not translate technical identifiers**: keep command names, flag names, file names, env vars, config keys 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.
|
||||
|
||||
Example — translating a feature entry:
|
||||
|
|
@ -322,6 +317,7 @@ Check:
|
|||
- PR links and commit hashes were stripped.
|
||||
- No `Thanks ...!` credit remains (remove it every time).
|
||||
- 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.
|
||||
- Markdown indentation and blank lines are intact.
|
||||
|
||||
|
|
@ -426,7 +422,6 @@ Return the PR URL to the user when done.
|
|||
- The English docs changelog is the source of truth.
|
||||
- Never edit upstream `apps/kimi-code/CHANGELOG.md`.
|
||||
- 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.
|
||||
- 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.
|
||||
|
|
@ -440,7 +435,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 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 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
|
@ -454,12 +449,13 @@ Return the PR URL to the user when done.
|
|||
| Leaving empty sections | Delete sections with no entries |
|
||||
| Putting everything under Other for convenience | Classify what can be classified first |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ All other workspace packages are private internal packages, are not published to
|
|||
- `@moonshot-ai/kaos`
|
||||
- `@moonshot-ai/kimi-code-oauth`
|
||||
- `@moonshot-ai/kimi-telemetry`
|
||||
- `@moonshot-ai/kimi-web`
|
||||
- `@moonshot-ai/kosong`
|
||||
- `@moonshot-ai/migration-legacy`
|
||||
- `@moonshot-ai/protocol`
|
||||
|
|
|
|||
8
.github/workflows/_native-build.yml
vendored
8
.github/workflows/_native-build.yml
vendored
|
|
@ -86,11 +86,9 @@ jobs:
|
|||
echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build Kimi web assets
|
||||
# The SEA blob step embeds apps/kimi-code/dist-web; build the web app
|
||||
# and stage its assets before producing the native executable.
|
||||
run: |
|
||||
pnpm --filter @moonshot-ai/kimi-web run build
|
||||
node apps/kimi-code/scripts/copy-web-assets.mjs
|
||||
# The SEA blob step embeds apps/kimi-code/dist-web. The bundle is
|
||||
# committed (synced from the code-app repo) — just verify it is in place.
|
||||
run: node apps/kimi-code/scripts/check-web-assets.mjs
|
||||
|
||||
- name: Build native executable (release profile, macOS signed)
|
||||
if: runner.os == 'macOS' && inputs.sign-macos
|
||||
|
|
|
|||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -127,8 +127,6 @@ jobs:
|
|||
done
|
||||
- name: Typecheck VS Code extension
|
||||
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
|
||||
run: pnpm --filter @moonshot-ai/vis-server run typecheck
|
||||
- name: Typecheck vis-web
|
||||
|
|
|
|||
3
.github/workflows/pkg-pr-new.yml
vendored
3
.github/workflows/pkg-pr-new.yml
vendored
|
|
@ -36,9 +36,6 @@ jobs:
|
|||
- name: Build package dependencies
|
||||
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
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
|||
node_modules/
|
||||
dist/
|
||||
dist-web/
|
||||
dist-single/
|
||||
dist-native/
|
||||
.tmp-api-extractor/
|
||||
|
|
|
|||
|
|
@ -90,6 +90,26 @@
|
|||
"eslint/no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
// The stage-6 worker closure: these modules (and everything
|
||||
// packages/minidb/src/worker/ pulls 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 that closure.
|
||||
"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"
|
||||
],
|
||||
"rules": {
|
||||
"import/extensions": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/kosong/src/providers/**/*.ts"],
|
||||
"rules": {
|
||||
|
|
@ -146,6 +166,7 @@
|
|||
],
|
||||
"ignorePatterns": [
|
||||
"dist/",
|
||||
"dist-web/",
|
||||
"coverage/",
|
||||
"node_modules/",
|
||||
"apps/*/scripts/",
|
||||
|
|
|
|||
20
AGENTS.md
20
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
|
||||
|
||||
# Copied from packages/pi-tui/native at build time by scripts/copy-native-assets.mjs
|
||||
native/
|
||||
/native/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,187 @@
|
|||
# @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
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2410](https://github.com/MoonshotAI/kimi-code/pull/2410) [`f1a3475`](https://github.com/MoonshotAI/kimi-code/commit/f1a3475ad5d6540447496701aa75fd4b035ecb28) Thanks [@sailist](https://github.com/sailist)! - Fix sporadic "model is not configured" errors when starting kimi web, caused by the background provider-model refresh transiently clearing the model catalog while the first session was being created.
|
||||
|
||||
- [#2400](https://github.com/MoonshotAI/kimi-code/pull/2400) [`1f3f5da`](https://github.com/MoonshotAI/kimi-code/commit/1f3f5dadaaa4a1d705cc98aee1dbbef13680502c) Thanks [@7Sageer](https://github.com/7Sageer)! - Preserve the assistant's partial output when a turn is interrupted with Esc, and remind the model that the previous turn was deliberately interrupted.
|
||||
|
||||
- [#2415](https://github.com/MoonshotAI/kimi-code/pull/2415) [`5c0ec29`](https://github.com/MoonshotAI/kimi-code/commit/5c0ec2938ac3a01624b6503e5e5df80c9b08f46a) Thanks [@wbxl2000](https://github.com/wbxl2000)! - web: Enable Monaco-based highlighting for code blocks, and fix line numbers overlapping or drifting out of alignment in fallback-rendered code blocks.
|
||||
|
||||
- [#2442](https://github.com/MoonshotAI/kimi-code/pull/2442) [`bb2919e`](https://github.com/MoonshotAI/kimi-code/commit/bb2919eb818a6cb51c71cbabf1bac9020131bce7) Thanks [@liruifengv](https://github.com/liruifengv)! - Reduce frequent full-screen redraws in the TUI.
|
||||
|
||||
- [#2125](https://github.com/MoonshotAI/kimi-code/pull/2125) [`e111c87`](https://github.com/MoonshotAI/kimi-code/commit/e111c878fd5cd07994e125b9e4e07e4069f01be1) Thanks [@bowenliang123](https://github.com/bowenliang123)! - web: Order permission modes from safest to most permissive across settings surfaces, and fix the swapped yolo/auto risk colors in the status panel and mobile settings.
|
||||
|
||||
- [#2459](https://github.com/MoonshotAI/kimi-code/pull/2459) [`326e1fb`](https://github.com/MoonshotAI/kimi-code/commit/326e1fb6ce59fbf2d6c7646e6d587759565814fd) Thanks [@wbxl2000](https://github.com/wbxl2000)! - web: Fix chat code blocks rendering in the proportional UI font at the wrong size after the markdown renderer upgrade, and align the loading fallback with the highlighted block so the upgrade no longer shifts layout.
|
||||
|
||||
- [#2437](https://github.com/MoonshotAI/kimi-code/pull/2437) [`ed7a4cc`](https://github.com/MoonshotAI/kimi-code/commit/ed7a4cc095e1619e4dbb6c2c77c89a52e312b085) Thanks [@sailist](https://github.com/sailist)! - web: Make the @ file mention work in a new-session draft, before the first prompt creates the session.
|
||||
|
||||
- [#2437](https://github.com/MoonshotAI/kimi-code/pull/2437) [`ed7a4cc`](https://github.com/MoonshotAI/kimi-code/commit/ed7a4cc095e1619e4dbb6c2c77c89a52e312b085) Thanks [@sailist](https://github.com/sailist)! - web: Fix new sessions showing the thinking level (e.g. Max) while the first message actually ran with thinking off.
|
||||
|
||||
## 0.31.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#2365](https://github.com/MoonshotAI/kimi-code/pull/2365) [`fa2c5ce`](https://github.com/MoonshotAI/kimi-code/commit/fa2c5ce18b70577fa3ada4eb8bdd4993891994ce) Thanks [@7Sageer](https://github.com/7Sageer)! - Add support for plugin-contributed custom agents, discovered automatically and available for sub-agent delegation. Ship an `agents/` directory in the plugin (or declare `agents` paths in the plugin manifest) to provide them.
|
||||
|
||||
- [#2314](https://github.com/MoonshotAI/kimi-code/pull/2314) [`02d77b2`](https://github.com/MoonshotAI/kimi-code/commit/02d77b20d941873563f14890e049ffe40cec76e4) Thanks [@7Sageer](https://github.com/7Sageer)! - Allow enabled plugins to contribute agent system-prompt instructions through `systemPrompt` or `systemPromptPath` in `kimi.plugin.json`, effective on both agent engines (the TUI, `kimi -p`, and `kimi web`).
|
||||
|
||||
- [#2232](https://github.com/MoonshotAI/kimi-code/pull/2232) [`efac96c`](https://github.com/MoonshotAI/kimi-code/commit/efac96c8a95a3c3ca4e1ae9bce38082498a02b2e) Thanks [@7Sageer](https://github.com/7Sageer)! - Support Markdown-defined custom agents on agent-core.
|
||||
|
||||
- [#2232](https://github.com/MoonshotAI/kimi-code/pull/2232) [`efac96c`](https://github.com/MoonshotAI/kimi-code/commit/efac96c8a95a3c3ca4e1ae9bce38082498a02b2e) Thanks [@7Sageer](https://github.com/7Sageer)! - Add the /secondary_model slash command to configure the secondary model used by subagents.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2382](https://github.com/MoonshotAI/kimi-code/pull/2382) [`40172c7`](https://github.com/MoonshotAI/kimi-code/commit/40172c7ca96ca981b043b793588dd32e898979fa) Thanks [@liruifengv](https://github.com/liruifengv)! - Fix request headers not being passed correctly on some requests.
|
||||
|
||||
- [#2379](https://github.com/MoonshotAI/kimi-code/pull/2379) [`691ec46`](https://github.com/MoonshotAI/kimi-code/commit/691ec4679ea19d6be8ac18f359088384ed3e446d) Thanks [@RealKai42](https://github.com/RealKai42)! - Remove the blocking `block`/`timeout` wait from the TaskOutput tool so checking a background task can no longer stall the conversation; it now always returns an immediate snapshot, and completion still arrives via automatic notification.
|
||||
|
||||
- [#2395](https://github.com/MoonshotAI/kimi-code/pull/2395) [`d10b1c1`](https://github.com/MoonshotAI/kimi-code/commit/d10b1c130813dbd6ee8c8599a6a98feb36aea67f) Thanks [@sailist](https://github.com/sailist)! - Fix sessions missing from the session picker when their cached metadata predates the archived flag.
|
||||
|
||||
## 0.30.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#2255](https://github.com/MoonshotAI/kimi-code/pull/2255) [`67dd031`](https://github.com/MoonshotAI/kimi-code/commit/67dd03149f36be91a0c081e70d8a2d721b0f1c64) Thanks [@he-yufeng](https://github.com/he-yufeng)! - Add a customizable footer status line, configured via `[status_line]` in `tui.toml`.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2313](https://github.com/MoonshotAI/kimi-code/pull/2313) [`de0ba9d`](https://github.com/MoonshotAI/kimi-code/commit/de0ba9d0654273ff6b028a7a561983ebee4e723e) Thanks [@starquakee](https://github.com/starquakee)! - Stop the turn after repeated invalid tool calls instead of retrying indefinitely.
|
||||
|
||||
- [#2147](https://github.com/MoonshotAI/kimi-code/pull/2147) [`29783e4`](https://github.com/MoonshotAI/kimi-code/commit/29783e471afcf7975852e496907646458264d2e6) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Show a quota note after installing official plugins that bill against plan quota (such as Kimi Datasource).
|
||||
|
||||
- [#2147](https://github.com/MoonshotAI/kimi-code/pull/2147) [`29783e4`](https://github.com/MoonshotAI/kimi-code/commit/29783e471afcf7975852e496907646458264d2e6) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Show a notice when an official plugin used in the session has an update available. Run /plugins to install it.
|
||||
|
||||
- [#1857](https://github.com/MoonshotAI/kimi-code/pull/1857) [`cdbd33c`](https://github.com/MoonshotAI/kimi-code/commit/cdbd33c13c7f5cd4c49ec112ee4313b3938a7752) Thanks [@vinlee19](https://github.com/vinlee19)! - Fail fast when account quota or balance is exhausted instead of silently retrying for ~3 minutes.
|
||||
|
||||
- [#2294](https://github.com/MoonshotAI/kimi-code/pull/2294) [`425cfdf`](https://github.com/MoonshotAI/kimi-code/commit/425cfdf53f0fd3b01527f5fba87acff68f49f368) Thanks [@wbxl2000](https://github.com/wbxl2000)! - web: Fix garbled line numbers in code blocks.
|
||||
|
||||
- [#2312](https://github.com/MoonshotAI/kimi-code/pull/2312) [`d03a488`](https://github.com/MoonshotAI/kimi-code/commit/d03a4886fdf7c35014c10079a3d417aeb0447d9a) Thanks [@sailist](https://github.com/sailist)! - Remove the 50 MB size limit on file uploads to the built-in server.
|
||||
|
||||
## 0.29.2
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
|||
29
apps/kimi-code/dist-web/assets/CodeBlockNode-ZZ-0lk3E.js
Normal file
29
apps/kimi-code/dist-web/assets/CodeBlockNode-ZZ-0lk3E.js
Normal file
File diff suppressed because one or more lines are too long
13
apps/kimi-code/dist-web/assets/DesignSystemView-BOD_23qT.js
Normal file
13
apps/kimi-code/dist-web/assets/DesignSystemView-BOD_23qT.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf
Normal file
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.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Jm3AIy58.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Jm3AIy58.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-waoOVXN0.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-waoOVXN0.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-3WenGoN9.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-3WenGoN9.ttf
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-BMLOBm91.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-BMLOBm91.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-B22Nviop.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-B22Nviop.woff2
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-Dr94JaBh.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-Dr94JaBh.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-DA0__PXp.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-DA0__PXp.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-t53AETM-.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-t53AETM-.woff2
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf
Normal file
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.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-C195tn64.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-C195tn64.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff
Normal file
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf
Normal file
BIN
apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
apps/kimi-code/dist-web/assets/NotoSansSC_wght_-BkPpiACN.woff2
Normal file
BIN
apps/kimi-code/dist-web/assets/NotoSansSC_wght_-BkPpiACN.woff2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
apps/kimi-code/dist-web/assets/Tooltip-CPKMqLZA.js
Normal file
1
apps/kimi-code/dist-web/assets/Tooltip-CPKMqLZA.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
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};
|
||||
|
|
@ -0,0 +1 @@
|
|||
function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}export{e as g};
|
||||
1
apps/kimi-code/dist-web/assets/abap-BdImnpbu.js
Normal file
1
apps/kimi-code/dist-web/assets/abap-BdImnpbu.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
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};
|
||||
|
|
@ -0,0 +1 @@
|
|||
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
1
apps/kimi-code/dist-web/assets/ada-bCR0ucgS.js
Normal file
1
apps/kimi-code/dist-web/assets/ada-bCR0ucgS.js
Normal file
File diff suppressed because one or more lines are too long
1
apps/kimi-code/dist-web/assets/andromeeda-C4gqWexZ.js
Normal file
1
apps/kimi-code/dist-web/assets/andromeeda-C4gqWexZ.js
Normal file
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