Commit Graph

1137 Commits

Author SHA1 Message Date
Yichen Jiang
0512b12714 feat(config)!: one ordering for configuration sources, and a bootstrap deny rule
$DSH_HOME/.env had just become an ordinary environment layer, which left the
harness resolving user-facing values from a flattened process.env that could
no longer say where a value came from. A key stored through the web page
stayed shadowed by an older key in the user's own .env. An endpoint could be
redirected by the project: the invoking directory's .env is materialized like
every other layer, and a base URL decides where a resolved API key is sent, so
a DEEPSEEK_BASE_URL written into a model-editable workspace would send the
user's credential — and the prompts carrying their code — to whatever host
that file named.

Give every user-facing value one ordering, with four kinds of source:

  explicit for this run     per-operation override, CLI argument
  > authored by deployment  --config / --config-replace
  > this launch's shell     inherited process environment
  > product-managed store   settings.yaml, .credentials.yaml
  > discovered file         $DSH_HOME/.env
  > defaults                schema default, shipped base, public default

The domains differ only in which tiers exist. The earlier split — credentials
ranking the environment over the managed file while settings ranked over the
environment — was inconsistent: the distinguishing fact is who authored the
source, not the domain.

packages/util/environment owns an immutable snapshot with per-layer
provenance. getFrom(name, sources) searches only the layers a caller names,
and omitting one is a refusal rather than a demotion: the adapters ask for
['process', 'user-env'], so no reordering can let a project file back into a
decision it was excluded from.

isBootstrapOnly rejects, before anything is materialized, any .env setting a
variable that governs how a process launches (PATH, SHELL, NODE_OPTIONS,
LD_PRELOAD), where code or model-visible instructions load from (the whole
DSH_* namespace, HOME, XDG_*), or how the network is reached (proxy and CA
variables). The namespace is denied wholesale so a switch added later cannot
become settable by being forgotten, and there is no opt-out.

verify-config-source-ownership keeps both rules: no unregistered process.env
read under packages/*/*/src (26 allowlisted with reasons), and no apiKey,
baseURL, or headers inlined from the environment in shipped Cordis config —
removing those inlines is what makes the deployment tier meaningful.
2026-08-04 16:17:32 +08:00
Yichen Jiang
8ddc53f7a0 feat(cli)!: complete --config on every surface and delete the personal overlay
$DSH_HOME/config.yaml was an implicit composition layer: if the file existed,
every launch applied an arbitrary Loader patch graph over the shipped tree,
kept live by a dedicated HMR watcher. Three costs came from the implicitness,
not the capability. A patch replaces its target row's whole config, so a file
written months ago pins that row to the field set it knew and every default
the shipped tree later adds silently stops applying. It competed with the
typed settings namespaces llm-deepseek and llm-pi-ai already register, so
which one wins was a function of layer order rather than meaning. And the
explicit escape hatch it was supposedly redundant with did not exist on every
surface: dsh -p, dsh meta, and dsh upgrade all rejected --config, so for them
the implicit file was the only composition route at all.

Complete the explicit layer first: --config and --config-replace now work on
every booting surface. A headless --config-replace tree must still mount a
webserver row, because that surface reaches its own agent over the same HTTP
gateway the browser uses; AppCLIEntry names that contract in the failure
instead of reporting a bare missing service.

Then delete the implicit one. PERSONAL_CONFIG_FILENAME, loadPersonalPatches,
watchPersonalPatches, and the config-only HMR row mounted for it are gone; a
file left at that path is inert, and --dump-config no longer reads the Harness
home. --config therefore stops *replacing* the personal overlay and simply
*is* the user overlay.

No migration: a user who wants the old behavior names the same file
(dsh --config ~/.dsh/config.yaml), which a shell alias makes permanent.
2026-08-04 15:25:04 +08:00
Yichen Jiang
03b534de16 feat(credentials): move the store to .credentials.yaml and layer $DSH_HOME/.env
$DSH_HOME/.env carried two incompatible jobs. As credentials-local's writable
secret store it could not be hoisted into process.env — hoisting makes every
stored key read as a read-only launch override and blocks rotation from the
TUI and the web page. But its name and dotenv format promise an environment
file, so a DEEPSEEK_BASE_URL sitting beside a working DEEPSEEK_API_KEY in the
same file was silently ignored: only the credential provider read the
document, and it addresses credential references alone.

