mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix: address ds-review-bot round — insert-aliasing clones, settlement gates, closure module fallback
- Clone patch lists per generation (boot + composeLive): the include pushes insert rows by reference and mutates them in place, so a reused object baked user overrides into bundle rows and removal could not revert; the built-bin hot-reload e2e now asserts an override AND its removal reverting. - The headless runner awaits Loader settlement before prompting (its inject gate covers only apiProxy/httpServer) and abandons cleanly when the tree died during the wait. - healProfilesModuleFallback walks the app's full dependency+peer closure: out-of-tree plugins import seam packages (dsh-compact, dsh-subprocess, ...) that only implementations reach, and peers are how seams are declared. - Profile init writes pnpm-workspace.yaml (nodeLinker: hoisted), not .npmrc — pnpm >=10 reads settings from the workspace manifest. - Web dumps reject boot-only flags instead of printing a tree that differs from the same invocation's boot; --port validates at the flag; --dump-default-config no longer parses the (possibly broken) user layer; trustedHosts flag derivation merges over the composed value instead of replacing it; web-runtime gains surfaceContext (headless disables the GUI prompt/bash-vars the old -p never mounted); 'node_modules' is a reserved profile name; plugin-warning names the recovery step; client AGENTS.md registration surfaces point at the web-app bundle. - Ship session-reference/tmux-context/tool-ask-user as app dependencies for terminal front-door patch layers (turtle-ui), same stance as mcp-client.
This commit is contained in:
@@ -186,15 +186,22 @@ export async function runProfile(options: RunProfileOptions): Promise<{ ctx: Con
|
||||
composed.profile.layers.reduce((n, layer) => n + layer.patches.length, 0)
|
||||
+ composed.profile.patches.length,
|
||||
)
|
||||
const composeLive = (profilePatches: PatchOptions[]): PatchOptions[] => [
|
||||
// Fresh clones per generation: the include pushes `insert` rows into the
|
||||
// mounted tree BY REFERENCE and later id-targeted patches mutate those
|
||||
// objects in place. Reusing one parsed patch object across applications
|
||||
// would bake a user override into the bundle's in-memory insert row, so
|
||||
// removing the override could never revert the row to the bundle default.
|
||||
const composeLive = (profilePatches: PatchOptions[]): PatchOptions[] => structuredClone([
|
||||
...composed.profile.layers.flatMap(layer => layer.patches),
|
||||
...profilePatches,
|
||||
...overlayAndFlags,
|
||||
]
|
||||
])
|
||||
// One-shot runs exit through the runner; watching would only hold the
|
||||
// process open after its exit request.
|
||||
const watchProfilePatch = options.task === undefined
|
||||
const ctx = await boot(NAME, rootConfig, composed.patches, async (hostCtx) => {
|
||||
// Cloned for the same insert-aliasing reason as composeLive: the boot
|
||||
// application must not mutate the objects later reloads recompose from.
|
||||
const ctx = await boot(NAME, rootConfig, structuredClone(composed.patches), async (hostCtx) => {
|
||||
app.current = hostCtx
|
||||
if (options.task !== undefined) {
|
||||
const io: HeadlessIo = {
|
||||
|
||||
Reference in New Issue
Block a user