Merge pull request #3219 from deepseek-harness/perf/tsconfig-paths-flatten

perf(infra): map each workspace package to an explicit path alias
This commit is contained in:
Yichen Jiang
2026-08-27 20:16:56 +08:00
committed by GitHub
11 changed files with 825 additions and 111 deletions
@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-27-explicit-workspace-path-aliases.md
2026-08-27-explicit-workspace-path-aliases.md: 51d2dee7911d323637121f509e160ef92c352568
2026-08-27-explicit-workspace-path-aliases.zh.md: 702d3d7a8cf91c8c307b1708fc30faad6cab009a
@@ -0,0 +1,61 @@
# Agent Note: Explicit workspace path aliases replace per-group wildcards
Status: implemented
English | [中文](2026-08-27-explicit-workspace-path-aliases.zh.md)
## Problem
`tsconfig.base.json` is the resolution facade for the whole repository: every package project extends it, both aggregates read it, and every Vitest config points `vite-tsconfig-paths` at it. Two of its aliases carried one candidate per package *group* rather than one per package — `@deepseek-ai/dsh-*` listed 49 candidate globs and `@deepseek-ai/dsh-*/invariant` listed 45.
TypeScript and tsx try those candidates in order and take the first that exists, so a specifier whose package sits late in the list pays for every earlier miss. Under the `dsh` source launch each miss is an `ERR_MODULE_NOT_FOUND` that Node decorates with `decorateErrorWithCommonJSHints`, which runs a full CommonJS resolution walk per failure. A profile of a source-launch boot attributed 934.6 ms — 35% of the boot — to that decoration path alone, from 60,942 failed resolutions.
The cost fell hardest on the most-imported packages. `packages/util/*` sat at position 44 of 49 and holds the leaf utilities nearly every plugin imports, so `dsh-timeout` paid roughly 9 ms per resolution against 0.05 ms for a specifier with an explicit alias.
## Decision
`scripts/gen-tsconfig-paths.ts` writes one explicit alias per workspace package into a marked region at the end of `paths`, and both group wildcards are deleted. `pnpm run gen-tsconfig-paths` rewrites the region; `pnpm run verify-tsconfig-paths` reports drift instead, and runs in the `ci-static` lane beside the other generated-artifact checks.
The generator emits an alias only for a package whose declared name is exactly `@deepseek-ai/dsh-<directory>`, because that is the only shape a wildcard could ever have resolved: it substituted the specifier's suffix into `packages/<group>/<suffix>/src`. Packages named after something other than their directory — `@deepseek-ai/dsh-typert-protocol` at `packages/typert/protocol`, the `dsh-client-*` and `dsh-host-*` families — already carry hand-written aliases and are left alone. A specifier claimed by two package directories throws rather than picking one, because an explicit map cannot express the group-order tiebreak the wildcard used; no such collision exists today.
Deleting the wildcards removed the fallback that used to resolve a package nobody had aliased, so the generator also asserts coverage: every workspace package carrying a `src` directory must be mapped by a generated or hand-written alias, and `--check` names any that is not. Without it a package whose name does not match its directory could be added, skipped by the generator, and left resolving through the workspace symlink to built `lib/` output — the same artifact-plane leak the explicit aliases exist to close.
The region is written by text surgery between marker comments rather than by re-serializing the file. `tsconfig.base.json` is JSONC and its hand-written aliases carry comments that explain non-obvious mappings; re-serializing would drop them.
This partly supersedes the [package-inventory discovery proposal](../../proposed/process/2026-06-20-discover-package-inventory.md), which records the collapse into one wildcard as current: the wildcard is gone, while that proposal's remaining subject — the aggregate configs' explicit `references` arrays — is untouched here.
Four wildcards remain, each with a single candidate: `dsh-host-*/invariant`, `dsh-client-*/invariant`, `dsh-client-*/client`, and the five `dsh-host-<name>/*` subpath maps. One candidate costs one probe, so expanding them would trade file size for nothing.
## Resolution differences this change makes
Every `@deepseek-ai/dsh-*` specifier appearing in repository sources — 1,023 distinct — resolves to the same target as before, with eleven exceptions that now resolve where they previously did not. All eleven previously reached built `lib/` output through the workspace symlink rather than source.
Seven are `/invariant` subpaths: `dsh-invariants/invariant`, `dsh-lsp/invariant`, `dsh-lsp-stdio/invariant`, `dsh-tool-lsp/invariant`, `dsh-terminal/invariant`, `dsh-terminal-bash/invariant`, and `dsh-tool-terminal/invariant`.
The deleted `dsh-*/invariant` wildcard omitted the `lsp`, `terminal`, `client`, and `host` groups. The `client` and `host` omissions are deliberate and documented — those families have dedicated wildcards because their package names prefix the group directory. The `lsp` and `terminal` omissions have no such reason, and `packages/runtime-diagnostics/invariants` appeared in neither list. Those seven specifiers therefore resolved through the workspace symlink and the package's `./invariant` export to built `lib/types/*.d.ts` instead of to source, which contradicts the rule that static gates resolve workspace imports through `paths` to `src` and pass on a clean tree. Making the aliases uniform resolves them to source like every sibling.
The other four are whole packages the coverage assertion surfaced: `dsh-client-ui-directory-picker-browse`, `dsh-client-ui-directory-picker-native`, `dsh-experimental-agent-team-profile`, and `dsh-experimental-agent-team-web-profile`. Each is named `dsh-<group>-<directory>`, which no wildcard could ever substitute, and each sits beside siblings that do carry hand-written aliases — they were simply missing. They now carry one too.
## Testing
`scripts/gen-tsconfig-paths.spec.ts` pins that the collector maps a package to its own directory, skips packages carrying hand-written aliases, and returns a sorted list; that the renderer yields to a hand-written specifier and closes the region without a trailing comma; that the region writer replaces only the marked span and refuses a config without markers; and that neither group wildcard survives in the committed config. Two further cases pin the coverage assertion: it names an unmapped package, and it reports none against the committed config.
The gate's rejection path is exercised directly: deleting one generated alias makes `verify-tsconfig-paths` exit non-zero, and restoring it makes the check pass.
The CLI entry guard uses the repository's established comparison, `import.meta.filename === resolve(process.argv[1])`, rather than concatenating a `file://` URL. The concatenated form fails whenever `import.meta.url` percent-encodes something `process.argv[1]` does not — a repository path containing a space, or any Windows drive path — and the failure is silent: the script exits 0 having done nothing, which would make the gate a no-op exactly where it is needed. Running a copy from a directory whose name contains a space reproduces that: the concatenated guard evaluates false, the established one true.
## Alternatives considered
**Reordering the wildcard's candidate globs so the hottest groups come first.** This needs no generator and no new gate, and recovers perhaps half the cost by moving `util`, `core`, `llm`, and `session` to the front. It was rejected because the win decays as packages are added, the ordering has no invariant a reader could check, and every group after the first still pays. It also leaves the worst property intact: adding a package group silently slows every boot.
**Moving `paths` into a generated `tsconfig.paths.json` that the base config extends.** This keeps the generated content out of the hand-written file entirely and produces a cleaner diff. It was rejected for this change because several consumers read `tsconfig.base.json` directly rather than through a resolver that follows `extends` — six Vitest configs plus `project-reference-faces.ts`, `verify-export-jsdoc.ts`, `doc-typecheck.ts`, and `rescope-vendor.ts` — and auditing each is a larger change than the aliasing itself. The marker region achieves the same isolation with no consumer risk.
**Keeping the wildcards as a fallback beneath the explicit aliases.** An explicit alias already wins over a wildcard, so correctness would be unchanged, and a package added without regenerating would keep resolving. It was rejected because the fallback is exactly what makes a stale config invisible: the repository's stance is that misconfiguration fails loud, and the `--check` gate turns a missing alias into a named failure instead of a slow boot nobody attributes.
## Consequences
A source-launch boot of the `headless` profile drops from a 2,157/2,182/2,153 ms baseline to 1,069/1,052/1,055 ms — about 1.1 seconds, or 51%, with the two ranges nowhere near overlapping and `--help` output byte-identical.
The win is confined to the tsx source launch. Vitest resolves through `vite-tsconfig-paths`, which matches in-process and checks file existence without ever constructing a Node module error, so it never paid the decoration cost: an A/B over one package's suite measured 5,934/5,829/5,908 ms against 5,878/5,851/5,905 ms, which is noise. Repository gate scripts import few `@deepseek-ai/dsh-*` packages and likewise show no separable difference. Shipped users run built `lib/` under plain Node and were never affected.
`paths` grows from 188 keys to 523, and adding a package now requires running the generator. The `--check` gate makes that a named failure rather than a silent one, and the generated region keeps the diff of such a change to a single line.
@@ -0,0 +1,61 @@
# Agent Note: Explicit workspace path aliases replace per-group wildcards
Status: implemented
[English](2026-08-27-explicit-workspace-path-aliases.md) | 中文
## Problem
`tsconfig.base.json` 是整个仓库的解析门面:每个包的 project 都 extends 它,两个聚合配置都读它,每个 Vitest 配置都把 `vite-tsconfig-paths` 指向它。其中两条别名按包**分组**而不是按包各写一条候选——`@deepseek-ai/dsh-*` 列了 49 个候选 glob`@deepseek-ai/dsh-*/invariant` 列了 45 个。
TypeScript 与 tsx 按顺序逐个尝试这些候选、取第一个存在的,因此一个位于列表靠后位置的包,其说明符要为前面每一次未命中买单。在 `dsh` 源码启动下,每次未命中都是一个 `ERR_MODULE_NOT_FOUND`,而 Node 会用 `decorateErrorWithCommonJSHints` 装饰它——每次失败都跑一遍完整的 CommonJS 解析走查。一次源码启动的 profile 把 **934.6 ms(占启动 35%)**单独归给了这条装饰路径,来源是 60,942 次失败解析。
代价最重的恰好落在被引用最多的包上:`packages/util/*` 排在 49 个候选里的第 44 位,却装着几乎每个插件都要引用的叶子工具,因此 `dsh-timeout` 每次解析约付 9 ms,而一个有显式别名的说明符只要 0.05 ms。
## Decision
`scripts/gen-tsconfig-paths.ts``paths` 末尾一个带标记的区域里,为每个 workspace 包写入一条显式别名,两条分组通配符随之删除。`pnpm run gen-tsconfig-paths` 重写该区域;`pnpm run verify-tsconfig-paths` 只报告漂移,并与其他生成物检查一起跑在 `ci-static` 车道上。
生成器只为**声明名恰好等于 `@deepseek-ai/dsh-<目录名>`** 的包发别名,因为那是通配符唯一可能解析出的形态:它把说明符的后缀代入 `packages/<group>/<后缀>/src`。名字与目录不一致的包——`packages/typert/protocol` 上的 `@deepseek-ai/dsh-typert-protocol`、以及 `dsh-client-*``dsh-host-*` 两族——本来就有手写别名,保持不动。若某个说明符被两个包目录同时认领,生成器**抛错**而不是任选其一,因为显式映射无法表达通配符依赖的分组顺序裁决;当前不存在这种冲突。
删除通配符也删掉了「没人写别名的包仍能解析」的兜底,因此生成器同时断言覆盖完备:每个含 `src` 的 workspace 包都必须被生成别名或手写别名映射,`--check` 会点名任何未被覆盖者。没有这条断言,一个名字与目录不一致的新包会被生成器跳过,继续经 workspace 软链解析到构建产物 `lib/`——正是显式别名要消除的产物层泄漏。
该区域用标记注释之间的**定点文本改写**生成,而不是重新序列化整个文件。`tsconfig.base.json` 是 JSONC,其手写别名带有解释非显然映射的注释,重新序列化会把它们丢掉。
本决策**部分取代**了[包清单自动发现提案](../../proposed/process/2026-06-20-discover-package-inventory.zh.md)——该提案把「合并为一个通配符」记为当前实现,而通配符已被删除;该提案剩余的主题(聚合配置里显式的 `references` 数组)不受本次改动影响。
保留四条通配符,每条只有一个候选:`dsh-host-*/invariant``dsh-client-*/invariant``dsh-client-*/client`,以及五条 `dsh-host-<name>/*` 子路径映射。一个候选只花一次探测,展开它们只会换来文件变大而无收益。
## Resolution differences this change makes
仓库源码中出现的每个 `@deepseek-ai/dsh-*` 说明符——共 1,023 个互不相同——解析目标与改动前完全一致,只有十一个例外:它们现在能解析,而此前不能。这十一个此前都是经 workspace 软链解析到构建产物 `lib/`,而不是源码。
其中七个是 `/invariant` 子路径:`dsh-invariants/invariant``dsh-lsp/invariant``dsh-lsp-stdio/invariant``dsh-tool-lsp/invariant``dsh-terminal/invariant``dsh-terminal-bash/invariant``dsh-tool-terminal/invariant`
被删除的 `dsh-*/invariant` 通配符遗漏了 `lsp``terminal``client``host` 四个分组。其中 `client``host` 的遗漏是**刻意且有文档的**——这两族有专用通配符,因为它们的包名以分组目录名为前缀。而 `lsp``terminal` 的遗漏没有任何这类理由,`packages/runtime-diagnostics/invariants` 则两条列表都不在。于是这七个说明符此前是通过 workspace 软链与包的 `./invariant` 导出解析到构建产物 `lib/types/*.d.ts`,而不是解析到源码——这与「静态门禁通过 `paths` 把 workspace 导入解析到 `src`、并在干净树上通过」的规则相抵触。把别名统一之后,它们与所有同类一样解析到源码。
另外四个是被覆盖断言揪出来的**整包**:`dsh-client-ui-directory-picker-browse``dsh-client-ui-directory-picker-native``dsh-experimental-agent-team-profile``dsh-experimental-agent-team-web-profile`。它们都叫 `dsh-<分组>-<目录>`,任何通配符都代不出这种形态;而它们身旁的同族包都有手写别名——这四个只是漏了。现在补上。
## Testing
`scripts/gen-tsconfig-paths.spec.ts` 钉住:收集器把包映射到它自己的目录、跳过带手写别名的包、返回有序列表;渲染器让位于手写说明符,且区域收尾不带多余逗号;区域写入器只替换标记范围,并在缺少标记时拒绝;以及提交后的配置里两条分组通配符都不复存在。另有两条用例钉住覆盖断言:它会点名未被映射的包,且对提交后的配置报告为空。
门禁的拒绝路径被直接验证过:删掉一条生成的别名会让 `verify-tsconfig-paths` 以非零码退出,恢复后检查通过。
CLI 入口守卫采用仓库既有的比较方式 `import.meta.filename === resolve(process.argv[1])`,而不是拼接 `file://` URL。拼接形式在 `import.meta.url` 做了百分号编码而 `process.argv[1]` 没做时失效——仓库路径含空格、或任何 Windows 盘符路径——且失效是静默的:脚本什么也不做就以 0 退出,恰恰会让这道门在最需要它的环境里形同虚设。把脚本复制到一个名字含空格的目录下运行即可复现:拼接式守卫求值为 false,既有写法为 true。
## Alternatives considered
**给通配符的候选 glob 重新排序,把最热的分组放前面。** 这不需要生成器也不需要新门禁,把 `util``core``llm``session` 挪到前面大约能拿回一半收益。否决理由:收益随着包的增加而衰减,这个顺序没有任何读者可核验的不变量,而且第一个分组之后的每一组仍然要付钱。它还保留了最糟的性质——新增一个包分组会悄悄拖慢所有人的启动。
**把 `paths` 挪进一个生成的 `tsconfig.paths.json`,由 base 配置 `extends`。** 这能把生成内容彻底移出手写文件,diff 也更干净。本次否决的理由是:有若干消费者**直接读** `tsconfig.base.json`,而不是通过会跟随 `extends` 的解析器——六个 Vitest 配置,外加 `project-reference-faces.ts``verify-export-jsdoc.ts``doc-typecheck.ts``rescope-vendor.ts`——逐个审计它们比这次别名改造本身还大。标记区域用零消费者风险达成了同样的隔离。
**在显式别名下方保留通配符作为兜底。** 显式别名本来就优先于通配符,因此正确性不变,而且新增包忘了重新生成也仍能解析。否决理由:兜底恰恰是让陈旧配置隐形的原因——仓库的立场是「misconfiguration fails loud」,而 `--check` 门禁把缺失的别名变成一次具名失败,而不是一次没人归因的慢启动。
## Consequences
`headless` profile 的源码启动从 2,157 / 2,182 / 2,153 ms 的基线降到 1,069 / 1,052 / 1,055 ms——约 **1.1 秒,51%**,两个区间相距极远,且 `--help` 输出逐字节一致。
**收益仅限于 tsx 源码启动这一条路径。** Vitest 走 `vite-tsconfig-paths`,它在进程内做匹配与文件存在性检查,从不构造 Node 模块错误,因此从未付过那笔装饰代价:对某个包的整套用例做 A/B,实测 5,934 / 5,829 / 5,908 ms 对 5,878 / 5,851 / 5,905 ms,属于噪声。仓库的门禁脚本只 import 少数几个 `@deepseek-ai/dsh-*` 包,同样测不出可分离的差异。发布用户在裸 Node 下跑构建好的 `lib/`,本来就不受影响。
`paths` 从 188 个 key 增长到 523 个,新增包时必须运行生成器。`--check` 门禁把这件事变成一次具名失败而非静默失败,而生成区域让这类改动的 diff 只有一行。
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/proposed/process/2026-06-20-discover-package-inventory.md
2026-06-20-discover-package-inventory.md: 7de865e43f87f0e41fad43b3786b9825509e9d50
2026-06-20-discover-package-inventory.zh.md: fed3d9dd8740b2dc22434f8af7e1e8c025502f61
2026-06-20-discover-package-inventory.md: 90ad595312431b942f3aac562e4ce8843fb6cc83
2026-06-20-discover-package-inventory.zh.md: 4c5312f17ddeab1d6457a1a904f921f44e7d0b9d
@@ -8,7 +8,7 @@ English | [中文](2026-06-20-discover-package-inventory.zh.md)
Package and gate inventories are repeated across TypeScript project references, package docs, CI prose, and Knip overrides. Most restate package layout, manifest data, or aggregate command contents. Each new package therefore creates avoidable synchronization points.
The [package hierarchy](../../archived/architecture/2026-06-20-package-hierarchy.md) already removed several of these by hand: `scripts/publint-all.ts` now derives its list from the `packages/<group>/<pkg>` layout, and the two `tsconfig` `paths` maps collapsed to one `@deepseek-ai/dsh-*` wildcard. What remains is the inventory that cannot be globbed away — chiefly the aggregate configs' (`tsconfig.host.json`, `tsconfig.client.json`) project `references`, which TypeScript requires as explicit arrays (no wildcard form).
The [package hierarchy](../../archived/architecture/2026-06-20-package-hierarchy.md) already removed several of these by hand: `scripts/publint-all.ts` now derives its list from the `packages/<group>/<pkg>` layout, and the two `tsconfig` `paths` maps collapsed to one `@deepseek-ai/dsh-*` wildcard — since reverted to one explicit alias per package, generated and gated, because resolving a wildcard's candidates in order dominated source-launch boot ([explicit workspace path aliases](../../implemented/process/2026-08-27-explicit-workspace-path-aliases.md)). What remains is the inventory that cannot be globbed away — chiefly the aggregate configs' (`tsconfig.host.json`, `tsconfig.client.json`) project `references`, which TypeScript requires as explicit arrays (no wildcard form).
Static lists are appropriate when they encode policy; they are needless friction when they duplicate manifest data or layout facts that already exist in `package.json`, workspace globs, or the package hierarchy.
@@ -8,7 +8,7 @@ Status: proposed
包与门禁清单在 TypeScript project references、包文档、CI 描述和 Knip 覆盖项中反复出现。大多数只是重述包布局、manifest(元数据清单)数据或聚合命令内容。因此每新增一个包都会产生本可避免的同步点。
[包层级结构](../../archived/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages/<group>/<pkg>` 布局推导列表,两份 `tsconfig``paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单,主要是聚合配置(`tsconfig.host.json``tsconfig.client.json`)中的项目引用(`references`)——TypeScript 要求它们是显式数组(没有通配符形式)。
[包层级结构](../../archived/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages/<group>/<pkg>` 布局推导列表,两份 `tsconfig``paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符——该合并此后已被回退为「每包一条、由生成器托管并有门禁把关」的显式别名,因为按顺序试候选的解析开销主导了源码启动时间([显式 workspace 路径别名](../../implemented/process/2026-08-27-explicit-workspace-path-aliases.zh.md)。剩下的是无法用 glob 消除的清单,主要是聚合配置(`tsconfig.host.json``tsconfig.client.json`)中的项目引用(`references`)——TypeScript 要求它们是显式数组(没有通配符形式)。
当静态列表编码的是策略时,它们是合理的;当它们只是重复 `package.json`、workspace glob 或包层级结构中已有的 manifest 数据或布局事实时,就是不必要的摩擦。
+2
View File
@@ -112,6 +112,8 @@
"rescope-vendor": "tsx scripts/rescope-vendor.ts",
"rescope-vendor:check": "tsx scripts/rescope-vendor.ts --check",
"verify-client-domain-graph": "tsx scripts/verify-client-domain-graph.ts",
"gen-tsconfig-paths": "tsx scripts/gen-tsconfig-paths.ts",
"verify-tsconfig-paths": "tsx scripts/gen-tsconfig-paths.ts --check",
"gen-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts",
"verify-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts --check",
"gen-cordis-api": "tsx scripts/gen-cordis-api.ts",
+98
View File
@@ -0,0 +1,98 @@
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
import {
collectPackageAliases,
collectPackageNames,
mappedSpecifiers,
renderAliases,
uncoveredPackages,
writeRegion,
} from './gen-tsconfig-paths.ts'
const root = resolve(import.meta.dirname, '..')
describe('generated tsconfig package aliases', () => {
it('maps each package to its own source directory', () => {
const aliases = collectPackageAliases()
expect(aliases.length).toBeGreaterThan(100)
const session = aliases.find(alias => alias.specifier === '@deepseek-ai/dsh-session')
expect(session).toEqual({
specifier: '@deepseek-ai/dsh-session',
source: './packages/core/session/src',
hasInvariant: true,
})
// Sorted, so a package added anywhere lands in a stable spot in the diff.
expect([...aliases].sort((a, b) => a.specifier.localeCompare(b.specifier))).toEqual(aliases)
// Only packages named after their directory: the rest carry hand-written
// aliases, because the removed wildcards could never have resolved them.
expect(aliases.some(alias => alias.specifier === '@deepseek-ai/dsh-typert-protocol')).toBe(false)
})
it('yields to a hand-written alias and closes without a trailing comma', () => {
const aliases = [
{ specifier: '@deepseek-ai/dsh-a', source: './packages/g/a/src', hasInvariant: true },
{ specifier: '@deepseek-ai/dsh-b', source: './packages/g/b/src', hasInvariant: false },
]
const body = renderAliases(aliases, new Set(['@deepseek-ai/dsh-a']))
// The hand-written bare alias is skipped; its /invariant sibling is not.
expect(body).toBe([
' "@deepseek-ai/dsh-a/invariant": ["./packages/g/a/src/invariant.ts"]',
' "@deepseek-ai/dsh-b": ["./packages/g/b/src"]',
].join(',\n'))
expect(body.endsWith(',')).toBe(false)
})
it('replaces only the marked region', () => {
const text = [
'{ "before": 1,',
' // BEGIN generated package aliases — pnpm run gen-tsconfig-paths',
' "stale": ["gone"]',
' // END generated package aliases',
' "after": 2 }',
].join('\n')
const next = writeRegion(text, ' "fresh": ["kept"]')
expect(next).toContain('{ "before": 1,')
expect(next).toContain(' "after": 2 }')
expect(next).toContain('"fresh": ["kept"]')
expect(next).not.toContain('stale')
})
it('refuses a config without the region markers', () => {
expect(() => writeRegion('{}', '')).toThrow('missing the generated-region markers')
})
it('names a package that no alias covers', () => {
// Deleting the group wildcards removed the fallback that used to resolve a
// package nobody had aliased. A package whose name does not match its
// directory is skipped by the generator, so without this check it would
// resolve through the workspace symlink to built lib/types instead.
expect(uncoveredPackages(
['@deepseek-ai/dsh-a', '@deepseek-ai/dsh-b'],
new Set(['@deepseek-ai/dsh-a', '@deepseek-ai/dsh-a/invariant']),
)).toEqual(['@deepseek-ai/dsh-b'])
expect(uncoveredPackages(['@deepseek-ai/dsh-a'], new Set(['@deepseek-ai/dsh-a']))).toEqual([])
})
it('covers every workspace package in the committed config', () => {
const config = readFileSync(resolve(root, 'tsconfig.base.json'), 'utf8')
// Includes the packages the generator skips because their name does not
// match their directory: those carry hand-written aliases.
const names = collectPackageNames()
expect(names).toContain('@deepseek-ai/dsh-typert-protocol')
expect(uncoveredPackages(names, mappedSpecifiers(config))).toEqual([])
})
it('leaves no wildcard that probes every package group', () => {
const config = readFileSync(resolve(root, 'tsconfig.base.json'), 'utf8')
// These two listed one candidate per group, so resolving a package late in
// the list cost a filesystem probe — and under tsx a decorated module
// error — for every group before it.
expect(config).not.toContain('"@deepseek-ai/dsh-*":')
expect(config).not.toContain('"@deepseek-ai/dsh-*/invariant":')
})
})
+248
View File
@@ -0,0 +1,248 @@
/**
* Expand the workspace path aliases that a wildcard would otherwise resolve by
* probing every package group in turn.
*
* `tsconfig.base.json` is the resolution facade for the whole repository, and
* two of its aliases used one key per *group* rather than per package:
* `@deepseek-ai/dsh-*` listed 49 candidate globs and `@deepseek-ai/dsh-*\/invariant`
* listed 45. TypeScript and tsx try those candidates in order, so a specifier
* whose package sits late in the list pays for every earlier miss. Under tsx's
* ESM hook each miss is an `ERR_MODULE_NOT_FOUND` that Node decorates with a
* full CommonJS resolution walk, which dominated source-launch boot.
*
* This generator writes one explicit entry per package into a marked region of
* `tsconfig.base.json`, leaving every hand-written alias and comment outside
* that region untouched. `--check` reports drift instead of writing, so a new
* package that needs an alias fails a gate rather than silently resolving
* through a fallback that no longer exists.
*
* @module scripts/gen-tsconfig-paths
*/
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'node:fs'
import { join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = fileURLToPath(new URL('..', import.meta.url))
const CONFIG = join(ROOT, 'tsconfig.base.json')
const BEGIN = ' // BEGIN generated package aliases — pnpm run gen-tsconfig-paths'
const END = ' // END generated package aliases'
/** Package-name prefix the expanded aliases cover. */
const PREFIX = '@deepseek-ai/dsh-'
/** One workspace package the generated region maps. */
interface PackageAlias {
/** Bare specifier, e.g. `@deepseek-ai/dsh-session`. */
readonly specifier: string
/** Repository-relative source directory, e.g. `./packages/session/session/src`. */
readonly source: string
/** Whether the package carries `src/invariant.ts`, which earns a second alias. */
readonly hasInvariant: boolean
}
/**
* Read a workspace manifest's declared name.
* @param manifest - absolute path to a `package.json`.
* @returns The declared name, or undefined when the file is absent or nameless.
*/
function packageName(manifest: string): string | undefined {
let parsed: unknown
try {
parsed = JSON.parse(readFileSync(manifest, 'utf8'))
} catch (_absentOrUnreadableManifest) {
return undefined
}
if (typeof parsed !== 'object' || parsed === null) return undefined
const name: unknown = (parsed as { name?: unknown }).name
return typeof name === 'string' ? name : undefined
}
/** One workspace package directory and the name its manifest declares. */
interface WorkspacePackage {
readonly group: string
readonly directory: string
readonly packageDir: string
readonly name: string
}
/**
* Walk `packages/<group>/<directory>` once, in a stable order.
* @returns Every directory whose manifest names a `@deepseek-ai/dsh-` package and that carries `src`.
*/
function workspacePackages(): WorkspacePackage[] {
const packages = join(ROOT, 'packages')
const found: WorkspacePackage[] = []
for (const group of readdirSync(packages).sort()) {
const groupDir = join(packages, group)
if (!statSync(groupDir).isDirectory()) continue
for (const directory of readdirSync(groupDir).sort()) {
const packageDir = join(groupDir, directory)
const name = packageName(join(packageDir, 'package.json'))
if (name === undefined || !name.startsWith(PREFIX)) continue
if (existsSync(join(packageDir, 'src'))) found.push({ group, directory, packageDir, name })
}
}
return found
}
/**
* Collect every package the removed wildcards could resolve.
*
* A wildcard substituted the specifier's suffix into `packages/<group>/<suffix>/src`,
* so it only ever resolved a package whose declared name is exactly
* `@deepseek-ai/dsh-<directory>`. Packages named after something other than
* their directory already carry a hand-written alias and are skipped here.
*
* @returns Aliases sorted by specifier.
* @throws When two package directories claim one specifier, which the removed
* wildcards resolved by group order and an explicit map cannot express.
*/
export function collectPackageAliases(): PackageAlias[] {
const bySpecifier = new Map<string, PackageAlias & { directory: string }>()
for (const { group, directory, packageDir, name } of workspacePackages()) {
if (name !== `${PREFIX}${directory}`) continue
const previous = bySpecifier.get(name)
if (previous !== undefined) {
throw new Error(
`gen-tsconfig-paths: ${name} is claimed by packages/${previous.directory} and packages/${group}/${directory}; `
+ 'an explicit alias cannot express the group-order tiebreak the wildcard used.',
)
}
bySpecifier.set(name, {
specifier: name,
source: `./packages/${group}/${directory}/src`,
hasInvariant: existsSync(join(packageDir, 'src', 'invariant.ts')),
directory: `${group}/${directory}`,
})
}
return [...bySpecifier.values()]
.map(({ specifier, source, hasInvariant }) => ({ specifier, source, hasInvariant }))
.sort((left, right) => left.specifier.localeCompare(right.specifier))
}
/**
* Collect every workspace package the aliases must cover.
*
* Unlike {@link collectPackageAliases} this keeps packages whose name does not
* match their directory. The generator cannot map those — only a hand-written
* alias can — but they still have to be mapped by something, because deleting
* the group wildcards removed the fallback that used to catch them.
*
* @returns Declared names of every `@deepseek-ai/dsh-` package carrying a `src` directory.
*/
export function collectPackageNames(): string[] {
return workspacePackages()
.map(({ name }) => name)
.sort((left, right) => left.localeCompare(right))
}
/**
* Read the bare package specifiers a config maps, generated region included.
* @param text - `tsconfig.base.json` contents.
* @returns Specifiers mapped without a subpath.
*/
export function mappedSpecifiers(text: string): Set<string> {
const keys = new Set<string>()
for (const match of text.matchAll(/^\s*"(@deepseek-ai\/dsh-[^"/]+)":/gm)) {
const key = match[1]
if (key !== undefined) keys.add(key)
}
return keys
}
/**
* Report packages that no alias maps.
*
* A package missing from `paths` still resolves — through the workspace symlink
* and the package's own `exports` — but to built `lib/` output rather than to
* source, which is the artifact-plane leak the explicit aliases exist to avoid.
* Naming it here turns that into a gate failure instead of a silent difference.
*
* @param packages - every workspace package that needs an alias.
* @param mapped - bare specifiers the config maps.
* @returns Unmapped package names, in the order given.
*/
export function uncoveredPackages(
packages: readonly string[],
mapped: ReadonlySet<string>,
): string[] {
return packages.filter(name => !mapped.has(name))
}
/**
* Render the generated region's alias lines.
* @param aliases - packages to map, in emission order.
* @param handWritten - specifiers already mapped outside the region; a duplicate key would shadow one silently.
* @returns The region body, one JSON member per line.
*/
export function renderAliases(aliases: readonly PackageAlias[], handWritten: ReadonlySet<string>): string {
const lines: string[] = []
for (const alias of aliases) {
if (!handWritten.has(alias.specifier)) {
lines.push(` ${JSON.stringify(alias.specifier)}: [${JSON.stringify(alias.source)}]`)
}
const invariant = `${alias.specifier}/invariant`
if (alias.hasInvariant && !handWritten.has(invariant)) {
lines.push(` ${JSON.stringify(invariant)}: [${JSON.stringify(`${alias.source}/invariant.ts`)}]`)
}
}
// The region closes `paths`, so the last member carries no trailing comma.
return lines.join(',\n')
}
/**
* Replace the generated region of a config's text.
* @param text - current `tsconfig.base.json` contents.
* @param body - rendered alias lines.
* @returns The updated contents.
* @throws When the markers are missing or out of order.
*/
export function writeRegion(text: string, body: string): string {
const begin = text.indexOf(BEGIN)
const end = text.indexOf(END)
if (begin < 0 || end < begin) {
throw new Error(`gen-tsconfig-paths: ${CONFIG} is missing the generated-region markers.`)
}
return `${text.slice(0, begin)}${BEGIN}\n${body}\n${END}${text.slice(end + END.length)}`
}
/**
* Parse the config's `paths` keys, ignoring the generated region.
* @param text - current `tsconfig.base.json` contents.
* @returns Specifiers mapped by hand.
*/
function handWrittenSpecifiers(text: string): Set<string> {
const begin = text.indexOf(BEGIN)
const end = text.indexOf(END)
const outside = begin < 0 || end < begin ? text : text.slice(0, begin) + text.slice(end)
const keys = new Set<string>()
for (const match of outside.matchAll(/^\s*"(@deepseek-ai\/[^"]+)":/gm)) {
const key = match[1]
if (key !== undefined) keys.add(key)
}
return keys
}
if (process.argv[1] && import.meta.filename === resolve(process.argv[1])) {
const check = process.argv.includes('--check')
const current = readFileSync(CONFIG, 'utf8')
const next = writeRegion(current, renderAliases(collectPackageAliases(), handWrittenSpecifiers(current)))
const uncovered = uncoveredPackages(collectPackageNames(), mappedSpecifiers(next))
if (uncovered.length > 0) {
console.error(
'gen-tsconfig-paths: no alias maps '
+ `${uncovered.join(', ')}; add a hand-written entry, because a package named after `
+ 'something other than its directory cannot be generated.',
)
process.exitCode = 1
} else if (current === next) {
console.log('gen-tsconfig-paths: tsconfig.base.json package aliases are current.')
} else if (check) {
console.error('gen-tsconfig-paths: tsconfig.base.json is stale; run `pnpm run gen-tsconfig-paths`.')
process.exitCode = 1
} else {
writeFileSync(CONFIG, next)
console.log('gen-tsconfig-paths: rewrote tsconfig.base.json package aliases.')
}
}
+1
View File
@@ -720,6 +720,7 @@ function docSyncLeafGates(options: {
pnpmScript('doc-refs', 'verify-doc-refs', { label: 'doc refs', quick: true }),
pnpmScript('subsystem-pages', 'verify-subsystem-pages', { label: 'subsystem pages' }),
pnpmScript('package-paths', 'verify-package-paths', { label: 'package paths' }),
pnpmScript('tsconfig-paths', 'verify-tsconfig-paths', { label: 'tsconfig paths' }),
pnpmScript('config-source-ownership', 'verify-config-source-ownership', { label: 'config source ownership' }),
pnpmScript('package-readme-model-experience', 'verify-package-readme-model-experience', { label: 'package README model experience', quick: true }),
pnpmScript('agent-note-classification', 'verify-agent-note-classification', { label: 'agent note classification', quick: true }),
+344 -107
View File
@@ -127,67 +127,15 @@
"@deepseek-ai/dsh-experimental-webworker-packer/invariant": ["./packages/experimental/webworker-packer/src/invariant.ts"],
"@deepseek-ai/dsh-experimental-inspector/invariant": ["./packages/experimental/inspector/src/invariant.ts"],
"@deepseek-ai/dsh-util-crypto/invariant": ["./packages/util/crypto/src/invariant.ts"],
"@deepseek-ai/dsh-*/invariant": [
"./packages/core/*/src/invariant.ts",
"./packages/prompt/*/src/invariant.ts",
"./packages/llm/*/src/invariant.ts",
"./packages/shell/*/src/invariant.ts",
"./packages/subprocess/*/src/invariant.ts",
"./packages/e2b/*/src/invariant.ts",
"./packages/code-runtime/*/src/invariant.ts",
"./packages/fs/*/src/invariant.ts",
"./packages/skill/*/src/invariant.ts",
"./packages/compaction/*/src/invariant.ts",
"./packages/context/*/src/invariant.ts",
"./packages/goal/*/src/invariant.ts",
"./packages/feedback/*/src/invariant.ts",
"./packages/schedule/*/src/invariant.ts",
"./packages/guard/*/src/invariant.ts",
"./packages/plan/*/src/invariant.ts",
"./packages/preset/*/src/invariant.ts",
"./packages/subagent/*/src/invariant.ts",
"./packages/jobs/*/src/invariant.ts",
"./packages/experimental/*/src/invariant.ts",
"./packages/workflow/*/src/invariant.ts",
"./packages/webhook/*/src/invariant.ts",
"./packages/web/*/src/invariant.ts",
"./packages/attachment/*/src/invariant.ts",
"./packages/spill/*/src/invariant.ts",
"./packages/todo/*/src/invariant.ts",
"./packages/bundle/*/src/invariant.ts",
"./packages/extensions/*/src/invariant.ts",
"./packages/sandbox/*/src/invariant.ts",
"./packages/hooks/*/src/invariant.ts",
"./packages/session/*/src/invariant.ts",
"./packages/session-query/*/src/invariant.ts",
"./packages/settings/*/src/invariant.ts",
"./packages/credentials/*/src/invariant.ts",
"./packages/acp/*/src/invariant.ts",
"./packages/storage/*/src/invariant.ts",
"./packages/workspace/*/src/invariant.ts",
"./packages/sdk/*/src/invariant.ts",
"./packages/interaction/*/src/invariant.ts",
"./packages/boot/*/src/invariant.ts",
"./packages/examples/*/src/invariant.ts",
"./packages/util/*/src/invariant.ts",
"./packages/mcp/*/src/invariant.ts",
"./packages/identity/*/src/invariant.ts",
"./packages/test-support/*/src/invariant.ts"
],
// host/client package names prefix the group dir (dsh-client-<dir>), so
// the generic dsh-*/invariant list above cannot map them; strip the
// group prefix with a dedicated wildcard per group instead.
// the generated aliases below — which map a package only when its name is
// exactly dsh-<dir> — skip them; strip the group prefix with a dedicated
// wildcard per group instead.
"@deepseek-ai/dsh-host-*/invariant": ["./packages/host/*/src/invariant.ts"],
"@deepseek-ai/dsh-client-*/invariant": ["./packages/client/*/src/invariant.ts"],
"@deepseek-ai/dsh-headless/startup": ["./packages/bundle/headless/src/startup.ts"],
"@deepseek-ai/dsh-web-app/startup": ["./packages/bundle/web-app/src/startup.ts"],
"@deepseek-ai/dsh-client-*/client": ["./packages/client/*/src/client"],
// One wildcard maps every @deepseek-ai/dsh-<name> to its source. Package
// dir names are unique across groups, so first-on-disk-wins resolution is
// unambiguous; adding a package under an existing group needs no edit
// here. The aggregates' project references (tsconfig.host.json /
// tsconfig.client.json) stay explicit — TS project references have no
// wildcard form.
"@deepseek-ai/dsh-host-apiproxy": ["./packages/host/apiproxy/src"],
"@deepseek-ai/dsh-host-directory-picker": ["./packages/host/directory-picker/src"],
"@deepseek-ai/dsh-host-directory-picker/*": ["./packages/host/directory-picker/src/*"],
@@ -263,69 +211,358 @@
"@deepseek-ai/dsh-client-ui-settings-plugin-inventory": ["./packages/client/ui-settings-plugin-inventory/src"],
"@deepseek-ai/dsh-client-locale": ["./packages/client/locale/src"],
"@deepseek-ai/dsh-client-web": ["./packages/client/web/src"],
"@deepseek-ai/dsh-client-ui-directory-picker-browse": ["./packages/client/ui-directory-picker-browse/src"],
"@deepseek-ai/dsh-client-ui-directory-picker-native": ["./packages/client/ui-directory-picker-native/src"],
// sdk/ folders are role-named without their npm-side sdk/jsonrpc prefixes,
// so the generic wildcard cannot map these three package names.
// so their names do not match their directories and the generated aliases
// below cannot map them; these three stay hand-written.
"@deepseek-ai/dsh-sdk-client": ["./packages/sdk/client/src"],
"@deepseek-ai/dsh-sdk-protocol": ["./packages/sdk/protocol/src"],
"@deepseek-ai/dsh-sdk-jsonrpc-server": ["./packages/sdk/server/src"],
"@deepseek-ai/dsh-experimental-agent-team": ["./packages/experimental/agent-team/src"],
"@deepseek-ai/dsh-experimental-agent-team-profile": ["./packages/experimental/agent-team-profile/src"],
"@deepseek-ai/dsh-experimental-agent-team-web-profile": ["./packages/experimental/agent-team-web-profile/src"],
"@deepseek-ai/dsh-experimental-tool-agent-team": ["./packages/experimental/tool-agent-team/src"],
"@deepseek-ai/dsh-experimental-webworker-runtime": ["./packages/experimental/webworker-runtime/src"],
"@deepseek-ai/dsh-experimental-webworker-packer": ["./packages/experimental/webworker-packer/src"],
"@deepseek-ai/dsh-experimental-inspector": ["./packages/experimental/inspector/src"],
"@deepseek-ai/dsh-experimental-inspector/client": ["./packages/experimental/inspector/src/client/index.ts"],
"@deepseek-ai/dsh-util-crypto": ["./packages/util/crypto/src"],
"@deepseek-ai/dsh-*": [
"./packages/core/*/src",
"./packages/prompt/*/src",
"./packages/llm/*/src",
"./packages/shell/*/src",
"./packages/terminal/*/src",
"./packages/subprocess/*/src",
"./packages/e2b/*/src",
"./packages/code-runtime/*/src",
"./packages/fs/*/src",
"./packages/lsp/*/src",
"./packages/skill/*/src",
"./packages/compaction/*/src",
"./packages/context/*/src",
"./packages/goal/*/src",
"./packages/feedback/*/src",
"./packages/schedule/*/src",
"./packages/guard/*/src",
"./packages/plan/*/src",
"./packages/preset/*/src",
"./packages/subagent/*/src",
"./packages/jobs/*/src",
"./packages/experimental/*/src",
"./packages/workflow/*/src",
"./packages/webhook/*/src",
"./packages/web/*/src",
"./packages/attachment/*/src",
"./packages/spill/*/src",
"./packages/todo/*/src",
"./packages/bundle/*/src",
"./packages/extensions/*/src",
"./packages/sandbox/*/src",
"./packages/hooks/*/src",
"./packages/session/*/src",
"./packages/session-query/*/src",
"./packages/settings/*/src",
"./packages/credentials/*/src",
"./packages/acp/*/src",
"./packages/storage/*/src",
"./packages/workspace/*/src",
"./packages/sdk/*/src",
"./packages/interaction/*/src",
"./packages/boot/*/src",
"./packages/examples/*/src",
"./packages/util/*/src",
"./packages/mcp/*/src",
"./packages/identity/*/src",
"./packages/test-support/*/src",
"./packages/host/*/src",
"./packages/client/*/src"
]
// BEGIN generated package aliases — pnpm run gen-tsconfig-paths
"@deepseek-ai/dsh-acp": ["./packages/acp/acp/src"],
"@deepseek-ai/dsh-acp/invariant": ["./packages/acp/acp/src/invariant.ts"],
"@deepseek-ai/dsh-acp-app": ["./packages/bundle/acp-app/src"],
"@deepseek-ai/dsh-acp-app/invariant": ["./packages/bundle/acp-app/src/invariant.ts"],
"@deepseek-ai/dsh-agent": ["./packages/core/agent/src"],
"@deepseek-ai/dsh-agent-default-model": ["./packages/core/agent-default-model/src"],
"@deepseek-ai/dsh-agent-default-model/invariant": ["./packages/core/agent-default-model/src/invariant.ts"],
"@deepseek-ai/dsh-agent-instructions": ["./packages/context/agent-instructions/src"],
"@deepseek-ai/dsh-agent-instructions/invariant": ["./packages/context/agent-instructions/src/invariant.ts"],
"@deepseek-ai/dsh-agent-loop": ["./packages/core/agent-loop/src"],
"@deepseek-ai/dsh-agent-loop-testkit": ["./packages/test-support/agent-loop-testkit/src"],
"@deepseek-ai/dsh-agent-loop-testkit/invariant": ["./packages/test-support/agent-loop-testkit/src/invariant.ts"],
"@deepseek-ai/dsh-agent-presets": ["./packages/preset/agent-presets/src"],
"@deepseek-ai/dsh-agent-presets/invariant": ["./packages/preset/agent-presets/src/invariant.ts"],
"@deepseek-ai/dsh-agent-spine-demo": ["./packages/examples/agent-spine-demo/src"],
"@deepseek-ai/dsh-agent-spine-demo/invariant": ["./packages/examples/agent-spine-demo/src/invariant.ts"],
"@deepseek-ai/dsh-agent-tool-presentation": ["./packages/core/agent-tool-presentation/src"],
"@deepseek-ai/dsh-agent-tool-presentation/invariant": ["./packages/core/agent-tool-presentation/src/invariant.ts"],
"@deepseek-ai/dsh-anonymous-user-id": ["./packages/identity/anonymous-user-id/src"],
"@deepseek-ai/dsh-anonymous-user-id/invariant": ["./packages/identity/anonymous-user-id/src/invariant.ts"],
"@deepseek-ai/dsh-app-boot": ["./packages/boot/app-boot/src"],
"@deepseek-ai/dsh-app-boot/invariant": ["./packages/boot/app-boot/src/invariant.ts"],
"@deepseek-ai/dsh-atomic-write": ["./packages/util/atomic-write/src"],
"@deepseek-ai/dsh-atomic-write/invariant": ["./packages/util/atomic-write/src/invariant.ts"],
"@deepseek-ai/dsh-attachment": ["./packages/attachment/attachment/src"],
"@deepseek-ai/dsh-attachment/invariant": ["./packages/attachment/attachment/src/invariant.ts"],
"@deepseek-ai/dsh-attachment-local": ["./packages/attachment/attachment-local/src"],
"@deepseek-ai/dsh-attachment-local/invariant": ["./packages/attachment/attachment-local/src/invariant.ts"],
"@deepseek-ai/dsh-authorization": ["./packages/credentials/authorization/src"],
"@deepseek-ai/dsh-authorization/invariant": ["./packages/credentials/authorization/src/invariant.ts"],
"@deepseek-ai/dsh-base": ["./packages/bundle/base/src"],
"@deepseek-ai/dsh-base/invariant": ["./packages/bundle/base/src/invariant.ts"],
"@deepseek-ai/dsh-bash-local": ["./packages/shell/bash-local/src"],
"@deepseek-ai/dsh-bash-local/invariant": ["./packages/shell/bash-local/src/invariant.ts"],
"@deepseek-ai/dsh-bash-sandbox": ["./packages/shell/bash-sandbox/src"],
"@deepseek-ai/dsh-bash-sandbox/invariant": ["./packages/shell/bash-sandbox/src/invariant.ts"],
"@deepseek-ai/dsh-brand": ["./packages/util/brand/src"],
"@deepseek-ai/dsh-brand/invariant": ["./packages/util/brand/src/invariant.ts"],
"@deepseek-ai/dsh-cmdline": ["./packages/boot/cmdline/src"],
"@deepseek-ai/dsh-cmdline/invariant": ["./packages/boot/cmdline/src/invariant.ts"],
"@deepseek-ai/dsh-code-runtime": ["./packages/code-runtime/code-runtime/src"],
"@deepseek-ai/dsh-code-runtime/invariant": ["./packages/code-runtime/code-runtime/src/invariant.ts"],
"@deepseek-ai/dsh-code-runtime-python": ["./packages/code-runtime/code-runtime-python/src"],
"@deepseek-ai/dsh-code-runtime-python/invariant": ["./packages/code-runtime/code-runtime-python/src/invariant.ts"],
"@deepseek-ai/dsh-code-runtime-worker-thread": ["./packages/code-runtime/code-runtime-worker-thread/src"],
"@deepseek-ai/dsh-code-runtime-worker-thread/invariant": ["./packages/code-runtime/code-runtime-worker-thread/src/invariant.ts"],
"@deepseek-ai/dsh-command-compact": ["./packages/compaction/command-compact/src"],
"@deepseek-ai/dsh-command-compact/invariant": ["./packages/compaction/command-compact/src/invariant.ts"],
"@deepseek-ai/dsh-command-feedback": ["./packages/feedback/command-feedback/src"],
"@deepseek-ai/dsh-command-feedback/invariant": ["./packages/feedback/command-feedback/src/invariant.ts"],
"@deepseek-ai/dsh-command-goal": ["./packages/goal/command-goal/src"],
"@deepseek-ai/dsh-command-goal/invariant": ["./packages/goal/command-goal/src/invariant.ts"],
"@deepseek-ai/dsh-commands": ["./packages/interaction/commands/src"],
"@deepseek-ai/dsh-commands/invariant": ["./packages/interaction/commands/src/invariant.ts"],
"@deepseek-ai/dsh-compaction": ["./packages/compaction/compaction/src"],
"@deepseek-ai/dsh-compaction/invariant": ["./packages/compaction/compaction/src/invariant.ts"],
"@deepseek-ai/dsh-compaction-basic": ["./packages/compaction/compaction-basic/src"],
"@deepseek-ai/dsh-compaction-basic/invariant": ["./packages/compaction/compaction-basic/src/invariant.ts"],
"@deepseek-ai/dsh-compaction-tool-result-pruner": ["./packages/compaction/compaction-tool-result-pruner/src"],
"@deepseek-ai/dsh-compaction-tool-result-pruner/invariant": ["./packages/compaction/compaction-tool-result-pruner/src/invariant.ts"],
"@deepseek-ai/dsh-cordis-host-runner/invariant": ["./packages/extensions/cordis-host-runner/src/invariant.ts"],
"@deepseek-ai/dsh-credentials": ["./packages/credentials/credentials/src"],
"@deepseek-ai/dsh-credentials/invariant": ["./packages/credentials/credentials/src/invariant.ts"],
"@deepseek-ai/dsh-credentials-local": ["./packages/credentials/credentials-local/src"],
"@deepseek-ai/dsh-credentials-local/invariant": ["./packages/credentials/credentials-local/src/invariant.ts"],
"@deepseek-ai/dsh-deepseek-llm-api-extensions": ["./packages/llm/deepseek-llm-api-extensions/src"],
"@deepseek-ai/dsh-deepseek-llm-api-extensions/invariant": ["./packages/llm/deepseek-llm-api-extensions/src/invariant.ts"],
"@deepseek-ai/dsh-e2b": ["./packages/e2b/e2b/src"],
"@deepseek-ai/dsh-e2b/invariant": ["./packages/e2b/e2b/src/invariant.ts"],
"@deepseek-ai/dsh-file-reference": ["./packages/context/file-reference/src"],
"@deepseek-ai/dsh-file-reference/invariant": ["./packages/context/file-reference/src/invariant.ts"],
"@deepseek-ai/dsh-file-reference-local": ["./packages/context/file-reference-local/src"],
"@deepseek-ai/dsh-file-reference-local/invariant": ["./packages/context/file-reference-local/src/invariant.ts"],
"@deepseek-ai/dsh-fs": ["./packages/fs/fs/src"],
"@deepseek-ai/dsh-fs/invariant": ["./packages/fs/fs/src/invariant.ts"],
"@deepseek-ai/dsh-fs-e2b": ["./packages/e2b/fs-e2b/src"],
"@deepseek-ai/dsh-fs-e2b/invariant": ["./packages/e2b/fs-e2b/src/invariant.ts"],
"@deepseek-ai/dsh-fs-local": ["./packages/fs/fs-local/src"],
"@deepseek-ai/dsh-fs-local/invariant": ["./packages/fs/fs-local/src/invariant.ts"],
"@deepseek-ai/dsh-fs-observation-policy": ["./packages/fs/fs-observation-policy/src"],
"@deepseek-ai/dsh-fs-observation-policy/invariant": ["./packages/fs/fs-observation-policy/src/invariant.ts"],
"@deepseek-ai/dsh-fs-sandbox": ["./packages/fs/fs-sandbox/src"],
"@deepseek-ai/dsh-fs-sandbox/invariant": ["./packages/fs/fs-sandbox/src/invariant.ts"],
"@deepseek-ai/dsh-goal": ["./packages/goal/goal/src"],
"@deepseek-ai/dsh-goal/invariant": ["./packages/goal/goal/src/invariant.ts"],
"@deepseek-ai/dsh-goal-round-driver": ["./packages/goal/goal-round-driver/src"],
"@deepseek-ai/dsh-goal-round-driver/invariant": ["./packages/goal/goal-round-driver/src/invariant.ts"],
"@deepseek-ai/dsh-headless": ["./packages/bundle/headless/src"],
"@deepseek-ai/dsh-headless/invariant": ["./packages/bundle/headless/src/invariant.ts"],
"@deepseek-ai/dsh-home-paths": ["./packages/util/home-paths/src"],
"@deepseek-ai/dsh-home-paths/invariant": ["./packages/util/home-paths/src/invariant.ts"],
"@deepseek-ai/dsh-hook-protocol": ["./packages/hooks/hook-protocol/src"],
"@deepseek-ai/dsh-hook-protocol/invariant": ["./packages/hooks/hook-protocol/src/invariant.ts"],
"@deepseek-ai/dsh-hooks-claude-code": ["./packages/hooks/hooks-claude-code/src"],
"@deepseek-ai/dsh-hooks-claude-code/invariant": ["./packages/hooks/hooks-claude-code/src/invariant.ts"],
"@deepseek-ai/dsh-hooks-codex": ["./packages/hooks/hooks-codex/src"],
"@deepseek-ai/dsh-hooks-codex/invariant": ["./packages/hooks/hooks-codex/src/invariant.ts"],
"@deepseek-ai/dsh-invariants/invariant": ["./packages/runtime-diagnostics/invariants/src/invariant.ts"],
"@deepseek-ai/dsh-jobs": ["./packages/jobs/jobs/src"],
"@deepseek-ai/dsh-jobs/invariant": ["./packages/jobs/jobs/src/invariant.ts"],
"@deepseek-ai/dsh-jobs-local": ["./packages/jobs/jobs-local/src"],
"@deepseek-ai/dsh-jobs-local/invariant": ["./packages/jobs/jobs-local/src/invariant.ts"],
"@deepseek-ai/dsh-launch-environment": ["./packages/util/launch-environment/src"],
"@deepseek-ai/dsh-launch-environment/invariant": ["./packages/util/launch-environment/src/invariant.ts"],
"@deepseek-ai/dsh-llm": ["./packages/llm/llm/src"],
"@deepseek-ai/dsh-llm/invariant": ["./packages/llm/llm/src/invariant.ts"],
"@deepseek-ai/dsh-llm-deepseek": ["./packages/llm/llm-deepseek/src"],
"@deepseek-ai/dsh-llm-deepseek/invariant": ["./packages/llm/llm-deepseek/src/invariant.ts"],
"@deepseek-ai/dsh-llm-mock-server": ["./packages/test-support/llm-mock-server/src"],
"@deepseek-ai/dsh-llm-mock-server/invariant": ["./packages/test-support/llm-mock-server/src/invariant.ts"],
"@deepseek-ai/dsh-llm-pi-ai": ["./packages/llm/llm-pi-ai/src"],
"@deepseek-ai/dsh-llm-pi-ai/invariant": ["./packages/llm/llm-pi-ai/src/invariant.ts"],
"@deepseek-ai/dsh-llm-replay": ["./packages/test-support/llm-replay/src"],
"@deepseek-ai/dsh-llm-replay/invariant": ["./packages/test-support/llm-replay/src/invariant.ts"],
"@deepseek-ai/dsh-llm-retry": ["./packages/llm/llm-retry/src"],
"@deepseek-ai/dsh-llm-retry/invariant": ["./packages/llm/llm-retry/src/invariant.ts"],
"@deepseek-ai/dsh-loader-smoke": ["./packages/test-support/loader-smoke/src"],
"@deepseek-ai/dsh-loader-smoke/invariant": ["./packages/test-support/loader-smoke/src/invariant.ts"],
"@deepseek-ai/dsh-lsp": ["./packages/lsp/lsp/src"],
"@deepseek-ai/dsh-lsp/invariant": ["./packages/lsp/lsp/src/invariant.ts"],
"@deepseek-ai/dsh-lsp-stdio": ["./packages/lsp/lsp-stdio/src"],
"@deepseek-ai/dsh-lsp-stdio/invariant": ["./packages/lsp/lsp-stdio/src/invariant.ts"],
"@deepseek-ai/dsh-mcp-client": ["./packages/mcp/mcp-client/src"],
"@deepseek-ai/dsh-mcp-client/invariant": ["./packages/mcp/mcp-client/src/invariant.ts"],
"@deepseek-ai/dsh-message-feedback": ["./packages/feedback/message-feedback/src"],
"@deepseek-ai/dsh-message-feedback/invariant": ["./packages/feedback/message-feedback/src/invariant.ts"],
"@deepseek-ai/dsh-native-command": ["./packages/util/native-command/src"],
"@deepseek-ai/dsh-native-command/invariant": ["./packages/util/native-command/src/invariant.ts"],
"@deepseek-ai/dsh-output-retention": ["./packages/util/output-retention/src"],
"@deepseek-ai/dsh-output-retention/invariant": ["./packages/util/output-retention/src/invariant.ts"],
"@deepseek-ai/dsh-permission-presets": ["./packages/interaction/permission-presets/src"],
"@deepseek-ai/dsh-permission-presets/invariant": ["./packages/interaction/permission-presets/src/invariant.ts"],
"@deepseek-ai/dsh-persona": ["./packages/preset/persona/src"],
"@deepseek-ai/dsh-persona/invariant": ["./packages/preset/persona/src/invariant.ts"],
"@deepseek-ai/dsh-plan-mode": ["./packages/plan/plan-mode/src"],
"@deepseek-ai/dsh-plan-mode/invariant": ["./packages/plan/plan-mode/src/invariant.ts"],
"@deepseek-ai/dsh-plugin-package-inventory-deepseek": ["./packages/llm/plugin-package-inventory-deepseek/src"],
"@deepseek-ai/dsh-plugin-package-inventory-deepseek/invariant": ["./packages/llm/plugin-package-inventory-deepseek/src/invariant.ts"],
"@deepseek-ai/dsh-pwsh-local/invariant": ["./packages/shell/pwsh-local/src/invariant.ts"],
"@deepseek-ai/dsh-pwsh-sandbox": ["./packages/shell/pwsh-sandbox/src"],
"@deepseek-ai/dsh-pwsh-sandbox/invariant": ["./packages/shell/pwsh-sandbox/src/invariant.ts"],
"@deepseek-ai/dsh-repeat-tool-reminder": ["./packages/guard/repeat-tool-reminder/src"],
"@deepseek-ai/dsh-repeat-tool-reminder/invariant": ["./packages/guard/repeat-tool-reminder/src/invariant.ts"],
"@deepseek-ai/dsh-sandbox": ["./packages/sandbox/sandbox/src"],
"@deepseek-ai/dsh-sandbox/invariant": ["./packages/sandbox/sandbox/src/invariant.ts"],
"@deepseek-ai/dsh-sandbox-local": ["./packages/sandbox/sandbox-local/src"],
"@deepseek-ai/dsh-sandbox-local/invariant": ["./packages/sandbox/sandbox-local/src/invariant.ts"],
"@deepseek-ai/dsh-sandbox-policy": ["./packages/sandbox/sandbox-policy/src"],
"@deepseek-ai/dsh-sandbox-policy/invariant": ["./packages/sandbox/sandbox-policy/src/invariant.ts"],
"@deepseek-ai/dsh-sandbox-windows-acl": ["./packages/sandbox/sandbox-windows-acl/src"],
"@deepseek-ai/dsh-sandbox-windows-acl/invariant": ["./packages/sandbox/sandbox-windows-acl/src/invariant.ts"],
"@deepseek-ai/dsh-schedule": ["./packages/schedule/schedule/src"],
"@deepseek-ai/dsh-schedule/invariant": ["./packages/schedule/schedule/src/invariant.ts"],
"@deepseek-ai/dsh-scope": ["./packages/core/scope/src"],
"@deepseek-ai/dsh-sdk-app": ["./packages/bundle/sdk-app/src"],
"@deepseek-ai/dsh-sdk-app/invariant": ["./packages/bundle/sdk-app/src/invariant.ts"],
"@deepseek-ai/dsh-sdk-minimal": ["./packages/bundle/sdk-minimal/src"],
"@deepseek-ai/dsh-sdk-minimal/invariant": ["./packages/bundle/sdk-minimal/src/invariant.ts"],
"@deepseek-ai/dsh-session": ["./packages/core/session/src"],
"@deepseek-ai/dsh-session-checkpoint-policy": ["./packages/session/session-checkpoint-policy/src"],
"@deepseek-ai/dsh-session-checkpoint-policy/invariant": ["./packages/session/session-checkpoint-policy/src/invariant.ts"],
"@deepseek-ai/dsh-session-log-deepseek": ["./packages/session/session-log-deepseek/src"],
"@deepseek-ai/dsh-session-log-deepseek/invariant": ["./packages/session/session-log-deepseek/src/invariant.ts"],
"@deepseek-ai/dsh-session-log-export": ["./packages/session-query/session-log-export/src"],
"@deepseek-ai/dsh-session-log-export/invariant": ["./packages/session-query/session-log-export/src/invariant.ts"],
"@deepseek-ai/dsh-session-persistence": ["./packages/session/session-persistence/src"],
"@deepseek-ai/dsh-session-persistence/invariant": ["./packages/session/session-persistence/src/invariant.ts"],
"@deepseek-ai/dsh-session-persistence-jsonl": ["./packages/session/session-persistence-jsonl/src"],
"@deepseek-ai/dsh-session-persistence-jsonl/invariant": ["./packages/session/session-persistence-jsonl/src/invariant.ts"],
"@deepseek-ai/dsh-session-persistence-sqlite": ["./packages/session/session-persistence-sqlite/src"],
"@deepseek-ai/dsh-session-persistence-sqlite/invariant": ["./packages/session/session-persistence-sqlite/src/invariant.ts"],
"@deepseek-ai/dsh-session-projection": ["./packages/session/session-projection/src"],
"@deepseek-ai/dsh-session-projection/invariant": ["./packages/session/session-projection/src/invariant.ts"],
"@deepseek-ai/dsh-session-projection-cache": ["./packages/session/session-projection-cache/src"],
"@deepseek-ai/dsh-session-projection-cache/invariant": ["./packages/session/session-projection-cache/src/invariant.ts"],
"@deepseek-ai/dsh-session-query": ["./packages/session-query/session-query/src"],
"@deepseek-ai/dsh-session-query/invariant": ["./packages/session-query/session-query/src/invariant.ts"],
"@deepseek-ai/dsh-session-query-sqlite": ["./packages/session-query/session-query-sqlite/src"],
"@deepseek-ai/dsh-session-query-sqlite/invariant": ["./packages/session-query/session-query-sqlite/src/invariant.ts"],
"@deepseek-ai/dsh-session-reference": ["./packages/context/session-reference/src"],
"@deepseek-ai/dsh-session-reference/invariant": ["./packages/context/session-reference/src/invariant.ts"],
"@deepseek-ai/dsh-session-snapshot": ["./packages/test-support/session-snapshot/src"],
"@deepseek-ai/dsh-session-snapshot/invariant": ["./packages/test-support/session-snapshot/src/invariant.ts"],
"@deepseek-ai/dsh-session-stats": ["./packages/session/session-stats/src"],
"@deepseek-ai/dsh-session-stats/invariant": ["./packages/session/session-stats/src/invariant.ts"],
"@deepseek-ai/dsh-session-telemetry": ["./packages/session/session-telemetry/src"],
"@deepseek-ai/dsh-session-telemetry/invariant": ["./packages/session/session-telemetry/src/invariant.ts"],
"@deepseek-ai/dsh-session-telemetry-otel": ["./packages/session/session-telemetry-otel/src"],
"@deepseek-ai/dsh-session-telemetry-otel/invariant": ["./packages/session/session-telemetry-otel/src/invariant.ts"],
"@deepseek-ai/dsh-session-title": ["./packages/session/session-title/src"],
"@deepseek-ai/dsh-session-title/invariant": ["./packages/session/session-title/src/invariant.ts"],
"@deepseek-ai/dsh-session-title-all-prompts-llm": ["./packages/session/session-title-all-prompts-llm/src"],
"@deepseek-ai/dsh-session-title-all-prompts-llm/invariant": ["./packages/session/session-title-all-prompts-llm/src/invariant.ts"],
"@deepseek-ai/dsh-session-title-first-prompt-llm": ["./packages/session/session-title-first-prompt-llm/src"],
"@deepseek-ai/dsh-session-title-first-prompt-llm/invariant": ["./packages/session/session-title-first-prompt-llm/src/invariant.ts"],
"@deepseek-ai/dsh-session-title-llm": ["./packages/session/session-title-llm/src"],
"@deepseek-ai/dsh-session-title-llm/invariant": ["./packages/session/session-title-llm/src/invariant.ts"],
"@deepseek-ai/dsh-settings": ["./packages/settings/settings/src"],
"@deepseek-ai/dsh-settings/invariant": ["./packages/settings/settings/src/invariant.ts"],
"@deepseek-ai/dsh-settings-file": ["./packages/settings/settings-file/src"],
"@deepseek-ai/dsh-settings-file/invariant": ["./packages/settings/settings-file/src/invariant.ts"],
"@deepseek-ai/dsh-shell": ["./packages/shell/shell/src"],
"@deepseek-ai/dsh-shell/invariant": ["./packages/shell/shell/src/invariant.ts"],
"@deepseek-ai/dsh-shell-env/invariant": ["./packages/shell/shell-env/src/invariant.ts"],
"@deepseek-ai/dsh-skill": ["./packages/skill/skill/src"],
"@deepseek-ai/dsh-skill/invariant": ["./packages/skill/skill/src/invariant.ts"],
"@deepseek-ai/dsh-skill-badge": ["./packages/skill/skill-badge/src"],
"@deepseek-ai/dsh-skill-badge/invariant": ["./packages/skill/skill-badge/src/invariant.ts"],
"@deepseek-ai/dsh-skill-filesystem": ["./packages/skill/skill-filesystem/src"],
"@deepseek-ai/dsh-skill-filesystem/invariant": ["./packages/skill/skill-filesystem/src/invariant.ts"],
"@deepseek-ai/dsh-spill": ["./packages/spill/spill/src"],
"@deepseek-ai/dsh-spill/invariant": ["./packages/spill/spill/src/invariant.ts"],
"@deepseek-ai/dsh-spill-local": ["./packages/spill/spill-local/src"],
"@deepseek-ai/dsh-spill-local/invariant": ["./packages/spill/spill-local/src/invariant.ts"],
"@deepseek-ai/dsh-spill-policy": ["./packages/spill/spill-policy/src"],
"@deepseek-ai/dsh-spill-policy/invariant": ["./packages/spill/spill-policy/src/invariant.ts"],
"@deepseek-ai/dsh-storage": ["./packages/storage/storage/src"],
"@deepseek-ai/dsh-storage/invariant": ["./packages/storage/storage/src/invariant.ts"],
"@deepseek-ai/dsh-storage-domain": ["./packages/storage/storage-domain/src"],
"@deepseek-ai/dsh-storage-domain/invariant": ["./packages/storage/storage-domain/src/invariant.ts"],
"@deepseek-ai/dsh-storage-json": ["./packages/storage/storage-json/src"],
"@deepseek-ai/dsh-storage-json/invariant": ["./packages/storage/storage-json/src/invariant.ts"],
"@deepseek-ai/dsh-storage-sqlite": ["./packages/storage/storage-sqlite/src"],
"@deepseek-ai/dsh-storage-sqlite/invariant": ["./packages/storage/storage-sqlite/src/invariant.ts"],
"@deepseek-ai/dsh-subagent": ["./packages/subagent/subagent/src"],
"@deepseek-ai/dsh-subagent/invariant": ["./packages/subagent/subagent/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-acp": ["./packages/subagent/subagent-acp/src"],
"@deepseek-ai/dsh-subagent-acp/invariant": ["./packages/subagent/subagent-acp/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-claude-code": ["./packages/subagent/subagent-claude-code/src"],
"@deepseek-ai/dsh-subagent-claude-code/invariant": ["./packages/subagent/subagent-claude-code/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-codex": ["./packages/subagent/subagent-codex/src"],
"@deepseek-ai/dsh-subagent-codex/invariant": ["./packages/subagent/subagent-codex/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-dsh-sdk": ["./packages/subagent/subagent-dsh-sdk/src"],
"@deepseek-ai/dsh-subagent-dsh-sdk/invariant": ["./packages/subagent/subagent-dsh-sdk/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-fork-in-process": ["./packages/subagent/subagent-fork-in-process/src"],
"@deepseek-ai/dsh-subagent-fork-in-process/invariant": ["./packages/subagent/subagent-fork-in-process/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-in-process-driver": ["./packages/subagent/subagent-in-process-driver/src"],
"@deepseek-ai/dsh-subagent-in-process-driver/invariant": ["./packages/subagent/subagent-in-process-driver/src/invariant.ts"],
"@deepseek-ai/dsh-subagent-spawn-in-process": ["./packages/subagent/subagent-spawn-in-process/src"],
"@deepseek-ai/dsh-subagent-spawn-in-process/invariant": ["./packages/subagent/subagent-spawn-in-process/src/invariant.ts"],
"@deepseek-ai/dsh-subprocess": ["./packages/subprocess/subprocess/src"],
"@deepseek-ai/dsh-subprocess/invariant": ["./packages/subprocess/subprocess/src/invariant.ts"],
"@deepseek-ai/dsh-subprocess-e2b": ["./packages/e2b/subprocess-e2b/src"],
"@deepseek-ai/dsh-subprocess-e2b/invariant": ["./packages/e2b/subprocess-e2b/src/invariant.ts"],
"@deepseek-ai/dsh-subprocess-local": ["./packages/subprocess/subprocess-local/src"],
"@deepseek-ai/dsh-subprocess-local/invariant": ["./packages/subprocess/subprocess-local/src/invariant.ts"],
"@deepseek-ai/dsh-system-prompt": ["./packages/core/system-prompt/src"],
"@deepseek-ai/dsh-system-prompt/invariant": ["./packages/core/system-prompt/src/invariant.ts"],
"@deepseek-ai/dsh-terminal": ["./packages/terminal/terminal/src"],
"@deepseek-ai/dsh-terminal/invariant": ["./packages/terminal/terminal/src/invariant.ts"],
"@deepseek-ai/dsh-terminal-bash": ["./packages/terminal/terminal-bash/src"],
"@deepseek-ai/dsh-terminal-bash/invariant": ["./packages/terminal/terminal-bash/src/invariant.ts"],
"@deepseek-ai/dsh-time-context": ["./packages/context/time-context/src"],
"@deepseek-ai/dsh-time-context/invariant": ["./packages/context/time-context/src/invariant.ts"],
"@deepseek-ai/dsh-timeout": ["./packages/util/timeout/src"],
"@deepseek-ai/dsh-timeout/invariant": ["./packages/util/timeout/src/invariant.ts"],
"@deepseek-ai/dsh-tmux-context": ["./packages/context/tmux-context/src"],
"@deepseek-ai/dsh-tmux-context/invariant": ["./packages/context/tmux-context/src/invariant.ts"],
"@deepseek-ai/dsh-token-meter": ["./packages/llm/token-meter/src"],
"@deepseek-ai/dsh-token-meter/invariant": ["./packages/llm/token-meter/src/invariant.ts"],
"@deepseek-ai/dsh-tool-ask-user": ["./packages/interaction/tool-ask-user/src"],
"@deepseek-ai/dsh-tool-ask-user/invariant": ["./packages/interaction/tool-ask-user/src/invariant.ts"],
"@deepseek-ai/dsh-tool-bash": ["./packages/shell/tool-bash/src"],
"@deepseek-ai/dsh-tool-bash/invariant": ["./packages/shell/tool-bash/src/invariant.ts"],
"@deepseek-ai/dsh-tool-bash-persistent": ["./packages/shell/tool-bash-persistent/src"],
"@deepseek-ai/dsh-tool-bash-persistent/invariant": ["./packages/shell/tool-bash-persistent/src/invariant.ts"],
"@deepseek-ai/dsh-tool-cordis": ["./packages/extensions/tool-cordis/src"],
"@deepseek-ai/dsh-tool-cordis/invariant": ["./packages/extensions/tool-cordis/src/invariant.ts"],
"@deepseek-ai/dsh-tool-fs": ["./packages/fs/tool-fs/src"],
"@deepseek-ai/dsh-tool-fs/invariant": ["./packages/fs/tool-fs/src/invariant.ts"],
"@deepseek-ai/dsh-tool-fs-search": ["./packages/fs/tool-fs-search/src"],
"@deepseek-ai/dsh-tool-fs-search/invariant": ["./packages/fs/tool-fs-search/src/invariant.ts"],
"@deepseek-ai/dsh-tool-goal": ["./packages/goal/tool-goal/src"],
"@deepseek-ai/dsh-tool-goal/invariant": ["./packages/goal/tool-goal/src/invariant.ts"],
"@deepseek-ai/dsh-tool-jobs": ["./packages/jobs/tool-jobs/src"],
"@deepseek-ai/dsh-tool-jobs/invariant": ["./packages/jobs/tool-jobs/src/invariant.ts"],
"@deepseek-ai/dsh-tool-lsp": ["./packages/lsp/tool-lsp/src"],
"@deepseek-ai/dsh-tool-lsp/invariant": ["./packages/lsp/tool-lsp/src/invariant.ts"],
"@deepseek-ai/dsh-tool-pwsh/invariant": ["./packages/shell/tool-pwsh/src/invariant.ts"],
"@deepseek-ai/dsh-tool-pwsh-persistent": ["./packages/shell/tool-pwsh-persistent/src"],
"@deepseek-ai/dsh-tool-pwsh-persistent/invariant": ["./packages/shell/tool-pwsh-persistent/src/invariant.ts"],
"@deepseek-ai/dsh-tool-ralph": ["./packages/workflow/tool-ralph/src"],
"@deepseek-ai/dsh-tool-ralph/invariant": ["./packages/workflow/tool-ralph/src/invariant.ts"],
"@deepseek-ai/dsh-tool-session-query": ["./packages/session-query/tool-session-query/src"],
"@deepseek-ai/dsh-tool-session-query/invariant": ["./packages/session-query/tool-session-query/src/invariant.ts"],
"@deepseek-ai/dsh-tool-skill": ["./packages/skill/tool-skill/src"],
"@deepseek-ai/dsh-tool-skill/invariant": ["./packages/skill/tool-skill/src/invariant.ts"],
"@deepseek-ai/dsh-tool-str-replace-editor": ["./packages/fs/tool-str-replace-editor/src"],
"@deepseek-ai/dsh-tool-str-replace-editor/invariant": ["./packages/fs/tool-str-replace-editor/src/invariant.ts"],
"@deepseek-ai/dsh-tool-subagent": ["./packages/subagent/tool-subagent/src"],
"@deepseek-ai/dsh-tool-subagent/invariant": ["./packages/subagent/tool-subagent/src/invariant.ts"],
"@deepseek-ai/dsh-tool-subagent-control": ["./packages/subagent/tool-subagent-control/src"],
"@deepseek-ai/dsh-tool-subagent-control/invariant": ["./packages/subagent/tool-subagent-control/src/invariant.ts"],
"@deepseek-ai/dsh-tool-subagent-report": ["./packages/subagent/tool-subagent-report/src"],
"@deepseek-ai/dsh-tool-subagent-report/invariant": ["./packages/subagent/tool-subagent-report/src/invariant.ts"],
"@deepseek-ai/dsh-tool-terminal": ["./packages/terminal/tool-terminal/src"],
"@deepseek-ai/dsh-tool-terminal/invariant": ["./packages/terminal/tool-terminal/src/invariant.ts"],
"@deepseek-ai/dsh-tool-todo": ["./packages/todo/tool-todo/src"],
"@deepseek-ai/dsh-tool-todo/invariant": ["./packages/todo/tool-todo/src/invariant.ts"],
"@deepseek-ai/dsh-tool-web": ["./packages/web/tool-web/src"],
"@deepseek-ai/dsh-tool-web/invariant": ["./packages/web/tool-web/src/invariant.ts"],
"@deepseek-ai/dsh-tool-workflow": ["./packages/workflow/tool-workflow/src"],
"@deepseek-ai/dsh-tool-workflow/invariant": ["./packages/workflow/tool-workflow/src/invariant.ts"],
"@deepseek-ai/dsh-tools": ["./packages/core/tools/src"],
"@deepseek-ai/dsh-tools/invariant": ["./packages/core/tools/src/invariant.ts"],
"@deepseek-ai/dsh-user-approval": ["./packages/interaction/user-approval/src"],
"@deepseek-ai/dsh-user-approval/invariant": ["./packages/interaction/user-approval/src/invariant.ts"],
"@deepseek-ai/dsh-user-questions": ["./packages/interaction/user-questions/src"],
"@deepseek-ai/dsh-user-questions/invariant": ["./packages/interaction/user-questions/src/invariant.ts"],
"@deepseek-ai/dsh-web": ["./packages/web/web/src"],
"@deepseek-ai/dsh-web/invariant": ["./packages/web/web/src/invariant.ts"],
"@deepseek-ai/dsh-web-app": ["./packages/bundle/web-app/src"],
"@deepseek-ai/dsh-web-app/invariant": ["./packages/bundle/web-app/src/invariant.ts"],
"@deepseek-ai/dsh-web-fetch-http": ["./packages/web/web-fetch-http/src"],
"@deepseek-ai/dsh-web-fetch-http/invariant": ["./packages/web/web-fetch-http/src/invariant.ts"],
"@deepseek-ai/dsh-web-search-deepseek": ["./packages/web/web-search-deepseek/src"],
"@deepseek-ai/dsh-web-search-deepseek/invariant": ["./packages/web/web-search-deepseek/src/invariant.ts"],
"@deepseek-ai/dsh-web-search-exa": ["./packages/web/web-search-exa/src"],
"@deepseek-ai/dsh-web-search-exa/invariant": ["./packages/web/web-search-exa/src/invariant.ts"],
"@deepseek-ai/dsh-web-search-perplexity": ["./packages/web/web-search-perplexity/src"],
"@deepseek-ai/dsh-web-search-perplexity/invariant": ["./packages/web/web-search-perplexity/src/invariant.ts"],
"@deepseek-ai/dsh-webhook": ["./packages/webhook/webhook/src"],
"@deepseek-ai/dsh-webhook/invariant": ["./packages/webhook/webhook/src/invariant.ts"],
"@deepseek-ai/dsh-webhook-github": ["./packages/webhook/webhook-github/src"],
"@deepseek-ai/dsh-webhook-github/invariant": ["./packages/webhook/webhook-github/src/invariant.ts"],
"@deepseek-ai/dsh-win32-process": ["./packages/subprocess/win32-process/src"],
"@deepseek-ai/dsh-win32-process/invariant": ["./packages/subprocess/win32-process/src/invariant.ts"],
"@deepseek-ai/dsh-workflow": ["./packages/workflow/workflow/src"],
"@deepseek-ai/dsh-workflow/invariant": ["./packages/workflow/workflow/src/invariant.ts"],
"@deepseek-ai/dsh-workflow-worker-thread": ["./packages/workflow/workflow-worker-thread/src"],
"@deepseek-ai/dsh-workflow-worker-thread/invariant": ["./packages/workflow/workflow-worker-thread/src/invariant.ts"],
"@deepseek-ai/dsh-workspace": ["./packages/workspace/workspace/src"],
"@deepseek-ai/dsh-workspace/invariant": ["./packages/workspace/workspace/src/invariant.ts"]
// END generated package aliases
}
}
}