Split the two jobs into two files.

.credentials.yaml is the provider-managed store: a strict YAML mapping of
CredentialRef to non-empty string, no version field, no wrapper level. Because
it holds credentials and nothing else, a non-mapping root, a non-identifier
key, a non-string value, an empty string, a duplicate key, and malformed YAML
are all rejections rather than skipped entries — loud at boot and at a write,
warn-and-keep-last-good on a live reload. The dotenv physical-line editor
gives way to a patch of the parsed document, so comments and untouched entries
keep their formatting and any string value round-trips, multi-line included.
Writer lock, read-modify-write, atomic 0600 write under a 0700 directory,
watcher, self-write suppression, and quiescent disposal are unchanged.

$DSH_HOME/.env becomes the user's ordinary environment layer. app-boot's new
loadLayeredEnv loads the invoking directory's .env then the Harness home's,
giving user < project < inherited; the home resolves from the inherited
environment first, so a project .env cannot redirect it.

Credential precedence is unchanged: the live environment still wins read-only
over the file, and shadowed writes still reject. Whether a provider-managed
store should instead win over the environment is a separate decision.

No migration: a key already in $DSH_HOME/.env keeps resolving through the new
environment layer, as a read-only env source that shadows the stored one.
2026-08-04 14:50:38 +08:00
Yichen Jiang
88c035c98e cleanup(cli): remove the profile-json config entry
`./.dsh-tmp-profile/config.json` was the web config-tree boot's user-config
plane, but never gained a writer: no production code created or edited it, no
test exercised it, and no user documentation named it. The fields it mapped
have owners elsewhere — provider/model are the api-gateway's default route and
persistenceRoot is an assembly fact, while typed user preferences live in
$DSH_HOME/settings.yaml.

