fix: escape all control characters in TOML basic strings - #7
Closed
hobostay wants to merge 1 commit into
Closed
Conversation
escapeTomlBasicString only handled \b \t \n \f \r but not other control characters in U+0000-U+001F and U+007F. Per the TOML spec, basic strings may only contain certain escape sequences; unescaped control chars produce invalid TOML that smol-toml cannot parse, silently corrupting the config on next load. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Collaborator
|
Thank you for your interest in contributing to kimi-code. |
sailist
added a commit
that referenced
this pull request
Jun 5, 2026
…alue (P1.2)
Honour `SyncDescriptor.supportsDelayedInstantiation: true` by wrapping the
service in a `Proxy` that defers real construction until the first
non-event property access. Eager services (the default,
`supportsDelayedInstantiation: false`) remain unchanged — same eager
Reflect.construct path P1.1 installed.
- NEW `di/util/idleValue.ts` — vendors `GlobalIdleValue<T>` from krow
`base/async.ts` plus the `runWhenGlobalIdle` helper. Internally falls
back to `setTimeout` (one frame ~15 ms) when `requestIdleCallback` is
absent (the typical Node environment); reading `.value` before the
idle tick fires cancels the schedule and runs the executor inline.
Only `GlobalIdleValue` is exported; `runWhenGlobalIdle` is
module-private because the DI subsystem is the sole consumer.
- NEW `di/util/linkedList.ts` — vendors krow `base/linkedList.ts` (~80
LOC, zero deps). Used by the Proxy `get` trap to park
`onDid*`/`onWill*` event subscriptions while the real instance is
still pending. Each `push` returns its own disposer for O(1) removal.
- `_createServiceInstance(id, desc, supportsDelayedInstantiation,
_trace)` — eager path unchanged; lazy path captures `_ctor`, `_args`,
`earlyListeners: Map<string, LinkedList<EarlyListenerData>>` and
builds a `GlobalIdleValue<T>` whose executor runs `_createInstance`,
then replays every parked listener against the real event by calling
`(result as any)[key](callback, thisArg, disposables)`. The returned
Proxy traps `get` to (a) intercept `onDid*`/`onWill*` keys before
materialisation and park subscribers, (b) materialise + memoise
bound function references for other keys, and `getPrototypeOf`
returns `_ctor.prototype` so `instance instanceof Foo === true`
without forcing materialisation.
- `_servicesToMaybeDispose: Set<any>` — new field on
`InstantiationService`. Materialised lazy instances are added inside
the `GlobalIdleValue` executor (not via `_setCreatedServiceInstance`)
so `dispose()` can tear them down without ever reading the Proxy.
- `_setCreatedServiceInstance` gains a `lazy: boolean = false`
parameter; when true, the Proxy is written to `services` +
`_instances` (so subsequent `get(id)` returns the SAME Proxy) but is
intentionally NOT pushed to `_constructionOrder`. Disposing a Proxy
would require reading a property of it, which would force
materialisation just to probe for a `.dispose` method — exactly the
pessimisation `supportsDelayedInstantiation` was designed to avoid.
- `dispose()` now runs in two passes (PLAN D8 LIFO preserved for the
eager set): first walk `_constructionOrder` in reverse and dispose
each instance (also evicting from `_servicesToMaybeDispose` so we
don't double-dispose), then iterate the remaining
`_servicesToMaybeDispose` for Proxy-materialised real instances.
Tests (delayed.test.ts):
- `a.get(IFoo)` on a lazy descriptor returns a Proxy WITHOUT triggering
Foo's ctor.
- Reading any non-event property triggers exactly one ctor call.
- `proxy instanceof Foo === true` even pre-materialisation
(`getPrototypeOf` trap).
- Subscribing to `onDidChange` BEFORE first non-event access parks the
listener; subsequent property read materialises Foo; firing the real
event delivers the payload to the parked listener (replay logic).
Quality gates:
- agent-core: 2458 pass / 1 skip / 1 todo.
- daemon: 240 / 241 — the single failure is the known
`fs-watch.e2e.test.ts:257` / `fs-search.e2e.test.ts` timing flake at
baseline `57e7bfc69` (verified by checking out baseline files and
re-running: same failure). Per Phase 0 reviewer note #7 this is
treated as a pre-existing flake, NOT a P1.2 regression.
Review verdict: `/tmp/di-uplift-2026.06.05/phase-1/reviews.log`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sailist
added a commit
that referenced
this pull request
Jun 5, 2026
…alue (P1.2)
Honour `SyncDescriptor.supportsDelayedInstantiation: true` by wrapping the
service in a `Proxy` that defers real construction until the first
non-event property access. Eager services (the default,
`supportsDelayedInstantiation: false`) remain unchanged — same eager
Reflect.construct path P1.1 installed.
- NEW `di/util/idleValue.ts` — vendors `GlobalIdleValue<T>` from krow
`base/async.ts` plus the `runWhenGlobalIdle` helper. Internally falls
back to `setTimeout` (one frame ~15 ms) when `requestIdleCallback` is
absent (the typical Node environment); reading `.value` before the
idle tick fires cancels the schedule and runs the executor inline.
Only `GlobalIdleValue` is exported; `runWhenGlobalIdle` is
module-private because the DI subsystem is the sole consumer.
- NEW `di/util/linkedList.ts` — vendors krow `base/linkedList.ts` (~80
LOC, zero deps). Used by the Proxy `get` trap to park
`onDid*`/`onWill*` event subscriptions while the real instance is
still pending. Each `push` returns its own disposer for O(1) removal.
- `_createServiceInstance(id, desc, supportsDelayedInstantiation,
_trace)` — eager path unchanged; lazy path captures `_ctor`, `_args`,
`earlyListeners: Map<string, LinkedList<EarlyListenerData>>` and
builds a `GlobalIdleValue<T>` whose executor runs `_createInstance`,
then replays every parked listener against the real event by calling
`(result as any)[key](callback, thisArg, disposables)`. The returned
Proxy traps `get` to (a) intercept `onDid*`/`onWill*` keys before
materialisation and park subscribers, (b) materialise + memoise
bound function references for other keys, and `getPrototypeOf`
returns `_ctor.prototype` so `instance instanceof Foo === true`
without forcing materialisation.
- `_servicesToMaybeDispose: Set<any>` — new field on
`InstantiationService`. Materialised lazy instances are added inside
the `GlobalIdleValue` executor (not via `_setCreatedServiceInstance`)
so `dispose()` can tear them down without ever reading the Proxy.
- `_setCreatedServiceInstance` gains a `lazy: boolean = false`
parameter; when true, the Proxy is written to `services` +
`_instances` (so subsequent `get(id)` returns the SAME Proxy) but is
intentionally NOT pushed to `_constructionOrder`. Disposing a Proxy
would require reading a property of it, which would force
materialisation just to probe for a `.dispose` method — exactly the
pessimisation `supportsDelayedInstantiation` was designed to avoid.
- `dispose()` now runs in two passes (PLAN D8 LIFO preserved for the
eager set): first walk `_constructionOrder` in reverse and dispose
each instance (also evicting from `_servicesToMaybeDispose` so we
don't double-dispose), then iterate the remaining
`_servicesToMaybeDispose` for Proxy-materialised real instances.
Tests (delayed.test.ts):
- `a.get(IFoo)` on a lazy descriptor returns a Proxy WITHOUT triggering
Foo's ctor.
- Reading any non-event property triggers exactly one ctor call.
- `proxy instanceof Foo === true` even pre-materialisation
(`getPrototypeOf` trap).
- Subscribing to `onDidChange` BEFORE first non-event access parks the
listener; subsequent property read materialises Foo; firing the real
event delivers the payload to the parked listener (replay logic).
Quality gates:
- agent-core: 2458 pass / 1 skip / 1 todo.
- daemon: 240 / 241 — the single failure is the known
`fs-watch.e2e.test.ts:257` / `fs-search.e2e.test.ts` timing flake at
baseline `57e7bfc69` (verified by checking out baseline files and
re-running: same failure). Per Phase 0 reviewer note #7 this is
treated as a pre-existing flake, NOT a P1.2 regression.
Review verdict: `/tmp/di-uplift-2026.06.05/phase-1/reviews.log`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Planning note for issue/PR #7 (no code changes made yet). Requirement confirmed:
Code impact found:
Implementation plan:
Validation plan:
|
wintrover
added a commit
to wintrover/kimy
that referenced
this pull request
Jun 29, 2026
- kimy wrapper: move hash writes after smoke test (MoonshotAI#1) - kimy wrapper: add public/ to web hash inputs (MoonshotAI#3) - kimy wrapper: widen vis hash to include config files (MoonshotAI#4) - kimy wrapper: move lockfile from /tmp to ~/.kimy/bin (MoonshotAI#5) - kimy wrapper: use explicit package list for native hash (MoonshotAI#7) - 01-bundle.mjs: skip vis-asset build when already done (MoonshotAI#2) - justfile: sync deploy with new wrapper, add deploy-full (MoonshotAI#9,MoonshotAI#10,MoonshotAI#11) - flake.nix: add unpin guidance to nixpkgs comment (MoonshotAI#12)
wintrover
added a commit
to wintrover/kimy
that referenced
this pull request
Jun 29, 2026
…nshotAI#8 Replace manual file-set declarations with build engine introspection. - tsdown native config: add manifestPlugin() that writes build-manifest.json via OutputChunk.moduleIds (850 bundled modules, zero test files) - kimy wrapper: lockfile-based dependency hashing via pnpm-lock.yaml importers - kimy wrapper: manifest-based native hashing (bundledModules only) - kimy wrapper: double-checked locking inside flock (TOCTOU fix) - kimy wrapper: atomic hash file writes via temp + mv
asdshuaishuai
pushed a commit
to d2rabbit/kimi-code
that referenced
this pull request
Jul 21, 2026
…oonshotAI#7) SettingsView previously had two separate entry points (添加供应商 and 添加自定义模型) that opened ProviderModelDialog in mode='provider' or mode='model' — disjoint forms that couldn't compose (e.g. you couldn't create a provider AND a model AND configure thinking in one go). Rewrote ProviderModelDialog as a single unified form with three sections: ① 供应商 — type/id/key/baseURL OR pick existing provider ② 模型 — optional alias for the provider (toggleable off) ③ 思考 — toggle + effort level pills (minimal/low/medium/high) The thinking section mirrors kimi-code's config.toml [thinking] schema: - enabled = true → effort pick is one of minimal/low/medium/high - enabled = false → submits 'off' (no thinking) Effort levels are taken from the user's explicit request (minimal/low/medium/high), reflecting the actual values kimi-code accepts in [thinking] effort = "…". The footer of the dialog shows the equivalent TOML snippet for clarity. Both SettingsView entry points ('添加供应商' and '添加自定义模型') now open the same unified dialog — they default to the same form; the user can toggle the model section off if they only want a provider. svelte-check 0 errors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
escapeTomlBasicStringonly handled\b,\t,\n,\f,\rbut not other control characters in U+0000-U+001F and U+007Fsmol-tomlcannot parse\uXXXXsequencesTest plan
🤖 Generated with Claude Code