Delete PROFILE_DIR, PROFILE_FILE, ProfileMapping, PROFILE_MAPPINGS, and
readProfile() with the patch source that consumed them. AppCLIEntry now
composes patches from CLI flags and the resolved frontend distIndex only; the
surrounding layers are unchanged. A file on disk is ignored completely — no
migration, replacement format, or deprecation diagnostic, per the pre-release
stance.
2026-08-04 14:11:38 +08:00
imccyu
33b52502f4 Merge branch 'master' into agent/fix-remote-welcome-onboarding 2026-08-03 18:37:37 +08:00
imccyu
49ede3ebf3 Merge pull request #1333 from deepseek-harness/codex/fix-subagent-catalog-padding
fix(web): align subagent catalog spacing with Figma
2026-08-03 18:34:24 +08:00
kingwl
6585847144 fix(web): preserve subagent catalog styling 2026-08-03 18:24:25 +08:00
imccyu
e47ad8e393 Merge remote-tracking branch 'origin/master' into agent/fix-remote-welcome-onboarding 2026-08-03 18:19:24 +08:00
kingwl
70ad82ef00 Merge remote-tracking branch 'origin/master' into codex/fix-subagent-catalog-padding 2026-08-03 18:08:15 +08:00
imccyu
ae5ee37591 Merge remote-tracking branch 'origin/master' into mergebot/pr927-r3
# Conflicts:
#	packages/ui/tui/README.i18n.yaml
#	packages/ui/tui/src/components/dialogs.ts
2026-08-03 17:57:50 +08:00
kingwl
5baa86b97f fix(web): align subagent catalog spacing 2026-08-03 17:22:51 +08:00
imccyu
553fb9a119 fix: test 2026-08-03 17:17:41 +08:00
imccyu
a3d897359f test(web): refresh Markdown image golden for the fork-eligibility gate 2026-08-03 17:11:36 +08:00
imccyu
a8670bdec3 Merge remote-tracking branch 'origin/master' into mergebot/pr965 2026-08-03 17:04:00 +08:00
Turtle
4c8b47f3c6 test(web): refresh markdown image golden 2026-08-03 17:00:33 +08:00
imccyu
070f371370 Merge branch 'master' into worktree/fix-multi-select-custom-answer 2026-08-03 16:55:48 +08:00
imccyu
d1dbff66e0 Merge remote-tracking branch 'origin/master' into fix/session-waiting-approval 2026-08-03 16:51:18 +08:00
Ziya
aaa2102246 Merge branch 'master' into agent/fix-remote-welcome-onboarding 2026-08-03 04:49:00 -04:00
Yichen Jiang
3009bc5312 Merge pull request #1003 from deepseek-harness/worktree/web-remote-markdown-images
feat(web): render remote Markdown images
2026-08-03 16:41:00 +08:00
imccyu
4fd3ef5797 Merge branch 'master' into worktree/fix-multi-select-custom-answer 2026-08-03 16:30:35 +08:00
Yichen Jiang
85b9914934 Merge remote-tracking branch 'origin/master' into worktree/fix-multi-select-custom-answer
# Conflicts:
#	packages/ui/tui/README.i18n.yaml
2026-08-03 16:26:55 +08:00
imccyu
fec8339a18 Merge branch 'master' into worktree/web-remote-markdown-images 2026-08-03 16:23:50 +08:00
imccyu
a8a97d0202 Merge branch 'master' into codex/fork-real-turn-tail 2026-08-03 16:23:46 +08:00
Yichen Jiang
886c39d302 test(web): refresh Markdown image snapshot 2026-08-03 16:21:02 +08:00
kingwl
c5050f018e fix(web): keep ineligible message forks disabled 2026-08-03 16:19:49 +08:00
Yichen Jiang
61cba0cda2 Merge remote-tracking branch 'origin/master' into worktree/web-remote-markdown-images
# Conflicts:
#	packages/client/ui-primitives/README.i18n.yaml
#	packages/client/ui-primitives/README.md
#	packages/client/ui-primitives/README.zh.md
#	packages/client/ui-primitives/src/markdown/MarkdownText.tsx
#	packages/client/ui-primitives/tests/markdown.spec.tsx
2026-08-03 16:09:51 +08:00
Yichen Jiang
109d5b5e1c Merge remote-tracking branch 'origin/master' into worktree/fix-multi-select-custom-answer
# Conflicts:
#	apps/web/tests/snapshots/question-composer/answered.expected.md
#	apps/web/tests/snapshots/question-composer/session.jsonl
#	docs/core-data-structures/user-interaction.i18n.yaml
#	packages/client/ui-question/README.i18n.yaml
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.md
#	packages/host/apiproxy/README.zh.md
#	packages/ui/tui/README.i18n.yaml
#	packages/ui/user-interaction/README.i18n.yaml
2026-08-03 16:09:17 +08:00
Turtle
2178c66b0d test(tui): refresh queued compaction help snapshot 2026-08-03 16:06:51 +08:00
kingwl
c43eaaec82 Merge remote-tracking branch 'origin/master' into codex/pr-1150-disabled
# Conflicts:
#	packages/client/runtime/README.i18n.yaml
#	packages/client/ui-conversation/README.i18n.yaml
2026-08-03 16:02:33 +08:00
Wenlu Wang
6a3caea277 Merge pull request #1160 from deepseek-harness/codex/subagent-token-metrics
Show subagent token metrics
2026-08-03 15:35:17 +08:00
imccyu
2d31ec5fee Merge pull request #1173 from deepseek-harness/agent/web-bash-error-expand
fix(web): expand aborted Bash rows
2026-08-03 15:30:52 +08:00
kingwl
d5583210d4 tighten branchless subagent catalog layout 2026-08-03 15:19:53 +08:00
ZiyaZhang
59d923395a fix(web): document remote welcome constraints 2026-08-03 00:14:35 -07:00
Turtle
ef7637a5d8 Merge pull request #1093 from deepseek-harness/fix/tui-terminal-restore-on-boot-failure
fix(app-boot): restore the terminal when boot fails
2026-08-03 14:48:20 +08:00
ZiyaZhang
e63df333a1 test(web): normalize abort snapshot date 2026-08-02 23:45:47 -07:00
Wenlu Wang
8e820bbbf5 Merge pull request #1159 from deepseek-harness/codex/subagent-token-duration
Fix subagent active duration tracking
2026-08-03 14:45:29 +08:00
Turtle
f503c92aff Merge branch 'master' into fix/tui-terminal-restore-on-boot-failure 2026-08-03 14:40:58 +08:00
Ziya
b6b642fae4 Merge branch 'master' into agent/web-bash-error-expand 2026-08-03 02:30:36 -04:00
imccyu
8527ce23ae Merge pull request #1169 from deepseek-harness/worktree/directory-picker-path-editor
fix(directory-picker-browse): advertise the path editor and walk the panes with the draft
2026-08-03 14:30:34 +08:00
kingwl
a75b323e2e merge fractional duration normalization 2026-08-03 14:15:45 +08:00
kingwl
a9ed7c2e98 fix fractional duration normalization 2026-08-03 14:14:48 +08:00
Turtle
ad4aeacd19 fix(hmr,include): settle a failing boot instead of a silent exit 13
Master's transactional loader made the invalid-provider PTY case regress:
the HMR main watcher's initial scan refreshed the include mid-initial-apply,
the concurrent group updates stranded the include fiber, and once serialized
the failing apply's rollback deadlocked on HMR's refresh drain — dsh exited
13 with no diagnostic and the terminal stranded, the exact symptom this
branch fixes. Serialize every include child-tree mutation through one queue
and pass ignoreInitial to the HMR main watcher; the failing boot now settles
through boot()'s labelled rejection with the tree disposed and exit 1. The
PTY case asserts the settled diagnostic; the fail-loud release remains the
guard for rejections boot cannot see.
2026-08-03 14:14:20 +08:00
Turtle
b37c22bd0a Merge origin/master: combine boot-owned settlement with the fail-loud release
Conflicts: apps/cli/src/tui.ts (keep the release install over master's comment
rewording), packages/ui/app-boot/README* (master's new installFailLoud row
wording plus this branch's release and timeout rows).
2026-08-03 14:10:23 +08:00
ZiyaZhang
0a4ad25ce7 fix(web): expand aborted Bash rows 2026-08-02 23:06:00 -07:00
_Kerman
667960182a test(web): normalize detailed local clocks 2026-08-03 14:02:46 +08:00
_Kerman
5534431d42 fix(ui-trajectory): own composer overlay geometry 2026-08-03 14:02:40 +08:00
creatixchu
95826603cb review(web): poll the pane-arity assertions in the path-editor e2e
A bare count can observe a landing mid-commit on a loaded runner, and the
arity is the invariant this scenario exists to pin.
2026-08-03 13:57:20 +08:00
_Kerman
74cd2e4bd9 feat(ui-trajectory): enrich timeline timing interactions 2026-08-03 13:48:03 +08:00
kingwl
583d532bc3 merge compact duration display
# Conflicts:
#	.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md
#	.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md
#	apps/web/tests/snapshots/subagent-conversation/tree.expected.md
#	packages/client/ui-subagent/README.i18n.yaml
#	packages/client/ui-subagent/README.md
#	packages/client/ui-subagent/README.zh.md
#	packages/client/ui-subagent/src/client/SubagentCatalogAction.tsx
#	packages/client/ui-subagent/tests/conversation-ui.spec.tsx
2026-08-03 13:31:19 +08:00
creatixchu
2ceed380dd fix(directory-picker-browse): keep the typed level in the last pane
Skipping the draft-following scan whenever ANY pane happened to list the
directory was the cheaper rule and the wrong one: erasing a segment left the
level being typed on the LEFT, with its own child pane still standing to its
right, so the two panes stopped reading as "where I am, and where I came
from".

The pane arity is now the invariant the editor maintains — the last pane lists
the level the path names, its parent sits beside it, and only a display root
lists alone. Only that last pane's own tail costs no scan; every other
directory part re-lands.
2026-08-03 13:27:45 +08:00