mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-14 04:01:35 +00:00
Merge pull request #3165 from deepseek-harness/worktree-npmdepresolve
fix(npm): bound published peer dependency relays
This commit is contained in:
+2
-2
@@ -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/implemented/architecture/2026-08-15-client-shells-and-dynamic-packages.md
|
||||
2026-08-15-client-shells-and-dynamic-packages.md: 016314d10f55e0b590e98944ca417bae658ab56a
|
||||
2026-08-15-client-shells-and-dynamic-packages.zh.md: 4e0277d1becab8467521dc21d0e5b7509d1ee993
|
||||
2026-08-15-client-shells-and-dynamic-packages.md: 1d67c778b6a06849324dd6095a98d57dc41b94f9
|
||||
2026-08-15-client-shells-and-dynamic-packages.zh.md: db1e4e7e7b319c283ae39a94535d88d4dc71d60a
|
||||
|
||||
+3
-3
@@ -57,11 +57,11 @@ After the `immediately` tier has registered its factories, the kernel creates al
|
||||
|
||||
### Dependency declarations
|
||||
|
||||
Every client package keeps Cordis in matching `peerDependencies` and `devDependencies`. A dynamic package that imports, re-exports, augments, or names an internal dynamic package in `dsh.client.inject` keeps that package as matching peer and development dependencies. Static client inputs and React modules are development-only inputs for a dynamic package because the shell supplies their runtime identities.
|
||||
Every Client package keeps Cordis in matching `peerDependencies` and `devDependencies`; Cordis is its only peer. Browser imports, type references, module augmentations, and `dsh.client.inject` are development inputs because the Client build and shipped profile supply their runtime identities. A package that also publishes a Host entry keeps that entry's runtime value imports in `dependencies`. [Published dependency faces](../process/2026-08-26-published-dependency-faces.md) owns package discovery, exceptions, and the explicit Host roster.
|
||||
|
||||
Ordinary installed libraries remain `dependencies`: a dynamic build may bundle a private implementation, while a `staticLinked` library retains its bare import for the final host. Each build face decides externality independently from npm sections. Published file lists cover every runtime entry, relative asset, and declaration file reached by the artifact.
|
||||
|
||||
`verify-client-packages` enforces these classifications, dependency sections, build forms, parser-preload alignment, shared-module requests, and module-graph acyclicity. The repository publint pass enforces publication closure. The verifier's `--fix` mode repairs only unambiguous manifest drift.
|
||||
`verify-package-dependencies` enforces and repairs dependency sections. `verify-client-packages` enforces build forms, parser-preload alignment, shared-module requests, and module-graph acyclicity. The repository publint pass enforces publication closure.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
@@ -77,7 +77,7 @@ Ordinary installed libraries remain `dependencies`: a dynamic build may bundle a
|
||||
|
||||
## Consequences
|
||||
|
||||
Bundle contents stay stable when an npm dependency moves between peer and development sections, because each build face declares externality directly. Static libraries remain host-assembled, while dynamic packages retain uniform artifacts and lifecycle governance.
|
||||
Bundle contents stay stable when an internal DSH relationship is development-only, because each build face declares externality directly. Static libraries remain host-assembled, while dynamic packages retain uniform artifacts and lifecycle governance. The shipped profile owns the complete Client package roster, so individual Client packages do not ask npm to solve the same graph again through peer placement.
|
||||
|
||||
The startup protocol depends on the modules package id, and modules must remain self-contained at runtime. Combo generation preserves its ordinary package artifact and gives every other row one shared initial transport; HMR uses the same route with that row as its sole resource. A missing bootstrap registration fails before Cordis starts; later plugin import, apply, and service-wait failures remain visible through the boot page's ACTIVE scan.
|
||||
|
||||
|
||||
+3
-3
@@ -57,11 +57,11 @@ Bootstrap combo 当前只登记 modules factory。启动内核把原始图与外
|
||||
|
||||
### 依赖声明
|
||||
|
||||
每个 client 包都把 Cordis 保持为 matching `peerDependencies` 和 `devDependencies`。动态包若 import、re-export、augment 内部动态包,或在 `dsh.client.inject` 中命名它,就把该包保持为 matching peer 与开发依赖。静态 client 输入和 React 模块对动态包只是开发依赖,因为外壳提供其运行期身份。
|
||||
每个 Client 包都把 Cordis 保持为范围一致的 `peerDependencies` 和 `devDependencies`;Cordis 是唯一的 peer。Browser import、类型引用、模块扩充与 `dsh.client.inject` 都是开发输入,因为 Client 构建与发布 profile 会提供其运行期身份。同时发布 Host 入口的包把该入口的运行期 value import 放在 `dependencies`。[发布依赖门面](../process/2026-08-26-published-dependency-faces.zh.md)负责包发现、例外与显式 Host 名册。
|
||||
|
||||
普通安装库仍放在 `dependencies`:动态构建可以内联私有实现,而 `staticLinked` 库会保留 bare import 交给最终宿主。各构建 face 独立决定 external,不由 npm 区段推导。发布文件列表覆盖产物实际可达的每个运行期入口、相对资产和声明文件。
|
||||
|
||||
`verify-client-packages` 会检查这些分类、依赖区段、构建形态、parser preload 对齐、共享模块请求和模块图无环性。仓库 publint pass 负责检查发布闭包。该验证器的 `--fix` 模式只修复无歧义的 manifest 漂移。
|
||||
`verify-package-dependencies` 检查并修复依赖区段。`verify-client-packages` 检查构建形态、parser preload 对齐、共享模块请求和模块图无环性。仓库 publint pass 负责检查发布闭包。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
@@ -77,7 +77,7 @@ Bootstrap combo 当前只登记 modules factory。启动内核把原始图与外
|
||||
|
||||
## Consequences
|
||||
|
||||
Npm 依赖在 peer 与开发区段间移动时,bundle 内容保持稳定,因为每个构建 face 都直接声明 external。静态库继续由宿主装配,动态包则保留统一产物与生命周期治理。
|
||||
内部 DSH 关系仅放在开发区段时,bundle 内容仍保持稳定,因为每个构建 face 都直接声明 external。静态库继续由宿主装配,动态包则保留统一产物与生命周期治理。发布 profile 拥有完整 Client 包名册,因此各 Client 包不再要求 npm 通过 peer placement 重复求解同一张图。
|
||||
|
||||
启动协议依赖 modules 的 package id,modules 还必须保持运行期自包含。Combo 生成保留其普通 package 产物,并为其他全部 row 提供一条共享初始传输;HMR 使用同一条路由,并只把该 row 作为资源。缺少 bootstrap registration 会在 Cordis 启动前失败;后续插件 import、apply 与 service 等待失败仍由启动页的 ACTIVE 扫描呈现。
|
||||
|
||||
|
||||
@@ -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/implemented/process/2026-08-10-npm-release-sequences.md
|
||||
2026-08-10-npm-release-sequences.md: 014bfe3abb2548a369cbfc6a5f11263303e0656a
|
||||
2026-08-10-npm-release-sequences.zh.md: a67311afd93d3f4f9f0a396237c9ce0b04db0a06
|
||||
2026-08-10-npm-release-sequences.md: f83bce914bae4cfc5a047bf975b623579dc9156f
|
||||
2026-08-10-npm-release-sequences.zh.md: c24e5c0a29af2f875136d439ce3fe06577c061b1
|
||||
|
||||
@@ -80,6 +80,12 @@ Every reference to a workspace member uses `workspace:^`, so `pnpm pack` substit
|
||||
|
||||
`scripts/check-workspace-constraints.ts` requires the protocol, so a new package cannot reintroduce a hand-written range; the invariant-companion rule requires `workspace:^` for `@deepseek-ai/dsh-invariants` for the same reason.
|
||||
|
||||
### Published dependency faces use an explicit policy
|
||||
|
||||
[`verify-package-dependencies`](../../../../scripts/verify-package-dependencies.ts) classifies workspace relationships by their published Client and Host use, keeps only Cordis as a peer in covered packages, and applies a small explicit Host roster. [Published dependency faces and bounded peer relays](2026-08-26-published-dependency-faces.md) owns the selection rules and rationale.
|
||||
|
||||
`pnpm run benchmark:npm-resolution` measures this graph manually with the installed npm executable. `pnpm run benchmark:npm-resolution:next` additionally tries each reachable unconfigured Host package and serially remeasures the leading candidates. Both commands use a loopback metadata registry and reject archive requests, so their duration excludes package downloads. Neither command is an aggregate gate because scheduler load and metadata completion order make wall-clock thresholds nondeterministic.
|
||||
|
||||
### An optional dependency is never loaded at module scope
|
||||
|
||||
A dependency in `optionalDependencies`, or a peer carrying `peerDependenciesMeta.<name>.optional`, may be absent from an installed tree — that absence is the whole promise of "optional". A static import is evaluated when the importing module loads, so one absent package stops being "this capability is unavailable" and becomes a load failure for everything that reaches the importing module. The failure appears only in an installed tree missing that package, and no test here constructs one: a workspace install always has every package, so the unit tests, the snapshots, and the packed-install probe all pass while the published package is broken for the consumer who declined the optional peer.
|
||||
|
||||
@@ -80,6 +80,12 @@ registry 的两个行为决定了「怎么尝试一次发布」。写入之间
|
||||
|
||||
`scripts/check-workspace-constraints.ts` 要求这个协议,所以新包无法再引入硬写的范围;同理,invariant companion 规则要求 `@deepseek-ai/dsh-invariants` 用 `workspace:^`。
|
||||
|
||||
### 发布依赖门面使用显式策略
|
||||
|
||||
[`verify-package-dependencies`](../../../../scripts/verify-package-dependencies.ts) 按已发布的 Client 与 Host 用法分类 workspace 关系,让受管包只保留 Cordis peer,并应用一份较小的显式 Host 名册。[发布依赖门面与有限 peer 中继](2026-08-26-published-dependency-faces.zh.md)记录选包规则与理由。
|
||||
|
||||
`pnpm run benchmark:npm-resolution` 使用当前安装的 npm 手动测量该依赖图。`pnpm run benchmark:npm-resolution:next` 还会逐个尝试每个可达且未配置的 Host 包,再串行复测领先候选。两个命令都使用回环 metadata registry 并拒绝包归档请求,因此耗时不包含包下载。调度器负载与 metadata 完成顺序会使墙钟阈值失去确定性,所以两个命令都不进入聚合门禁。
|
||||
|
||||
### optional 依赖绝不在模块作用域被加载
|
||||
|
||||
`optionalDependencies` 里的依赖,或带 `peerDependenciesMeta.<name>.optional` 的 peer,在安装出来的树里可以不存在——这份「可以不存在」正是 optional 的全部承诺。而静态 import 在引入方模块加载时就求值,于是一个缺失的包不再表现为「这个能力不可用」,而是变成所有能走到该模块的代码的加载失败。这种失败只在「缺了该包的安装树」里出现,而本仓没有任何测试构造这种树:workspace 安装总是把每个包都装上,所以单测、快照、打包安装探针全都会过,而那个拒绝了这个 optional peer 的消费者拿到的却是坏的包。
|
||||
|
||||
@@ -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-26-published-dependency-faces.md
|
||||
2026-08-26-published-dependency-faces.md: 668d4c721446a87388ae50951156d1b24f91138c
|
||||
2026-08-26-published-dependency-faces.zh.md: b10a285a81490f8eb66d70d3e73c2f676ad1b35c
|
||||
@@ -0,0 +1,93 @@
|
||||
# Agent Note: Published dependency faces and bounded peer relays
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-26-published-dependency-faces.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
A package may contain a browser bundle, a Host entry, shared TypeScript declarations, and Cordis injection metadata. Encoding all of those relationships as required npm peers made the published CLI expensive to install: npm installs peers automatically and repeatedly evaluates placement through deep, converging peer paths. Changing ranges or making the peers optional did not remove that traversal.
|
||||
|
||||
The package that chooses a Client build input is the shipped profile, while a Host value import is loaded by Node from the importing package. Those relationships need different npm sections. Applying one rule to every Host package would reduce the graph but would also create a large migration with no corresponding installation benefit.
|
||||
|
||||
## Decision
|
||||
|
||||
### Package selection
|
||||
|
||||
[`verify-package-dependencies`](../../../../scripts/verify-package-dependencies.ts) owns dependency-section policy. It always covers packages under `packages/client/` and every non-experimental package that declares `dsh.client`. Inside the directory, `dsh.client` marks a Client/Host package whose Host entry is scanned; a package without that declaration is a Client-only static build input. Outside the directory, `dsh.client` selects the same Client/Host scan. A `"./client"` export alone is an API and does not select npm dependency policy.
|
||||
|
||||
[`package-dependency-policy.ts`](../../../../scripts/package-dependency-policy.ts) provides explicit Client-face include and exclude lists. An include handles an exceptional package without `dsh.client`, while an exclude removes an automatically discovered dual-face package outside `packages/client/`. The verifier rejects unknown, stale, redundant, duplicate, overlapping, and ineffective entries. The include list is empty; the exclude list contains `@deepseek-ai/dsh-api-session-controller` and `@deepseek-ai/dsh-api-workspace-controller`. Adding Session Controller back would migrate nine more Host edges while its five-run candidate retest improved median resolution by only 0.15 seconds.
|
||||
|
||||
Host-only packages join the same policy through a separate explicit list. The list contains `@deepseek-ai/dsh-llm` and `@deepseek-ai/dsh-session`; source imports do not expand it.
|
||||
|
||||
### Dependency sections
|
||||
|
||||
Every covered package keeps `@deepseek-ai/cordis` in matching `peerDependencies` and `devDependencies`. Cordis is the shared plugin runtime whose identity the application controls.
|
||||
|
||||
A workspace package reached by a runtime value import from the Host entry closure belongs only in `dependencies` when every imported runtime export appears in the policy's `safeHostDependencyExports` table. An export whose constructor identity or module state must be shared appears in `peerRequiredHostExports`; importing one such export keeps the whole package edge in matching `peerDependencies` and `devDependencies`. Each table key is an exact module specifier and each value is a reviewed export set. The verifier follows runtime local imports from the Host entry, records named and default imports and re-exports, and rejects exports present in neither table; namespace, dynamic, and side-effect imports remain unbounded and cannot enter either table.
|
||||
|
||||
Workspace imports used by the Client bundle, type-only imports, module augmentations, `dsh.client.inject`, invariant companions, and existing metadata-only peers belong only in `devDependencies`. Ordinary third-party packages imported by the Host runtime belong in `dependencies`; other third-party relationships keep their declared section. Workspace references use `workspace:^`.
|
||||
|
||||
Some development relationships exist only in `dsh.client.inject` or TypeScript project references. The policy's `configurationOnlyDevDependencies` table names only those reviewed edges and keeps them in `devDependencies`.
|
||||
|
||||
The verifier reads source manifests and source files, so it runs on a clean tree without built `lib/`. Every selected Host face must have `src/index.ts`. An unclassified Host runtime export is a policy violation that blocks all `--fix` writes; a maintainer must review the export and classify it, change the source relationship, or change the package selection. Once source safety passes, `--fix` performs only the section and range changes implied by the classification and removes stale peer metadata.
|
||||
|
||||
### Maintainer workflow
|
||||
|
||||
Run the verifier without `--fix` for a read-only check of package selection, export classifications, dependency sections, workspace ranges, and peer metadata. An unclassified runtime import reports one clickable `path:line:column` diagnostic per imported export.
|
||||
|
||||
```sh
|
||||
pnpm run verify-package-dependencies
|
||||
```
|
||||
|
||||
Classify each new Host runtime export in [`package-dependency-policy.ts`](../../../../scripts/package-dependency-policy.ts) before generating manifests. `safeHostDependencyExports` permits an ordinary dependency; `peerRequiredHostExports` keeps the whole provider package edge in matching peer and development sections. An export may appear in exactly one table. After refactoring a peer-required export so duplicate package copies are safe, move that exact specifier and export to the safe table; an edge becomes an ordinary dependency only after none of its imported exports remain peer-required.
|
||||
|
||||
Generate the managed manifests and every directly derived artifact with one command. `--fix` writes nothing while a policy violation exists; after success it refreshes `pnpm-lock.yaml`, regenerates both module-graph languages and their pairing record, and prints the ordinary-dependency and peer-required edge lists.
|
||||
|
||||
```sh
|
||||
pnpm run verify-package-dependencies -- --fix
|
||||
git diff -- packages pnpm-lock.yaml docs/module-graph.md docs/module-graph.zh.md docs/module-graph.i18n.yaml
|
||||
```
|
||||
|
||||
Measure the working-tree graph and a Git ref through the local metadata-only registry. Each run creates a fresh consumer and npm cache, replaces inherited npm configuration with explicit peer, hoisting, and registry settings, executes `npm install --package-lock-only`, rejects archive downloads, and leaves the repository unchanged. `--runs` controls repetitions, `--timeout-ms` terminates the npm process tree after its deadline, and optional `--max-ms` makes the command fail when the slowest run exceeds a threshold.
|
||||
|
||||
```sh
|
||||
pnpm run benchmark:npm-resolution -- --runs=5 --timeout-ms=300000
|
||||
pnpm run benchmark:npm-resolution -- --ref=origin/master --runs=5 --timeout-ms=300000
|
||||
```
|
||||
|
||||
Verify package placement through two incompatible synthetic DSH releases. The verifier copies every current DSH manifest into `0.1.0` and `0.2.0`, asks npm for a package lock only, and rejects cross-release DSH resolution, unexpected DSH locations, unequal release inventories, multiple Cordis installations, and package archive requests. The local index contains only installed current-platform metadata, so npm-accepted probes for unavailable optional packages are reported without failing the check.
|
||||
|
||||
```sh
|
||||
pnpm run verify-npm-install-layout
|
||||
```
|
||||
|
||||
Rank the next Host package by applying the current policy in memory, measuring a baseline, trying each reachable unconfigured package, and serially retesting the fastest coarse candidates. Positive `gainSeconds` is `baseline median - candidate median`; `--candidates` limits the roster, `--jobs` controls coarse concurrency, and neither phase writes manifests. A selected candidate still requires export classification before it joins `hostPackages`.
|
||||
|
||||
```sh
|
||||
pnpm run benchmark:npm-resolution:next -- --runs=1 --finalist-runs=5 --finalists=5 --jobs=8 --timeout-ms=120000
|
||||
```
|
||||
|
||||
### Performance verification
|
||||
|
||||
[`verify-npm-install-layout`](../../../../scripts/verify-npm-install-layout.ts) is a deterministic package-path and version check in the `Release (dsh)` workflow on every pull request and master push; it does not enforce resolver duration. [`benchmark-npm-resolution`](../../../../scripts/benchmark-npm-resolution.ts) and [`benchmark-next-package-dependency`](../../../../scripts/benchmark-next-package-dependency.ts) remain manual because resolver time varies with machine load and metadata completion order. Their fresh-consumer, metadata-only runs isolate npm's dependency-tree calculation from registry latency and archive downloads, so relative results identify peer relays without creating a release-time performance promise.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep internal relationships as peers.** npm must place and validate each required peer along converging ancestry paths, which recreates the reported install-time failure even when all internal versions are compatible.
|
||||
|
||||
**Use the `"./client"` export as the Client-face roster.** A package may publish Client-facing types or a browser API without contributing a dynamically loaded row. Selecting that package broadens the migration to unrelated Host packages such as Goal, Session Title, and Todo. `dsh.client` identifies dynamic rows, while the `packages/client/` directory independently covers static Client inputs.
|
||||
|
||||
**Flatten every Host package.** This removes more peer work but expands the migration to packages whose individual benchmark result is negligible. The explicit Host list preserves the remaining peer contracts until measurement justifies another entry.
|
||||
|
||||
**Move every Client-related declaration to development-only.** A dual-face package's Host value imports remain real Node loads. Omitting them from the published dependency graph makes the package depend on accidental hoisting by a profile.
|
||||
|
||||
**Enforce a wall-clock threshold in CI.** Resolver time varies with machine load and metadata completion order. Deterministic manifest classification belongs in CI; timing remains a maintainer benchmark.
|
||||
|
||||
## Consequences
|
||||
|
||||
The published dependency graph follows artifact ownership instead of source-directory coupling. Client bundles and shipped profiles provide browser identities, Host modules install duplicate-safe values they load, and Cordis plus explicitly peer-required Host exports retain shared package instances.
|
||||
|
||||
Moving a public type-only relationship to `devDependencies` means a standalone TypeScript consumer must install the referenced type package when it consumes that declaration. The shipped profiles install the complete supported package family; supporting independently assembled TypeScript consumers would require a different policy.
|
||||
|
||||
The explicit overrides, Host list, and export classifications are reviewable decisions. Class constructors used by `instanceof`, symbols, and accessors for module-private registries require peers when their identity or state crosses package boundaries; being a value import alone does not make an export duplicate-safe. Changing a classification changes the installed graph and requires the focused verifier tests, the two-release layout check, and a fresh next-package benchmark. The metadata-only benchmark is diagnostic evidence, not a release-time performance promise.
|
||||
@@ -0,0 +1,93 @@
|
||||
# Agent Note: 发布依赖门面与有限 peer 中继
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-26-published-dependency-faces.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
一个包可能同时包含浏览器 bundle、Host 入口、共享 TypeScript 声明和 Cordis 注入元数据。把这些关系全部编码成必需 npm peer 会使已发布 CLI 的安装代价过高:npm 会自动安装 peer,并沿深层、反复汇合的 peer 路径重复执行放置检查。修改版本范围或把 peer 标成 optional 都不会消除这类遍历。
|
||||
|
||||
Client 构建输入由发布 profile 选择,而 Host value import 由导入它的包通过 Node 加载;两者需要不同的 npm 区段。把规则应用到每个 Host 包虽然也能缩小依赖图,却会制造一个没有对应安装收益的大范围迁移。
|
||||
|
||||
## 决策
|
||||
|
||||
### 包选择
|
||||
|
||||
[`verify-package-dependencies`](../../../../scripts/verify-package-dependencies.ts) 统一负责依赖区段策略。它始终覆盖 `packages/client/` 下的包,以及声明 `dsh.client` 的每个非实验包。在该目录内,`dsh.client` 标记需要扫描 Host 入口的 Client/Host 包;没有该声明的包是仅供 Client 编译的静态输入。在目录外,`dsh.client` 选择相同的 Client/Host 扫描。仅有 `"./client"` export 只是 API,不参与 npm 依赖策略选包。
|
||||
|
||||
[`package-dependency-policy.ts`](../../../../scripts/package-dependency-policy.ts) 提供显式 Client 门面 include 与 exclude 列表。include 用于没有 `dsh.client` 的例外包,exclude 用于移除 `packages/client/` 之外自动发现的双面包。验证器拒绝未知、失效、冗余、重复、相互重叠和无法生效的配置项。include 列表为空;exclude 列表包含 `@deepseek-ai/dsh-api-session-controller` 和 `@deepseek-ai/dsh-api-workspace-controller`。把 Session Controller 加回会多迁移九条 Host 边,而五次候选复测的 resolver 中位数仅改善 0.15 秒。
|
||||
|
||||
Host-only 包通过另一份显式列表加入同一策略。该列表包含 `@deepseek-ai/dsh-llm` 和 `@deepseek-ai/dsh-session`;源码 import 不会自动扩大列表。
|
||||
|
||||
### 依赖区段
|
||||
|
||||
每个受管包都把 `@deepseek-ai/cordis` 保持在范围一致的 `peerDependencies` 和 `devDependencies` 中。Cordis 是由应用控制身份的共享插件运行时。
|
||||
|
||||
Host 入口闭包中的运行期 value import 所到达的 workspace 包,只有在每个运行期导出都列入策略的 `safeHostDependencyExports` 表时才只属于 `dependencies`。constructor 身份或模块状态必须共享的导出列入 `peerRequiredHostExports`;一旦使用这类导出,整条包依赖边就保留在范围一致的 `peerDependencies` 与 `devDependencies` 中。表的每个 key 都是精确 module specifier,每个 value 都是经审查的导出集合。验证器从 Host 入口沿运行期本地 import 扫描,记录具名与默认 import 和 re-export,并拒绝两个表都未收录的导出;namespace、dynamic 和 side-effect import 无法限定导出范围,因此不能进入任一表。
|
||||
|
||||
Client bundle 使用的 workspace import、纯类型 import、模块扩充、`dsh.client.inject`、invariant companion 和仅有元数据的现存 peer 只属于 `devDependencies`。Host 运行时导入的普通第三方包属于 `dependencies`;其他第三方关系保持原区段。Workspace 引用使用 `workspace:^`。
|
||||
|
||||
部分开发期关系只存在于 `dsh.client.inject` 或 TypeScript project reference 中。策略的 `configurationOnlyDevDependencies` 表只列出这些已评审的依赖边,并将它们保留在 `devDependencies` 中。
|
||||
|
||||
验证器读取源码 manifest 和源码文件,因此可以在没有已构建 `lib/` 的干净工作树上运行。每个被选中的 Host face 都必须存在 `src/index.ts`。未分类的 Host 运行期导出属于策略违规,会阻止 `--fix` 的全部写入;维护者必须审查该导出,并选择分类该导出、修改源码关系或修改选包范围。源码安全检查通过后,`--fix` 只执行分类所确定的区段与范围变更,并删除失效的 peer 元数据。
|
||||
|
||||
### 维护流程
|
||||
|
||||
不带 `--fix` 运行验证器,会以只读方式检查选包范围、导出分类、依赖区段、workspace range 与 peer metadata。未分类的运行期 import 会按每个导出分别报告可点击的 `path:line:column` 诊断。
|
||||
|
||||
```sh
|
||||
pnpm run verify-package-dependencies
|
||||
```
|
||||
|
||||
生成 manifest 前,在 [`package-dependency-policy.ts`](../../../../scripts/package-dependency-policy.ts) 中分类每个新增 Host 运行期导出。`safeHostDependencyExports` 允许普通 dependency;`peerRequiredHostExports` 让整个提供包依赖边保留在范围一致的 peer 与开发区段。一个导出只能出现在一个表中。把 peer-required 导出重构到重复安装安全后,将该精确 specifier 与导出移入 safe 表;只有当一条依赖边的所有 import 都不再使用 peer-required 导出时,它才会成为普通 dependency。
|
||||
|
||||
用一条命令生成受管 manifest 和所有直接派生产物。存在策略违规时,`--fix` 不写任何文件;成功后,它会刷新 `pnpm-lock.yaml`、重新生成中英文 module graph 及其配对记录,并打印普通 dependency 与 peer-required 依赖边。
|
||||
|
||||
```sh
|
||||
pnpm run verify-package-dependencies -- --fix
|
||||
git diff -- packages pnpm-lock.yaml docs/module-graph.md docs/module-graph.zh.md docs/module-graph.i18n.yaml
|
||||
```
|
||||
|
||||
通过仅 metadata 的本地 registry 测量工作树依赖图与 Git ref。每轮都会创建全新 consumer 与 npm cache,用明确的 peer、hoisting 和 registry 设置替换继承的 npm 配置,执行 `npm install --package-lock-only`,拒绝下载包归档,并保持仓库不变。`--runs` 控制重复次数,`--timeout-ms` 会在期限到达后终止 npm 进程树,可选 `--max-ms` 会在最慢一轮超过阈值时让命令失败。
|
||||
|
||||
```sh
|
||||
pnpm run benchmark:npm-resolution -- --runs=5 --timeout-ms=300000
|
||||
pnpm run benchmark:npm-resolution -- --ref=origin/master --runs=5 --timeout-ms=300000
|
||||
```
|
||||
|
||||
通过两个互不兼容的 DSH 合成版本验证包落位。验证器把每份当前 DSH manifest 分别复制为 `0.1.0` 和 `0.2.0`,只要求 npm 生成 package lock,并拒绝跨版本 DSH 解析、非预期 DSH 路径、两套版本清单不一致、多个 Cordis 实例以及包归档请求。本地索引只包含当前平台已安装的 metadata,因此只报告而不拒绝 npm 已接受的不可用可选包探测。
|
||||
|
||||
```sh
|
||||
pnpm run verify-npm-install-layout
|
||||
```
|
||||
|
||||
计算下一项 Host 包时,命令会在内存中应用当前策略、测量 baseline、逐个尝试可达且未配置的包,并串行复测粗筛中最快的候选。正数 `gainSeconds` 等于 `baseline median - candidate median`;`--candidates` 限定名册,`--jobs` 控制粗筛并发度,两个阶段都不写 manifest。选中的候选仍需先完成导出分类,才能加入 `hostPackages`。
|
||||
|
||||
```sh
|
||||
pnpm run benchmark:npm-resolution:next -- --runs=1 --finalist-runs=5 --finalists=5 --jobs=8 --timeout-ms=120000
|
||||
```
|
||||
|
||||
### 性能验证
|
||||
|
||||
[`verify-npm-install-layout`](../../../../scripts/verify-npm-install-layout.ts) 是 `Release (dsh)` workflow 在每个 pull request 和 master push 上运行的确定性包路径与版本检查;它不限制 resolver 耗时。[`benchmark-npm-resolution`](../../../../scripts/benchmark-npm-resolution.ts) 与 [`benchmark-next-package-dependency`](../../../../scripts/benchmark-next-package-dependency.ts) 保持为手动工具,因为 resolver 耗时会随机器负载和 metadata 完成顺序变化。它们通过全新 consumer 和仅 metadata 的运行,把 npm 依赖树计算与 registry 延迟、包归档下载分离,因此相对结果可以定位 peer 中继,但不构成发布时性能承诺。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
**把内部关系继续保留为 peer。** npm 必须沿汇合的祖先路径放置并验证每个必需 peer;即使内部版本全部兼容,也会重新产生已报告的安装耗时问题。
|
||||
|
||||
**用 `"./client"` export 作为 Client 门面名册。** 包可能发布 Client 类型或浏览器 API,却不贡献动态装载 row。选中这类包会把迁移扩大到 Goal、Session Title 和 Todo 等无关 Host 包。`dsh.client` 标识动态 row,而 `packages/client/` 目录独立覆盖静态 Client 输入。
|
||||
|
||||
**拍平全部 Host 包。** 这会移除更多 peer 工作,却把迁移扩大到单包 benchmark 收益可忽略的包。显式 Host 列表会保留其余 peer 约束,直到测量结果证明应增加新成员。
|
||||
|
||||
**把所有 Client 相关声明都改为仅开发依赖。** 双面包的 Host value import 仍是实际的 Node 加载;从发布依赖图中删掉它们,会让包依赖 profile 的偶然提升。
|
||||
|
||||
**在 CI 中强制墙钟阈值。** Resolver 耗时会随机器负载和 metadata 完成顺序变化。确定性的 manifest 分类进入 CI,耗时测量保留为维护者 benchmark。
|
||||
|
||||
## 结果
|
||||
|
||||
发布依赖图按产物归属而不是源码目录耦合分类。Client bundle 与发布 profile 提供浏览器运行时身份,Host 模块安装自己加载的可重复实体,而 Cordis 和显式标为 peer-required 的 Host 导出继续共享包实例。
|
||||
|
||||
把公开纯类型关系放进 `devDependencies`,意味着独立 TypeScript 消费者在使用该声明时必须自行安装被引用的类型包。发布 profile 会安装完整的受支持包族;若要支持独立组装的 TypeScript 消费者,需要另一套策略。
|
||||
|
||||
显式 override、Host 列表与导出分类都是需要评审的决策。当 class constructor、symbol 和访问模块私有 registry 的函数跨包传递身份或状态时,它们要求 peer;仅仅属于 value import 并不能证明导出可重复安装。修改分类会改变安装图,因此需要运行聚焦 verifier 测试、双版本布局检查并重新执行 next-package benchmark。仅 metadata benchmark 是诊断证据,不是发布时安装耗时承诺。
|
||||
@@ -2,9 +2,9 @@
|
||||
# entries, all on one version. The vendored framework and the native packages are
|
||||
# separate sequences with their own workflows and version lines.
|
||||
#
|
||||
# Pack runs without credentials on every pull request and master push, so a
|
||||
# pull request proves the whole publish set still packs. Publication is a manual
|
||||
# workflow_dispatch of release-publish.yml from a dsh-v* tag.
|
||||
# Pack and dependency-layout verification run without credentials on every pull
|
||||
# request and master push. Publication is a manual workflow_dispatch of
|
||||
# release-publish.yml from a dsh-v* tag.
|
||||
name: Release (dsh)
|
||||
|
||||
on:
|
||||
@@ -26,6 +26,46 @@ env:
|
||||
DSH_TELEMETRY_DISABLED: '1'
|
||||
|
||||
jobs:
|
||||
dependencies:
|
||||
name: Dependency layout
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
dest: ${{ runner.temp }}/setup-pnpm
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
||||
|
||||
- name: Configure pnpm store path
|
||||
id: pnpm-store
|
||||
run: |
|
||||
store_root="$HOME/.local/share/pnpm/store"
|
||||
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
|
||||
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
|
||||
echo "path=$store_path" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
||||
|
||||
- name: Install (immutable)
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Verify dependency policy
|
||||
run: pnpm run verify-package-dependencies
|
||||
|
||||
- name: Verify npm install layout
|
||||
run: pnpm run verify-npm-install-layout
|
||||
|
||||
pack:
|
||||
name: Pack npm tarballs
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
@@ -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 docs/module-graph.md
|
||||
module-graph.md: 7c4ccbf6841070d37116641c1404a70cbb598769
|
||||
module-graph.zh.md: 4581a5bdda1e75a9678a731ab109d3b3c71b7434
|
||||
module-graph.md: e5225db8618a3d056257bf96e57e3ad99fb73134
|
||||
module-graph.zh.md: 9a5f72ef3ddcc8c3823dd59812869611dec77169
|
||||
|
||||
+153
-556
@@ -1,9 +1,9 @@
|
||||
<!-- Generated by scripts/gen-module-graph.ts — do not edit by hand.
|
||||
Run `pnpm run gen-module-graph` to regenerate. -->
|
||||
|
||||
# Module dependency graph
|
||||
# Shared-instance dependency graph
|
||||
|
||||
Inter-package dependencies among the `@deepseek-ai/dsh-*` harness packages, derived from each package's `peerDependencies` (the canonical runtime-dependency signal) and grouped by the `packages/<group>/<pkg>` hierarchy. An edge `a --> b` means package `a` depends on package `b`. Names have the `@deepseek-ai/dsh-` prefix stripped.
|
||||
Peer dependencies among the `@deepseek-ai/dsh-*` harness packages. A peer means the consumer requires a shared instance; ordinary runtime dependencies and development-only relationships are not shown. The graph is grouped by the `packages/<group>/<pkg>` hierarchy. An edge `a --> b` means package `a` has package `b` as a peer. Names omit the `@deepseek-ai/dsh-` prefix.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@@ -375,11 +375,6 @@ flowchart TD
|
||||
pkg_base --> pkg_invariants
|
||||
pkg_sdk_app --> pkg_invariants
|
||||
pkg_sdk_minimal --> pkg_invariants
|
||||
pkg_client_store --> pkg_invariants
|
||||
pkg_client_ui_primitives --> pkg_invariants
|
||||
pkg_client_ui_renderer --> pkg_invariants
|
||||
pkg_client_ui_slots --> pkg_invariants
|
||||
pkg_client_web --> pkg_invariants
|
||||
pkg_code_runtime --> pkg_invariants
|
||||
pkg_code_runtime_python --> pkg_invariants
|
||||
pkg_e2b --> pkg_invariants
|
||||
@@ -396,18 +391,37 @@ flowchart TD
|
||||
pkg_win32_process --> pkg_invariants
|
||||
pkg_llm_mock_server --> pkg_invariants
|
||||
pkg_typert_generator --> pkg_invariants
|
||||
pkg_typert_loader --> pkg_invariants
|
||||
pkg_typert_loader --> pkg_typert_registry
|
||||
pkg_typert_protocol --> pkg_invariants
|
||||
pkg_typert_registry --> pkg_invariants
|
||||
pkg_llm --> pkg_typert_protocol
|
||||
pkg_session --> pkg_scope
|
||||
pkg_api_gateway --> pkg_typert_protocol
|
||||
pkg_api_remotes --> pkg_scope
|
||||
pkg_attachment --> pkg_brand
|
||||
pkg_attachment --> pkg_invariants
|
||||
pkg_client_modules --> pkg_host_webserver
|
||||
pkg_client_modules --> pkg_invariants
|
||||
pkg_credentials --> pkg_brand
|
||||
pkg_credentials --> pkg_invariants
|
||||
pkg_subprocess_e2b --> pkg_e2b
|
||||
pkg_subprocess_e2b --> pkg_invariants
|
||||
pkg_subprocess_e2b --> pkg_subprocess
|
||||
pkg_subprocess_e2b --> pkg_timeout
|
||||
pkg_experimental_inspector --> pkg_client_modules
|
||||
pkg_experimental_inspector --> pkg_host_webserver
|
||||
pkg_experimental_inspector --> pkg_invariants
|
||||
pkg_experimental_webworker_runtime --> pkg_client_connection
|
||||
pkg_experimental_webworker_runtime --> pkg_client_modules
|
||||
pkg_experimental_webworker_runtime --> pkg_host_webserver
|
||||
pkg_experimental_webworker_runtime --> pkg_invariants
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_webserver
|
||||
pkg_host_directory_picker_auto --> pkg_invariants
|
||||
pkg_host_frontend_static --> pkg_client_connection
|
||||
pkg_host_frontend_static --> pkg_host_webserver
|
||||
pkg_host_frontend_static --> pkg_invariants
|
||||
pkg_host_plugin_inventory --> pkg_brand
|
||||
pkg_host_plugin_inventory --> pkg_invariants
|
||||
pkg_host_plugin_inventory --> pkg_typert_protocol
|
||||
@@ -423,32 +437,6 @@ flowchart TD
|
||||
pkg_subprocess_local --> pkg_invariants
|
||||
pkg_subprocess_local --> pkg_subprocess
|
||||
pkg_subprocess_local --> pkg_timeout
|
||||
pkg_typert_loader --> pkg_invariants
|
||||
pkg_typert_loader --> pkg_typert_registry
|
||||
pkg_llm --> pkg_attachment
|
||||
pkg_llm --> pkg_brand
|
||||
pkg_llm --> pkg_invariants
|
||||
pkg_llm --> pkg_timeout
|
||||
pkg_llm --> pkg_typert_protocol
|
||||
pkg_attachment_local --> pkg_attachment
|
||||
pkg_attachment_local --> pkg_home_paths
|
||||
pkg_attachment_local --> pkg_invariants
|
||||
pkg_client_hmr --> pkg_client_modules
|
||||
pkg_client_hmr --> pkg_host_webserver
|
||||
pkg_client_hmr --> pkg_invariants
|
||||
pkg_credentials_local --> pkg_atomic_write
|
||||
pkg_credentials_local --> pkg_credentials
|
||||
pkg_credentials_local --> pkg_home_paths
|
||||
pkg_credentials_local --> pkg_invariants
|
||||
pkg_credentials_local --> pkg_launch_environment
|
||||
pkg_experimental_inspector --> pkg_client_modules
|
||||
pkg_experimental_inspector --> pkg_host_webserver
|
||||
pkg_experimental_inspector --> pkg_invariants
|
||||
pkg_session --> pkg_brand
|
||||
pkg_session --> pkg_invariants
|
||||
pkg_session --> pkg_llm
|
||||
pkg_session --> pkg_scope
|
||||
pkg_session --> pkg_typert_protocol
|
||||
pkg_system_prompt --> pkg_invariants
|
||||
pkg_system_prompt --> pkg_llm
|
||||
pkg_system_prompt --> pkg_scope
|
||||
@@ -457,37 +445,28 @@ flowchart TD
|
||||
pkg_skill --> pkg_scope
|
||||
pkg_web --> pkg_invariants
|
||||
pkg_web --> pkg_llm
|
||||
pkg_authorization --> pkg_credentials
|
||||
pkg_authorization --> pkg_invariants
|
||||
pkg_authorization --> pkg_llm
|
||||
pkg_lsp --> pkg_brand
|
||||
pkg_lsp --> pkg_invariants
|
||||
pkg_lsp --> pkg_llm
|
||||
pkg_skill_badge --> pkg_invariants
|
||||
pkg_skill_badge --> pkg_skill
|
||||
pkg_web_fetch_http --> pkg_invariants
|
||||
pkg_web_fetch_http --> pkg_timeout
|
||||
pkg_web_fetch_http --> pkg_web
|
||||
pkg_web_search_exa --> pkg_invariants
|
||||
pkg_web_search_exa --> pkg_launch_environment
|
||||
pkg_web_search_exa --> pkg_web
|
||||
pkg_web_search_perplexity --> pkg_invariants
|
||||
pkg_web_search_perplexity --> pkg_launch_environment
|
||||
pkg_web_search_perplexity --> pkg_web
|
||||
pkg_spill --> pkg_brand
|
||||
pkg_spill --> pkg_invariants
|
||||
pkg_spill --> pkg_llm
|
||||
pkg_spill --> pkg_session
|
||||
pkg_app_boot --> pkg_home_paths
|
||||
pkg_app_boot --> pkg_invariants
|
||||
pkg_app_boot --> pkg_launch_environment
|
||||
pkg_app_boot --> pkg_system_prompt
|
||||
pkg_attachment_local --> pkg_attachment
|
||||
pkg_attachment_local --> pkg_home_paths
|
||||
pkg_attachment_local --> pkg_invariants
|
||||
pkg_code_runtime_worker_thread --> pkg_code_runtime
|
||||
pkg_code_runtime_worker_thread --> pkg_invariants
|
||||
pkg_code_runtime_worker_thread --> pkg_session
|
||||
pkg_code_runtime_worker_thread --> pkg_timeout
|
||||
pkg_persona --> pkg_invariants
|
||||
pkg_persona --> pkg_system_prompt
|
||||
pkg_authorization --> pkg_credentials
|
||||
pkg_authorization --> pkg_invariants
|
||||
pkg_authorization --> pkg_llm
|
||||
pkg_credentials_local --> pkg_atomic_write
|
||||
pkg_credentials_local --> pkg_credentials
|
||||
pkg_credentials_local --> pkg_home_paths
|
||||
pkg_credentials_local --> pkg_invariants
|
||||
pkg_credentials_local --> pkg_launch_environment
|
||||
pkg_lsp --> pkg_brand
|
||||
pkg_lsp --> pkg_invariants
|
||||
pkg_lsp --> pkg_llm
|
||||
pkg_sandbox --> pkg_invariants
|
||||
pkg_sandbox --> pkg_llm
|
||||
pkg_sandbox --> pkg_session
|
||||
@@ -516,8 +495,23 @@ flowchart TD
|
||||
pkg_fs --> pkg_invariants
|
||||
pkg_fs --> pkg_llm
|
||||
pkg_fs --> pkg_sandbox
|
||||
pkg_skill_badge --> pkg_invariants
|
||||
pkg_skill_badge --> pkg_skill
|
||||
pkg_web_fetch_http --> pkg_invariants
|
||||
pkg_web_fetch_http --> pkg_timeout
|
||||
pkg_web_fetch_http --> pkg_web
|
||||
pkg_web_search_exa --> pkg_invariants
|
||||
pkg_web_search_exa --> pkg_launch_environment
|
||||
pkg_web_search_exa --> pkg_web
|
||||
pkg_web_search_perplexity --> pkg_invariants
|
||||
pkg_web_search_perplexity --> pkg_launch_environment
|
||||
pkg_web_search_perplexity --> pkg_web
|
||||
pkg_spill_local --> pkg_invariants
|
||||
pkg_spill_local --> pkg_spill
|
||||
pkg_app_boot --> pkg_home_paths
|
||||
pkg_app_boot --> pkg_invariants
|
||||
pkg_app_boot --> pkg_launch_environment
|
||||
pkg_app_boot --> pkg_system_prompt
|
||||
pkg_message_feedback --> pkg_brand
|
||||
pkg_message_feedback --> pkg_invariants
|
||||
pkg_message_feedback --> pkg_llm
|
||||
@@ -525,6 +519,8 @@ flowchart TD
|
||||
pkg_message_feedback --> pkg_session_persistence
|
||||
pkg_message_feedback --> pkg_storage_domain
|
||||
pkg_message_feedback --> pkg_typert_protocol
|
||||
pkg_persona --> pkg_invariants
|
||||
pkg_persona --> pkg_system_prompt
|
||||
pkg_sandbox_local --> pkg_invariants
|
||||
pkg_sandbox_local --> pkg_llm
|
||||
pkg_sandbox_local --> pkg_sandbox
|
||||
@@ -618,6 +614,14 @@ flowchart TD
|
||||
pkg_hook_protocol --> pkg_invariants
|
||||
pkg_hook_protocol --> pkg_session
|
||||
pkg_hook_protocol --> pkg_shell
|
||||
pkg_api_workspace_controller --> pkg_api_gateway
|
||||
pkg_api_workspace_controller --> pkg_client_connection
|
||||
pkg_api_workspace_controller --> pkg_host_directory_picker
|
||||
pkg_api_workspace_controller --> pkg_invariants
|
||||
pkg_api_workspace_controller --> pkg_session
|
||||
pkg_api_workspace_controller --> pkg_storage_domain
|
||||
pkg_api_workspace_controller --> pkg_typert_protocol
|
||||
pkg_api_workspace_controller --> pkg_workspace
|
||||
pkg_file_reference --> pkg_agent
|
||||
pkg_file_reference --> pkg_invariants
|
||||
pkg_time_context --> pkg_agent
|
||||
@@ -1032,17 +1036,6 @@ flowchart TD
|
||||
pkg_web_app --> pkg_invariants
|
||||
pkg_web_app --> pkg_shell_env
|
||||
pkg_web_app --> pkg_system_prompt
|
||||
pkg_client_connection --> pkg_attachment
|
||||
pkg_client_connection --> pkg_brand
|
||||
pkg_client_connection --> pkg_commands
|
||||
pkg_client_connection --> pkg_credentials
|
||||
pkg_client_connection --> pkg_host_directory_picker
|
||||
pkg_client_connection --> pkg_host_webserver
|
||||
pkg_client_connection --> pkg_invariants
|
||||
pkg_client_connection --> pkg_llm
|
||||
pkg_client_connection --> pkg_session
|
||||
pkg_client_connection --> pkg_settings
|
||||
pkg_client_connection --> pkg_tool_todo
|
||||
pkg_compaction_tool_result_pruner --> pkg_compaction
|
||||
pkg_compaction_tool_result_pruner --> pkg_invariants
|
||||
pkg_compaction_tool_result_pruner --> pkg_llm
|
||||
@@ -1121,11 +1114,6 @@ flowchart TD
|
||||
pkg_tool_session_query --> pkg_system_prompt
|
||||
pkg_tool_session_query --> pkg_timeout
|
||||
pkg_tool_session_query --> pkg_tools
|
||||
pkg_api_gateway --> pkg_brand
|
||||
pkg_api_gateway --> pkg_client_connection
|
||||
pkg_api_gateway --> pkg_host_webserver
|
||||
pkg_api_gateway --> pkg_invariants
|
||||
pkg_api_gateway --> pkg_typert_registry
|
||||
pkg_compaction_basic --> pkg_agent
|
||||
pkg_compaction_basic --> pkg_commands
|
||||
pkg_compaction_basic --> pkg_compaction
|
||||
@@ -1167,13 +1155,6 @@ flowchart TD
|
||||
pkg_agent_spine_demo --> pkg_tool_jobs
|
||||
pkg_agent_spine_demo --> pkg_tool_skill
|
||||
pkg_agent_spine_demo --> pkg_tools
|
||||
pkg_experimental_webworker_runtime --> pkg_client_connection
|
||||
pkg_experimental_webworker_runtime --> pkg_client_modules
|
||||
pkg_experimental_webworker_runtime --> pkg_host_webserver
|
||||
pkg_experimental_webworker_runtime --> pkg_invariants
|
||||
pkg_host_frontend_static --> pkg_client_connection
|
||||
pkg_host_frontend_static --> pkg_host_webserver
|
||||
pkg_host_frontend_static --> pkg_invariants
|
||||
pkg_webhook_github --> pkg_credentials
|
||||
pkg_webhook_github --> pkg_host_webserver
|
||||
pkg_webhook_github --> pkg_invariants
|
||||
@@ -1261,14 +1242,6 @@ flowchart TD
|
||||
pkg_api_session_controller --> pkg_util_time
|
||||
pkg_api_session_controller --> pkg_util_workspace_path
|
||||
pkg_api_session_controller --> pkg_workspace
|
||||
pkg_api_workspace_controller --> pkg_api_gateway
|
||||
pkg_api_workspace_controller --> pkg_client_connection
|
||||
pkg_api_workspace_controller --> pkg_host_directory_picker
|
||||
pkg_api_workspace_controller --> pkg_invariants
|
||||
pkg_api_workspace_controller --> pkg_session
|
||||
pkg_api_workspace_controller --> pkg_storage_domain
|
||||
pkg_api_workspace_controller --> pkg_typert_protocol
|
||||
pkg_api_workspace_controller --> pkg_workspace
|
||||
pkg_experimental_agent_team --> pkg_agent
|
||||
pkg_experimental_agent_team --> pkg_brand
|
||||
pkg_experimental_agent_team --> pkg_invariants
|
||||
@@ -1305,30 +1278,18 @@ flowchart TD
|
||||
pkg_subagent_spawn_in_process --> pkg_invariants
|
||||
pkg_subagent_spawn_in_process --> pkg_subagent
|
||||
pkg_subagent_spawn_in_process --> pkg_subagent_in_process_driver
|
||||
pkg_api_remotes --> pkg_agent_presets
|
||||
pkg_api_remotes --> pkg_api_gateway
|
||||
pkg_api_remotes --> pkg_api_session_controller
|
||||
pkg_api_remotes --> pkg_api_settings_controller
|
||||
pkg_api_remotes --> pkg_api_workspace_controller
|
||||
pkg_api_remotes --> pkg_commands
|
||||
pkg_api_remotes --> pkg_cordis_host_runner
|
||||
pkg_api_remotes --> pkg_credentials
|
||||
pkg_api_remotes --> pkg_file_reference
|
||||
pkg_api_remotes --> pkg_goal
|
||||
pkg_api_remotes --> pkg_host_plugin_inventory
|
||||
pkg_api_remotes --> pkg_invariants
|
||||
pkg_api_remotes --> pkg_llm
|
||||
pkg_api_remotes --> pkg_message_feedback
|
||||
pkg_api_remotes --> pkg_session
|
||||
pkg_api_remotes --> pkg_session_reference
|
||||
pkg_api_remotes --> pkg_settings
|
||||
pkg_api_remotes --> pkg_subagent
|
||||
pkg_api_remotes --> pkg_user_approval
|
||||
pkg_api_remotes --> pkg_user_questions
|
||||
pkg_client_ui_session --> pkg_api_session_controller
|
||||
pkg_client_ui_session --> pkg_client_ui_renderer
|
||||
pkg_client_ui_session --> pkg_invariants
|
||||
pkg_client_ui_session --> pkg_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_remotes
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_session_controller
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_locale
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_conversation
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_primitives
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_renderer
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_slots
|
||||
pkg_experimental_client_ui_agent_team --> pkg_experimental_agent_team
|
||||
pkg_experimental_client_ui_agent_team --> pkg_invariants
|
||||
pkg_experimental_client_ui_agent_team --> pkg_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_typert_protocol
|
||||
pkg_experimental_tool_agent_team --> pkg_agent
|
||||
pkg_experimental_tool_agent_team --> pkg_experimental_agent_team
|
||||
pkg_experimental_tool_agent_team --> pkg_invariants
|
||||
@@ -1348,358 +1309,6 @@ flowchart TD
|
||||
pkg_sdk_jsonrpc_server --> pkg_sdk_protocol
|
||||
pkg_sdk_jsonrpc_server --> pkg_session
|
||||
pkg_sdk_jsonrpc_server --> pkg_subagent
|
||||
pkg_subagent_dsh_sdk --> pkg_agent
|
||||
pkg_subagent_dsh_sdk --> pkg_invariants
|
||||
pkg_subagent_dsh_sdk --> pkg_llm
|
||||
pkg_subagent_dsh_sdk --> pkg_sdk_client
|
||||
pkg_subagent_dsh_sdk --> pkg_session
|
||||
pkg_subagent_dsh_sdk --> pkg_subagent
|
||||
pkg_subagent_dsh_sdk --> pkg_subprocess
|
||||
pkg_client_ui_settings --> pkg_api_remotes
|
||||
pkg_client_ui_settings --> pkg_invariants
|
||||
pkg_client_ui_settings --> pkg_settings
|
||||
pkg_client_locale --> pkg_api_remotes
|
||||
pkg_client_locale --> pkg_client_connection
|
||||
pkg_client_locale --> pkg_client_ui_renderer
|
||||
pkg_client_locale --> pkg_client_ui_settings
|
||||
pkg_client_locale --> pkg_invariants
|
||||
pkg_client_locale --> pkg_settings
|
||||
pkg_client_ui_settings_models --> pkg_api_remotes
|
||||
pkg_client_ui_settings_models --> pkg_client_locale
|
||||
pkg_client_ui_settings_models --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_models --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_models --> pkg_invariants
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_api_remotes
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_client_locale
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_invariants
|
||||
pkg_client_ui_settings_plugins --> pkg_api_remotes
|
||||
pkg_client_ui_settings_plugins --> pkg_client_locale
|
||||
pkg_client_ui_settings_plugins --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_plugins --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_plugins --> pkg_invariants
|
||||
pkg_client_ui_theme --> pkg_api_remotes
|
||||
pkg_client_ui_theme --> pkg_client_connection
|
||||
pkg_client_ui_theme --> pkg_client_locale
|
||||
pkg_client_ui_theme --> pkg_client_ui_renderer
|
||||
pkg_client_ui_theme --> pkg_client_ui_settings
|
||||
pkg_client_ui_theme --> pkg_host_webserver
|
||||
pkg_client_ui_theme --> pkg_invariants
|
||||
pkg_client_ui_theme --> pkg_settings
|
||||
pkg_client_ui_layout --> pkg_client_locale
|
||||
pkg_client_ui_layout --> pkg_client_ui_renderer
|
||||
pkg_client_ui_layout --> pkg_client_ui_session
|
||||
pkg_client_ui_layout --> pkg_client_ui_theme
|
||||
pkg_client_ui_layout --> pkg_invariants
|
||||
pkg_cordis_client_runner --> pkg_api_remotes
|
||||
pkg_cordis_client_runner --> pkg_client_modules
|
||||
pkg_cordis_client_runner --> pkg_client_ui_renderer
|
||||
pkg_cordis_client_runner --> pkg_client_ui_theme
|
||||
pkg_cordis_client_runner --> pkg_invariants
|
||||
pkg_client_ui_conversation --> pkg_api_remotes
|
||||
pkg_client_ui_conversation --> pkg_api_session_controller
|
||||
pkg_client_ui_conversation --> pkg_api_workspace_controller
|
||||
pkg_client_ui_conversation --> pkg_attachment
|
||||
pkg_client_ui_conversation --> pkg_brand
|
||||
pkg_client_ui_conversation --> pkg_client_locale
|
||||
pkg_client_ui_conversation --> pkg_client_ui_layout
|
||||
pkg_client_ui_conversation --> pkg_client_ui_renderer
|
||||
pkg_client_ui_conversation --> pkg_client_ui_session
|
||||
pkg_client_ui_conversation --> pkg_client_ui_settings
|
||||
pkg_client_ui_conversation --> pkg_client_ui_workspace
|
||||
pkg_client_ui_conversation --> pkg_commands
|
||||
pkg_client_ui_conversation --> pkg_goal
|
||||
pkg_client_ui_conversation --> pkg_invariants
|
||||
pkg_client_ui_conversation --> pkg_llm
|
||||
pkg_client_ui_conversation --> pkg_llm_retry
|
||||
pkg_client_ui_conversation --> pkg_permission_presets
|
||||
pkg_client_ui_conversation --> pkg_plan_mode
|
||||
pkg_client_ui_conversation --> pkg_session
|
||||
pkg_client_ui_conversation --> pkg_settings
|
||||
pkg_client_ui_conversation --> pkg_token_meter
|
||||
pkg_client_ui_conversation --> pkg_tool_todo
|
||||
pkg_client_ui_conversation --> pkg_util_crypto
|
||||
pkg_client_ui_conversation --> pkg_util_workspace_path
|
||||
pkg_client_ui_conversation --> pkg_workspace
|
||||
pkg_client_ui_sidebar --> pkg_api_workspace_controller
|
||||
pkg_client_ui_sidebar --> pkg_client_locale
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_layout
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_renderer
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_session
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_workspace
|
||||
pkg_client_ui_sidebar --> pkg_invariants
|
||||
pkg_client_ui_workspace --> pkg_api_remotes
|
||||
pkg_client_ui_workspace --> pkg_api_session_controller
|
||||
pkg_client_ui_workspace --> pkg_api_workspace_controller
|
||||
pkg_client_ui_workspace --> pkg_client_connection
|
||||
pkg_client_ui_workspace --> pkg_client_locale
|
||||
pkg_client_ui_workspace --> pkg_client_ui_conversation
|
||||
pkg_client_ui_workspace --> pkg_client_ui_renderer
|
||||
pkg_client_ui_workspace --> pkg_client_ui_session
|
||||
pkg_client_ui_workspace --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_workspace --> pkg_invariants
|
||||
pkg_client_ui_workspace --> pkg_schedule
|
||||
pkg_client_ui_workspace --> pkg_session
|
||||
pkg_client_ui_workspace --> pkg_typert_protocol
|
||||
pkg_client_ui_workspace --> pkg_util_workspace_path
|
||||
pkg_client_ui_agent_preset --> pkg_agent_presets
|
||||
pkg_client_ui_agent_preset --> pkg_api_remotes
|
||||
pkg_client_ui_agent_preset --> pkg_api_session_controller
|
||||
pkg_client_ui_agent_preset --> pkg_client_connection
|
||||
pkg_client_ui_agent_preset --> pkg_client_locale
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_conversation
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_renderer
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_session
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_settings
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_workspace
|
||||
pkg_client_ui_agent_preset --> pkg_invariants
|
||||
pkg_client_ui_agent_preset --> pkg_session
|
||||
pkg_client_ui_approval --> pkg_api_remotes
|
||||
pkg_client_ui_approval --> pkg_api_session_controller
|
||||
pkg_client_ui_approval --> pkg_client_locale
|
||||
pkg_client_ui_approval --> pkg_client_ui_conversation
|
||||
pkg_client_ui_approval --> pkg_client_ui_renderer
|
||||
pkg_client_ui_approval --> pkg_client_ui_session
|
||||
pkg_client_ui_approval --> pkg_invariants
|
||||
pkg_client_ui_approval --> pkg_llm
|
||||
pkg_client_ui_approval --> pkg_session
|
||||
pkg_client_ui_approval --> pkg_typert_protocol
|
||||
pkg_client_ui_brand_official --> pkg_client_ui_renderer
|
||||
pkg_client_ui_brand_official --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_brand_official --> pkg_invariants
|
||||
pkg_client_ui_directory_picker_browse --> pkg_api_remotes
|
||||
pkg_client_ui_directory_picker_browse --> pkg_client_locale
|
||||
pkg_client_ui_directory_picker_browse --> pkg_client_ui_renderer
|
||||
pkg_client_ui_directory_picker_browse --> pkg_client_ui_workspace
|
||||
pkg_client_ui_directory_picker_browse --> pkg_invariants
|
||||
pkg_client_ui_directory_picker_native --> pkg_client_ui_renderer
|
||||
pkg_client_ui_directory_picker_native --> pkg_client_ui_workspace
|
||||
pkg_client_ui_directory_picker_native --> pkg_invariants
|
||||
pkg_client_ui_input_trigger --> pkg_api_session_controller
|
||||
pkg_client_ui_input_trigger --> pkg_client_locale
|
||||
pkg_client_ui_input_trigger --> pkg_client_ui_conversation
|
||||
pkg_client_ui_input_trigger --> pkg_client_ui_renderer
|
||||
pkg_client_ui_input_trigger --> pkg_client_ui_session
|
||||
pkg_client_ui_input_trigger --> pkg_file_reference
|
||||
pkg_client_ui_input_trigger --> pkg_invariants
|
||||
pkg_client_ui_input_trigger --> pkg_session
|
||||
pkg_client_ui_jobs --> pkg_api_session_controller
|
||||
pkg_client_ui_jobs --> pkg_client_locale
|
||||
pkg_client_ui_jobs --> pkg_client_ui_conversation
|
||||
pkg_client_ui_jobs --> pkg_client_ui_renderer
|
||||
pkg_client_ui_jobs --> pkg_client_ui_session
|
||||
pkg_client_ui_jobs --> pkg_invariants
|
||||
pkg_client_ui_plan --> pkg_api_remotes
|
||||
pkg_client_ui_plan --> pkg_client_locale
|
||||
pkg_client_ui_plan --> pkg_client_ui_conversation
|
||||
pkg_client_ui_plan --> pkg_client_ui_renderer
|
||||
pkg_client_ui_plan --> pkg_client_ui_session
|
||||
pkg_client_ui_plan --> pkg_invariants
|
||||
pkg_client_ui_plan --> pkg_plan_mode
|
||||
pkg_client_ui_plan --> pkg_session
|
||||
pkg_client_ui_schedule --> pkg_api_session_controller
|
||||
pkg_client_ui_schedule --> pkg_client_locale
|
||||
pkg_client_ui_schedule --> pkg_client_ui_conversation
|
||||
pkg_client_ui_schedule --> pkg_client_ui_renderer
|
||||
pkg_client_ui_schedule --> pkg_client_ui_session
|
||||
pkg_client_ui_schedule --> pkg_invariants
|
||||
pkg_client_ui_schedule --> pkg_schedule
|
||||
pkg_client_ui_settings_general --> pkg_api_remotes
|
||||
pkg_client_ui_settings_general --> pkg_client_connection
|
||||
pkg_client_ui_settings_general --> pkg_client_locale
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_session
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_settings_general --> pkg_invariants
|
||||
pkg_client_ui_settings_general --> pkg_settings
|
||||
pkg_client_ui_trajectory --> pkg_agent
|
||||
pkg_client_ui_trajectory --> pkg_api_session_controller
|
||||
pkg_client_ui_trajectory --> pkg_attachment
|
||||
pkg_client_ui_trajectory --> pkg_client_locale
|
||||
pkg_client_ui_trajectory --> pkg_client_ui_conversation
|
||||
pkg_client_ui_trajectory --> pkg_client_ui_renderer
|
||||
pkg_client_ui_trajectory --> pkg_client_ui_session
|
||||
pkg_client_ui_trajectory --> pkg_compaction
|
||||
pkg_client_ui_trajectory --> pkg_invariants
|
||||
pkg_client_ui_trajectory --> pkg_llm
|
||||
pkg_client_ui_trajectory --> pkg_session
|
||||
pkg_client_ui_trajectory --> pkg_tools
|
||||
pkg_client_ui_user_questions --> pkg_api_remotes
|
||||
pkg_client_ui_user_questions --> pkg_api_session_controller
|
||||
pkg_client_ui_user_questions --> pkg_client_locale
|
||||
pkg_client_ui_user_questions --> pkg_client_ui_conversation
|
||||
pkg_client_ui_user_questions --> pkg_client_ui_renderer
|
||||
pkg_client_ui_user_questions --> pkg_client_ui_session
|
||||
pkg_client_ui_user_questions --> pkg_invariants
|
||||
pkg_client_ui_user_questions --> pkg_session
|
||||
pkg_client_ui_user_questions --> pkg_typert_protocol
|
||||
pkg_client_ui_user_questions --> pkg_user_questions
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_remotes
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_session_controller
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_locale
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_conversation
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_primitives
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_renderer
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_slots
|
||||
pkg_experimental_client_ui_agent_team --> pkg_experimental_agent_team
|
||||
pkg_experimental_client_ui_agent_team --> pkg_invariants
|
||||
pkg_experimental_client_ui_agent_team --> pkg_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_typert_protocol
|
||||
pkg_client_ui_chat --> pkg_agent
|
||||
pkg_client_ui_chat --> pkg_api_remotes
|
||||
pkg_client_ui_chat --> pkg_api_session_controller
|
||||
pkg_client_ui_chat --> pkg_api_workspace_controller
|
||||
pkg_client_ui_chat --> pkg_attachment
|
||||
pkg_client_ui_chat --> pkg_client_locale
|
||||
pkg_client_ui_chat --> pkg_client_ui_approval
|
||||
pkg_client_ui_chat --> pkg_client_ui_conversation
|
||||
pkg_client_ui_chat --> pkg_client_ui_layout
|
||||
pkg_client_ui_chat --> pkg_client_ui_renderer
|
||||
pkg_client_ui_chat --> pkg_client_ui_session
|
||||
pkg_client_ui_chat --> pkg_client_ui_settings
|
||||
pkg_client_ui_chat --> pkg_client_ui_workspace
|
||||
pkg_client_ui_chat --> pkg_commands
|
||||
pkg_client_ui_chat --> pkg_compaction
|
||||
pkg_client_ui_chat --> pkg_invariants
|
||||
pkg_client_ui_chat --> pkg_llm
|
||||
pkg_client_ui_chat --> pkg_llm_retry
|
||||
pkg_client_ui_chat --> pkg_session
|
||||
pkg_client_ui_chat --> pkg_session_stats
|
||||
pkg_client_ui_chat --> pkg_settings
|
||||
pkg_client_ui_chat --> pkg_token_meter
|
||||
pkg_client_ui_chat --> pkg_tools
|
||||
pkg_client_ui_chat --> pkg_util_workspace_path
|
||||
pkg_client_ui_commands --> pkg_api_remotes
|
||||
pkg_client_ui_commands --> pkg_api_session_controller
|
||||
pkg_client_ui_commands --> pkg_client_locale
|
||||
pkg_client_ui_commands --> pkg_client_ui_conversation
|
||||
pkg_client_ui_commands --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_commands --> pkg_client_ui_renderer
|
||||
pkg_client_ui_commands --> pkg_client_ui_session
|
||||
pkg_client_ui_commands --> pkg_commands
|
||||
pkg_client_ui_commands --> pkg_invariants
|
||||
pkg_client_ui_commands --> pkg_session
|
||||
pkg_client_ui_reference --> pkg_api_remotes
|
||||
pkg_client_ui_reference --> pkg_api_session_controller
|
||||
pkg_client_ui_reference --> pkg_client_connection
|
||||
pkg_client_ui_reference --> pkg_client_locale
|
||||
pkg_client_ui_reference --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_reference --> pkg_file_reference
|
||||
pkg_client_ui_reference --> pkg_invariants
|
||||
pkg_client_ui_reference --> pkg_session_reference
|
||||
pkg_client_ui_reference --> pkg_typert_protocol
|
||||
pkg_client_ui_reference --> pkg_util_workspace_path
|
||||
pkg_client_ui_subagent --> pkg_api_session_controller
|
||||
pkg_client_ui_subagent --> pkg_client_connection
|
||||
pkg_client_ui_subagent --> pkg_client_locale
|
||||
pkg_client_ui_subagent --> pkg_client_ui_conversation
|
||||
pkg_client_ui_subagent --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_subagent --> pkg_client_ui_renderer
|
||||
pkg_client_ui_subagent --> pkg_client_ui_session
|
||||
pkg_client_ui_subagent --> pkg_invariants
|
||||
pkg_client_ui_subagent --> pkg_session
|
||||
pkg_client_ui_subagent --> pkg_subagent
|
||||
pkg_client_ui_subagent --> pkg_token_meter
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_webserver
|
||||
pkg_host_directory_picker_auto --> pkg_invariants
|
||||
pkg_session_log_export --> pkg_attachment
|
||||
pkg_session_log_export --> pkg_client_connection
|
||||
pkg_session_log_export --> pkg_client_locale
|
||||
pkg_session_log_export --> pkg_client_ui_commands
|
||||
pkg_session_log_export --> pkg_client_ui_conversation
|
||||
pkg_session_log_export --> pkg_client_ui_renderer
|
||||
pkg_session_log_export --> pkg_client_ui_session
|
||||
pkg_session_log_export --> pkg_commands
|
||||
pkg_session_log_export --> pkg_invariants
|
||||
pkg_session_log_export --> pkg_session
|
||||
pkg_session_log_export --> pkg_session_persistence
|
||||
pkg_session_log_export --> pkg_session_query
|
||||
pkg_client_ui_attachment --> pkg_attachment
|
||||
pkg_client_ui_attachment --> pkg_client_ui_chat
|
||||
pkg_client_ui_attachment --> pkg_client_ui_conversation
|
||||
pkg_client_ui_attachment --> pkg_client_ui_renderer
|
||||
pkg_client_ui_attachment --> pkg_client_ui_trajectory
|
||||
pkg_client_ui_attachment --> pkg_invariants
|
||||
pkg_client_ui_deliverables --> pkg_api_remotes
|
||||
pkg_client_ui_deliverables --> pkg_client_connection
|
||||
pkg_client_ui_deliverables --> pkg_client_locale
|
||||
pkg_client_ui_deliverables --> pkg_client_ui_chat
|
||||
pkg_client_ui_deliverables --> pkg_client_ui_conversation
|
||||
pkg_client_ui_deliverables --> pkg_client_ui_renderer
|
||||
pkg_client_ui_deliverables --> pkg_invariants
|
||||
pkg_client_ui_deliverables --> pkg_session
|
||||
pkg_client_ui_deliverables --> pkg_system_prompt
|
||||
pkg_client_ui_goal --> pkg_api_remotes
|
||||
pkg_client_ui_goal --> pkg_api_session_controller
|
||||
pkg_client_ui_goal --> pkg_client_locale
|
||||
pkg_client_ui_goal --> pkg_client_ui_chat
|
||||
pkg_client_ui_goal --> pkg_client_ui_conversation
|
||||
pkg_client_ui_goal --> pkg_client_ui_renderer
|
||||
pkg_client_ui_goal --> pkg_client_ui_session
|
||||
pkg_client_ui_goal --> pkg_commands
|
||||
pkg_client_ui_goal --> pkg_goal
|
||||
pkg_client_ui_goal --> pkg_invariants
|
||||
pkg_client_ui_goal --> pkg_session
|
||||
pkg_client_ui_goal --> pkg_typert_protocol
|
||||
pkg_client_ui_message_feedback --> pkg_api_remotes
|
||||
pkg_client_ui_message_feedback --> pkg_client_connection
|
||||
pkg_client_ui_message_feedback --> pkg_client_locale
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_chat
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_conversation
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_renderer
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_session
|
||||
pkg_client_ui_message_feedback --> pkg_invariants
|
||||
pkg_client_ui_message_feedback --> pkg_message_feedback
|
||||
pkg_client_ui_message_feedback --> pkg_session
|
||||
pkg_client_ui_message_feedback --> pkg_typert_protocol
|
||||
pkg_client_ui_model_selection --> pkg_api_remotes
|
||||
pkg_client_ui_model_selection --> pkg_api_session_controller
|
||||
pkg_client_ui_model_selection --> pkg_client_locale
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_commands
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_conversation
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_renderer
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_session
|
||||
pkg_client_ui_model_selection --> pkg_invariants
|
||||
pkg_client_ui_model_selection --> pkg_session
|
||||
pkg_client_ui_model_selection --> pkg_typert_protocol
|
||||
pkg_client_ui_permission_presets --> pkg_api_remotes
|
||||
pkg_client_ui_permission_presets --> pkg_api_session_controller
|
||||
pkg_client_ui_permission_presets --> pkg_client_locale
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_commands
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_renderer
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_session
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_settings
|
||||
pkg_client_ui_permission_presets --> pkg_invariants
|
||||
pkg_client_ui_permission_presets --> pkg_permission_presets
|
||||
pkg_client_ui_tool --> pkg_api_remotes
|
||||
pkg_client_ui_tool --> pkg_api_workspace_controller
|
||||
pkg_client_ui_tool --> pkg_client_connection
|
||||
pkg_client_ui_tool --> pkg_client_locale
|
||||
pkg_client_ui_tool --> pkg_client_ui_chat
|
||||
pkg_client_ui_tool --> pkg_client_ui_conversation
|
||||
pkg_client_ui_tool --> pkg_client_ui_renderer
|
||||
pkg_client_ui_tool --> pkg_client_ui_session
|
||||
pkg_client_ui_tool --> pkg_invariants
|
||||
pkg_client_ui_tool --> pkg_util_workspace_path
|
||||
pkg_client_ui_workflow_run --> pkg_api_session_controller
|
||||
pkg_client_ui_workflow_run --> pkg_client_locale
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_chat
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_conversation
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_renderer
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_session
|
||||
pkg_client_ui_workflow_run --> pkg_invariants
|
||||
pkg_client_ui_workflow_run --> pkg_session
|
||||
pkg_client_ui_workflow_run --> pkg_tool_workflow
|
||||
pkg_client_ui_workflow_run --> pkg_workflow
|
||||
pkg_client_test_runtime --> pkg_api_session_controller
|
||||
pkg_client_test_runtime --> pkg_api_workspace_controller
|
||||
pkg_client_test_runtime --> pkg_attachment
|
||||
@@ -1715,30 +1324,66 @@ flowchart TD
|
||||
pkg_client_test_runtime --> pkg_session
|
||||
pkg_client_test_runtime --> pkg_subagent
|
||||
pkg_client_test_runtime --> pkg_typert_protocol
|
||||
pkg_client_ui_skill --> pkg_api_remotes
|
||||
pkg_client_ui_skill --> pkg_api_session_controller
|
||||
pkg_client_ui_skill --> pkg_client_connection
|
||||
pkg_client_ui_skill --> pkg_client_locale
|
||||
pkg_client_ui_skill --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_skill --> pkg_client_ui_renderer
|
||||
pkg_client_ui_skill --> pkg_client_ui_tool
|
||||
pkg_client_ui_skill --> pkg_invariants
|
||||
pkg_client_ui_skill --> pkg_session
|
||||
pkg_client_ui_cordis --> pkg_api_remotes
|
||||
pkg_client_ui_cordis --> pkg_client_connection
|
||||
pkg_client_ui_cordis --> pkg_client_locale
|
||||
pkg_client_ui_cordis --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_cordis --> pkg_client_ui_renderer
|
||||
pkg_client_ui_cordis --> pkg_client_ui_session
|
||||
pkg_client_ui_cordis --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_cordis --> pkg_client_ui_tool
|
||||
pkg_client_ui_cordis --> pkg_cordis_client_runner
|
||||
pkg_client_ui_cordis --> pkg_invariants
|
||||
pkg_subagent_dsh_sdk --> pkg_agent
|
||||
pkg_subagent_dsh_sdk --> pkg_invariants
|
||||
pkg_subagent_dsh_sdk --> pkg_llm
|
||||
pkg_subagent_dsh_sdk --> pkg_sdk_client
|
||||
pkg_subagent_dsh_sdk --> pkg_session
|
||||
pkg_subagent_dsh_sdk --> pkg_subagent
|
||||
pkg_subagent_dsh_sdk --> pkg_subprocess
|
||||
```
|
||||
|
||||
| Package | Group | Depends on |
|
||||
| Package | Group | Peer dependencies |
|
||||
| --- | --- | --- |
|
||||
| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | — |
|
||||
| [`client-connection`](../packages/client/connection) | `client` | — |
|
||||
| [`client-hmr`](../packages/client/hmr) | `client` | — |
|
||||
| [`client-locale`](../packages/client/locale) | `client` | — |
|
||||
| [`client-modules`](../packages/client/modules) | `client` | — |
|
||||
| [`client-store`](../packages/client/store) | `client` | — |
|
||||
| [`client-ui-agent-preset`](../packages/client/ui-agent-preset) | `client` | — |
|
||||
| [`client-ui-approval`](../packages/client/ui-approval) | `client` | — |
|
||||
| [`client-ui-attachment`](../packages/client/ui-attachment) | `client` | — |
|
||||
| [`client-ui-brand-official`](../packages/client/ui-brand-official) | `client` | — |
|
||||
| [`client-ui-chat`](../packages/client/ui-chat) | `client` | — |
|
||||
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | — |
|
||||
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | — |
|
||||
| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | — |
|
||||
| [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | — |
|
||||
| [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | — |
|
||||
| [`client-ui-goal`](../packages/client/ui-goal) | `client` | — |
|
||||
| [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | — |
|
||||
| [`client-ui-jobs`](../packages/client/ui-jobs) | `client` | — |
|
||||
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | — |
|
||||
| [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | — |
|
||||
| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | — |
|
||||
| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | — |
|
||||
| [`client-ui-plan`](../packages/client/ui-plan) | `client` | — |
|
||||
| [`client-ui-primitives`](../packages/client/ui-primitives) | `client` | — |
|
||||
| [`client-ui-reference`](../packages/client/ui-reference) | `client` | — |
|
||||
| [`client-ui-renderer`](../packages/client/ui-renderer) | `client` | — |
|
||||
| [`client-ui-schedule`](../packages/client/ui-schedule) | `client` | — |
|
||||
| [`client-ui-session`](../packages/client/ui-session) | `client` | — |
|
||||
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | — |
|
||||
| [`client-ui-settings-general`](../packages/client/ui-settings-general) | `client` | — |
|
||||
| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | — |
|
||||
| [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | — |
|
||||
| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | — |
|
||||
| [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | — |
|
||||
| [`client-ui-skill`](../packages/client/ui-skill) | `client` | — |
|
||||
| [`client-ui-slots`](../packages/client/ui-slots) | `client` | — |
|
||||
| [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | — |
|
||||
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | — |
|
||||
| [`client-ui-tool`](../packages/client/ui-tool) | `client` | — |
|
||||
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | — |
|
||||
| [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | — |
|
||||
| [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | — |
|
||||
| [`client-ui-workspace`](../packages/client/ui-workspace) | `client` | — |
|
||||
| [`client-web`](../packages/client/web) | `client` | — |
|
||||
| [`client-ui-cordis`](../packages/extensions/ui-cordis) | `extensions` | — |
|
||||
| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | — |
|
||||
| [`invariants`](../packages/runtime-diagnostics/invariants) | `runtime-diagnostics` | — |
|
||||
| [`typert-registry`](../packages/typert/registry) | `typert` | — |
|
||||
| [`atomic-write`](../packages/util/atomic-write) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`brand`](../packages/util/brand) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`home-paths`](../packages/util/home-paths) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
@@ -1756,11 +1401,6 @@ flowchart TD
|
||||
| [`base`](../packages/bundle/base) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`sdk-minimal`](../packages/bundle/sdk-minimal) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-store`](../packages/client/store) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-primitives`](../packages/client/ui-primitives) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-renderer`](../packages/client/ui-renderer) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-slots`](../packages/client/ui-slots) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-web`](../packages/client/web) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`code-runtime`](../packages/code-runtime/code-runtime) | `code-runtime` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`code-runtime-python`](../packages/code-runtime/code-runtime-python) | `code-runtime` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`e2b`](../packages/e2b/e2b) | `e2b` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
@@ -1777,38 +1417,34 @@ flowchart TD
|
||||
| [`win32-process`](../packages/subprocess/win32-process) | `subprocess` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`llm-mock-server`](../packages/test-support/llm-mock-server) | `test-support` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`typert-generator`](../packages/typert/generator) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`typert-loader`](../packages/typert/loader) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
|
||||
| [`typert-protocol`](../packages/typert/protocol) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`typert-registry`](../packages/typert/registry) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`llm`](../packages/llm/llm) | `llm` | [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`session`](../packages/core/session) | `core` | [`scope`](../packages/core/scope) |
|
||||
| [`api-gateway`](../packages/api/gateway) | `api` | [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`api-remotes`](../packages/api/remotes) | `api` | [`scope`](../packages/core/scope) |
|
||||
| [`attachment`](../packages/attachment/attachment) | `attachment` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-modules`](../packages/client/modules) | `client` | [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`credentials`](../packages/credentials/credentials) | `credentials` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`subprocess-e2b`](../packages/e2b/subprocess-e2b) | `e2b` | [`e2b`](../packages/e2b/e2b), [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-plugin-inventory`](../packages/host/plugin-inventory) | `host` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`anonymous-user-id`](../packages/identity/anonymous-user-id) | `identity` | [`brand`](../packages/util/brand), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`storage-domain`](../packages/storage/storage-domain) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
|
||||
| [`storage-json`](../packages/storage/storage-json) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
|
||||
| [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
|
||||
| [`subprocess-local`](../packages/subprocess/subprocess-local) | `subprocess` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
| [`typert-loader`](../packages/typert/loader) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
|
||||
| [`llm`](../packages/llm/llm) | `llm` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-hmr`](../packages/client/hmr) | `client` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) |
|
||||
| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`session`](../packages/core/session) | `core` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`system-prompt`](../packages/core/system-prompt) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
|
||||
| [`skill`](../packages/skill/skill) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
|
||||
| [`web`](../packages/web/web) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`authorization`](../packages/credentials/authorization) | `credentials` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`lsp`](../packages/lsp/lsp) | `lsp` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`skill-badge`](../packages/skill/skill-badge) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`skill`](../packages/skill/skill) |
|
||||
| [`web-fetch-http`](../packages/web/web-fetch-http) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`web`](../packages/web/web) |
|
||||
| [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`spill`](../packages/spill/spill) | `spill` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
|
||||
| [`app-boot`](../packages/boot/app-boot) | `boot` | [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`code-runtime-worker-thread`](../packages/code-runtime/code-runtime-worker-thread) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) |
|
||||
| [`persona`](../packages/preset/persona) | `preset` | [`invariants`](../packages/runtime-diagnostics/invariants), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`authorization`](../packages/credentials/authorization) | `credentials` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) |
|
||||
| [`lsp`](../packages/lsp/lsp) | `lsp` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`sandbox`](../packages/sandbox/sandbox) | `sandbox` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
|
||||
| [`session-log-deepseek`](../packages/session/session-log-deepseek) | `session` | [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`session-persistence`](../packages/session/session-persistence) | `session` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) |
|
||||
@@ -1817,8 +1453,14 @@ flowchart TD
|
||||
| [`session-snapshot`](../packages/test-support/session-snapshot) | `test-support` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`agent`](../packages/core/agent) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`system-prompt`](../packages/core/system-prompt), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) |
|
||||
| [`skill-badge`](../packages/skill/skill-badge) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`skill`](../packages/skill/skill) |
|
||||
| [`web-fetch-http`](../packages/web/web-fetch-http) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`web`](../packages/web/web) |
|
||||
| [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`spill-local`](../packages/spill/spill-local) | `spill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`spill`](../packages/spill/spill) |
|
||||
| [`app-boot`](../packages/boot/app-boot) | `boot` | [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`message-feedback`](../packages/feedback/message-feedback) | `feedback` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`persona`](../packages/preset/persona) | `preset` | [`invariants`](../packages/runtime-diagnostics/invariants), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`sandbox-local`](../packages/sandbox/sandbox-local) | `sandbox` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`session`](../packages/core/session) |
|
||||
| [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence) |
|
||||
| [`session-persistence-sqlite`](../packages/session/session-persistence-sqlite) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence) |
|
||||
@@ -1837,6 +1479,7 @@ flowchart TD
|
||||
| [`skill-filesystem`](../packages/skill/skill-filesystem) | `skill` | [`fs`](../packages/fs/fs), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`skill`](../packages/skill/skill) |
|
||||
| [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`web`](../packages/web/web) |
|
||||
| [`hook-protocol`](../packages/hooks/hook-protocol) | `hooks` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`shell`](../packages/shell/shell) |
|
||||
| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) |
|
||||
| [`tmux-context`](../packages/context/tmux-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`shell`](../packages/shell/shell) |
|
||||
@@ -1908,7 +1551,6 @@ flowchart TD
|
||||
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
|
||||
| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`native-command`](../packages/util/native-command), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) |
|
||||
| [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | `compaction` | [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
|
||||
| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`agent`](../packages/core/agent), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
|
||||
| [`tool-bash`](../packages/shell/tool-bash) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
|
||||
@@ -1917,12 +1559,9 @@ flowchart TD
|
||||
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time) |
|
||||
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
|
||||
| [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
|
||||
| [`api-gateway`](../packages/api/gateway) | `api` | [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
|
||||
| [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
|
||||
| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
|
||||
| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`webhook-github`](../packages/webhook/webhook-github) | `webhook` | [`credentials`](../packages/credentials/credentials), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`webhook`](../packages/webhook/webhook) |
|
||||
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
| [`subagent-claude-code`](../packages/subagent/subagent-claude-code) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
@@ -1933,57 +1572,15 @@ flowchart TD
|
||||
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
|
||||
| [`hooks-claude-code`](../packages/hooks/hooks-claude-code) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
|
||||
| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`native-command`](../packages/util/native-command), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`skill`](../packages/skill/skill), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-time`](../packages/util/time), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`experimental-agent-team`](../packages/experimental/agent-team) | `experimental` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
|
||||
| [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
|
||||
| [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
|
||||
| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) |
|
||||
| [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team) | `experimental` | [`agent`](../packages/core/agent), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
|
||||
| [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
|
||||
| [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
|
||||
| [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
|
||||
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-modules`](../packages/client/modules), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-locale`](../packages/client/locale), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`token-meter`](../packages/llm/token-meter), [`tool-todo`](../packages/todo/tool-todo), [`util-crypto`](../packages/util/crypto), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | [`api-workspace-controller`](../packages/api/workspace-controller), [`client-locale`](../packages/client/locale), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-workspace`](../packages/client/ui-workspace) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`invariants`](../packages/runtime-diagnostics/invariants), [`schedule`](../packages/schedule/schedule), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-agent-preset`](../packages/client/ui-agent-preset) | `client` | [`agent-presets`](../packages/preset/agent-presets), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-approval`](../packages/client/ui-approval) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-brand-official`](../packages/client/ui-brand-official) | `client` | [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-jobs`](../packages/client/ui-jobs) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-plan`](../packages/client/ui-plan) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`plan-mode`](../packages/plan/plan-mode), [`session`](../packages/core/session) |
|
||||
| [`client-ui-schedule`](../packages/client/ui-schedule) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`schedule`](../packages/schedule/schedule) |
|
||||
| [`client-ui-settings-general`](../packages/client/ui-settings-general) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`agent`](../packages/core/agent), [`api-session-controller`](../packages/api/session-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
|
||||
| [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol), [`user-questions`](../packages/interaction/user-questions) |
|
||||
| [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`settings`](../packages/settings/settings), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter) |
|
||||
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
|
||||
| [`client-ui-attachment`](../packages/client/ui-attachment) | `client` | [`attachment`](../packages/attachment/attachment), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-trajectory`](../packages/client/ui-trajectory), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`client-ui-goal`](../packages/client/ui-goal) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) |
|
||||
| [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-store`](../packages/client/store), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-skill`](../packages/client/ui-skill) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-tool`](../packages/client/ui-tool), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-cordis`](../packages/extensions/ui-cordis) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`client-ui-tool`](../packages/client/ui-tool), [`cordis-client-runner`](../packages/extensions/cordis-client-runner), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
|
||||
|
||||
+155
-558
@@ -1,11 +1,11 @@
|
||||
<!-- 英文源文件由 scripts/gen-module-graph.ts 生成;本中文文件是通过双语配对维护的经评审对侧。
|
||||
更新时先运行 `pnpm run gen-module-graph` 更新英文,再更新本文件并运行 `pnpm run verify-translation-pairing --write docs/module-graph.md` 重新记录配对。 -->
|
||||
<!-- 由 scripts/gen-module-graph.ts 生成——请勿手工编辑。
|
||||
运行 `pnpm run gen-module-graph` 重新生成。 -->
|
||||
|
||||
# 模块依赖关系图
|
||||
# 共享实例依赖关系图
|
||||
|
||||
[English](module-graph.md) | 中文
|
||||
|
||||
`@deepseek-ai/dsh-*` harness 包之间的依赖关系。该关系图根据各包的 `peerDependencies`(规范的运行时依赖信号)生成,并按 `packages/<group>/<pkg>` 层级分组。边 `a --> b` 表示包 `a` 依赖包 `b`。名称中的 `@deepseek-ai/dsh-` 前缀已移除。
|
||||
`@deepseek-ai/dsh-*` harness 包之间的 peer 依赖关系。peer 表示消费端需要提供共享实例,不包括普通运行时 dependency 或仅开发期关系。该图按 `packages/<group>/<pkg>` 层级分组;边 `a --> b` 表示包 `a` peer 依赖包 `b`。名称中的 `@deepseek-ai/dsh-` 前缀已移除。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@@ -377,11 +377,6 @@ flowchart TD
|
||||
pkg_base --> pkg_invariants
|
||||
pkg_sdk_app --> pkg_invariants
|
||||
pkg_sdk_minimal --> pkg_invariants
|
||||
pkg_client_store --> pkg_invariants
|
||||
pkg_client_ui_primitives --> pkg_invariants
|
||||
pkg_client_ui_renderer --> pkg_invariants
|
||||
pkg_client_ui_slots --> pkg_invariants
|
||||
pkg_client_web --> pkg_invariants
|
||||
pkg_code_runtime --> pkg_invariants
|
||||
pkg_code_runtime_python --> pkg_invariants
|
||||
pkg_e2b --> pkg_invariants
|
||||
@@ -398,18 +393,37 @@ flowchart TD
|
||||
pkg_win32_process --> pkg_invariants
|
||||
pkg_llm_mock_server --> pkg_invariants
|
||||
pkg_typert_generator --> pkg_invariants
|
||||
pkg_typert_loader --> pkg_invariants
|
||||
pkg_typert_loader --> pkg_typert_registry
|
||||
pkg_typert_protocol --> pkg_invariants
|
||||
pkg_typert_registry --> pkg_invariants
|
||||
pkg_llm --> pkg_typert_protocol
|
||||
pkg_session --> pkg_scope
|
||||
pkg_api_gateway --> pkg_typert_protocol
|
||||
pkg_api_remotes --> pkg_scope
|
||||
pkg_attachment --> pkg_brand
|
||||
pkg_attachment --> pkg_invariants
|
||||
pkg_client_modules --> pkg_host_webserver
|
||||
pkg_client_modules --> pkg_invariants
|
||||
pkg_credentials --> pkg_brand
|
||||
pkg_credentials --> pkg_invariants
|
||||
pkg_subprocess_e2b --> pkg_e2b
|
||||
pkg_subprocess_e2b --> pkg_invariants
|
||||
pkg_subprocess_e2b --> pkg_subprocess
|
||||
pkg_subprocess_e2b --> pkg_timeout
|
||||
pkg_experimental_inspector --> pkg_client_modules
|
||||
pkg_experimental_inspector --> pkg_host_webserver
|
||||
pkg_experimental_inspector --> pkg_invariants
|
||||
pkg_experimental_webworker_runtime --> pkg_client_connection
|
||||
pkg_experimental_webworker_runtime --> pkg_client_modules
|
||||
pkg_experimental_webworker_runtime --> pkg_host_webserver
|
||||
pkg_experimental_webworker_runtime --> pkg_invariants
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_webserver
|
||||
pkg_host_directory_picker_auto --> pkg_invariants
|
||||
pkg_host_frontend_static --> pkg_client_connection
|
||||
pkg_host_frontend_static --> pkg_host_webserver
|
||||
pkg_host_frontend_static --> pkg_invariants
|
||||
pkg_host_plugin_inventory --> pkg_brand
|
||||
pkg_host_plugin_inventory --> pkg_invariants
|
||||
pkg_host_plugin_inventory --> pkg_typert_protocol
|
||||
@@ -425,32 +439,6 @@ flowchart TD
|
||||
pkg_subprocess_local --> pkg_invariants
|
||||
pkg_subprocess_local --> pkg_subprocess
|
||||
pkg_subprocess_local --> pkg_timeout
|
||||
pkg_typert_loader --> pkg_invariants
|
||||
pkg_typert_loader --> pkg_typert_registry
|
||||
pkg_llm --> pkg_attachment
|
||||
pkg_llm --> pkg_brand
|
||||
pkg_llm --> pkg_invariants
|
||||
pkg_llm --> pkg_timeout
|
||||
pkg_llm --> pkg_typert_protocol
|
||||
pkg_attachment_local --> pkg_attachment
|
||||
pkg_attachment_local --> pkg_home_paths
|
||||
pkg_attachment_local --> pkg_invariants
|
||||
pkg_client_hmr --> pkg_client_modules
|
||||
pkg_client_hmr --> pkg_host_webserver
|
||||
pkg_client_hmr --> pkg_invariants
|
||||
pkg_credentials_local --> pkg_atomic_write
|
||||
pkg_credentials_local --> pkg_credentials
|
||||
pkg_credentials_local --> pkg_home_paths
|
||||
pkg_credentials_local --> pkg_invariants
|
||||
pkg_credentials_local --> pkg_launch_environment
|
||||
pkg_experimental_inspector --> pkg_client_modules
|
||||
pkg_experimental_inspector --> pkg_host_webserver
|
||||
pkg_experimental_inspector --> pkg_invariants
|
||||
pkg_session --> pkg_brand
|
||||
pkg_session --> pkg_invariants
|
||||
pkg_session --> pkg_llm
|
||||
pkg_session --> pkg_scope
|
||||
pkg_session --> pkg_typert_protocol
|
||||
pkg_system_prompt --> pkg_invariants
|
||||
pkg_system_prompt --> pkg_llm
|
||||
pkg_system_prompt --> pkg_scope
|
||||
@@ -459,37 +447,28 @@ flowchart TD
|
||||
pkg_skill --> pkg_scope
|
||||
pkg_web --> pkg_invariants
|
||||
pkg_web --> pkg_llm
|
||||
pkg_authorization --> pkg_credentials
|
||||
pkg_authorization --> pkg_invariants
|
||||
pkg_authorization --> pkg_llm
|
||||
pkg_lsp --> pkg_brand
|
||||
pkg_lsp --> pkg_invariants
|
||||
pkg_lsp --> pkg_llm
|
||||
pkg_skill_badge --> pkg_invariants
|
||||
pkg_skill_badge --> pkg_skill
|
||||
pkg_web_fetch_http --> pkg_invariants
|
||||
pkg_web_fetch_http --> pkg_timeout
|
||||
pkg_web_fetch_http --> pkg_web
|
||||
pkg_web_search_exa --> pkg_invariants
|
||||
pkg_web_search_exa --> pkg_launch_environment
|
||||
pkg_web_search_exa --> pkg_web
|
||||
pkg_web_search_perplexity --> pkg_invariants
|
||||
pkg_web_search_perplexity --> pkg_launch_environment
|
||||
pkg_web_search_perplexity --> pkg_web
|
||||
pkg_spill --> pkg_brand
|
||||
pkg_spill --> pkg_invariants
|
||||
pkg_spill --> pkg_llm
|
||||
pkg_spill --> pkg_session
|
||||
pkg_app_boot --> pkg_home_paths
|
||||
pkg_app_boot --> pkg_invariants
|
||||
pkg_app_boot --> pkg_launch_environment
|
||||
pkg_app_boot --> pkg_system_prompt
|
||||
pkg_attachment_local --> pkg_attachment
|
||||
pkg_attachment_local --> pkg_home_paths
|
||||
pkg_attachment_local --> pkg_invariants
|
||||
pkg_code_runtime_worker_thread --> pkg_code_runtime
|
||||
pkg_code_runtime_worker_thread --> pkg_invariants
|
||||
pkg_code_runtime_worker_thread --> pkg_session
|
||||
pkg_code_runtime_worker_thread --> pkg_timeout
|
||||
pkg_persona --> pkg_invariants
|
||||
pkg_persona --> pkg_system_prompt
|
||||
pkg_authorization --> pkg_credentials
|
||||
pkg_authorization --> pkg_invariants
|
||||
pkg_authorization --> pkg_llm
|
||||
pkg_credentials_local --> pkg_atomic_write
|
||||
pkg_credentials_local --> pkg_credentials
|
||||
pkg_credentials_local --> pkg_home_paths
|
||||
pkg_credentials_local --> pkg_invariants
|
||||
pkg_credentials_local --> pkg_launch_environment
|
||||
pkg_lsp --> pkg_brand
|
||||
pkg_lsp --> pkg_invariants
|
||||
pkg_lsp --> pkg_llm
|
||||
pkg_sandbox --> pkg_invariants
|
||||
pkg_sandbox --> pkg_llm
|
||||
pkg_sandbox --> pkg_session
|
||||
@@ -518,8 +497,23 @@ flowchart TD
|
||||
pkg_fs --> pkg_invariants
|
||||
pkg_fs --> pkg_llm
|
||||
pkg_fs --> pkg_sandbox
|
||||
pkg_skill_badge --> pkg_invariants
|
||||
pkg_skill_badge --> pkg_skill
|
||||
pkg_web_fetch_http --> pkg_invariants
|
||||
pkg_web_fetch_http --> pkg_timeout
|
||||
pkg_web_fetch_http --> pkg_web
|
||||
pkg_web_search_exa --> pkg_invariants
|
||||
pkg_web_search_exa --> pkg_launch_environment
|
||||
pkg_web_search_exa --> pkg_web
|
||||
pkg_web_search_perplexity --> pkg_invariants
|
||||
pkg_web_search_perplexity --> pkg_launch_environment
|
||||
pkg_web_search_perplexity --> pkg_web
|
||||
pkg_spill_local --> pkg_invariants
|
||||
pkg_spill_local --> pkg_spill
|
||||
pkg_app_boot --> pkg_home_paths
|
||||
pkg_app_boot --> pkg_invariants
|
||||
pkg_app_boot --> pkg_launch_environment
|
||||
pkg_app_boot --> pkg_system_prompt
|
||||
pkg_message_feedback --> pkg_brand
|
||||
pkg_message_feedback --> pkg_invariants
|
||||
pkg_message_feedback --> pkg_llm
|
||||
@@ -527,6 +521,8 @@ flowchart TD
|
||||
pkg_message_feedback --> pkg_session_persistence
|
||||
pkg_message_feedback --> pkg_storage_domain
|
||||
pkg_message_feedback --> pkg_typert_protocol
|
||||
pkg_persona --> pkg_invariants
|
||||
pkg_persona --> pkg_system_prompt
|
||||
pkg_sandbox_local --> pkg_invariants
|
||||
pkg_sandbox_local --> pkg_llm
|
||||
pkg_sandbox_local --> pkg_sandbox
|
||||
@@ -620,6 +616,14 @@ flowchart TD
|
||||
pkg_hook_protocol --> pkg_invariants
|
||||
pkg_hook_protocol --> pkg_session
|
||||
pkg_hook_protocol --> pkg_shell
|
||||
pkg_api_workspace_controller --> pkg_api_gateway
|
||||
pkg_api_workspace_controller --> pkg_client_connection
|
||||
pkg_api_workspace_controller --> pkg_host_directory_picker
|
||||
pkg_api_workspace_controller --> pkg_invariants
|
||||
pkg_api_workspace_controller --> pkg_session
|
||||
pkg_api_workspace_controller --> pkg_storage_domain
|
||||
pkg_api_workspace_controller --> pkg_typert_protocol
|
||||
pkg_api_workspace_controller --> pkg_workspace
|
||||
pkg_file_reference --> pkg_agent
|
||||
pkg_file_reference --> pkg_invariants
|
||||
pkg_time_context --> pkg_agent
|
||||
@@ -1034,17 +1038,6 @@ flowchart TD
|
||||
pkg_web_app --> pkg_invariants
|
||||
pkg_web_app --> pkg_shell_env
|
||||
pkg_web_app --> pkg_system_prompt
|
||||
pkg_client_connection --> pkg_attachment
|
||||
pkg_client_connection --> pkg_brand
|
||||
pkg_client_connection --> pkg_commands
|
||||
pkg_client_connection --> pkg_credentials
|
||||
pkg_client_connection --> pkg_host_directory_picker
|
||||
pkg_client_connection --> pkg_host_webserver
|
||||
pkg_client_connection --> pkg_invariants
|
||||
pkg_client_connection --> pkg_llm
|
||||
pkg_client_connection --> pkg_session
|
||||
pkg_client_connection --> pkg_settings
|
||||
pkg_client_connection --> pkg_tool_todo
|
||||
pkg_compaction_tool_result_pruner --> pkg_compaction
|
||||
pkg_compaction_tool_result_pruner --> pkg_invariants
|
||||
pkg_compaction_tool_result_pruner --> pkg_llm
|
||||
@@ -1123,11 +1116,6 @@ flowchart TD
|
||||
pkg_tool_session_query --> pkg_system_prompt
|
||||
pkg_tool_session_query --> pkg_timeout
|
||||
pkg_tool_session_query --> pkg_tools
|
||||
pkg_api_gateway --> pkg_brand
|
||||
pkg_api_gateway --> pkg_client_connection
|
||||
pkg_api_gateway --> pkg_host_webserver
|
||||
pkg_api_gateway --> pkg_invariants
|
||||
pkg_api_gateway --> pkg_typert_registry
|
||||
pkg_compaction_basic --> pkg_agent
|
||||
pkg_compaction_basic --> pkg_commands
|
||||
pkg_compaction_basic --> pkg_compaction
|
||||
@@ -1169,13 +1157,6 @@ flowchart TD
|
||||
pkg_agent_spine_demo --> pkg_tool_jobs
|
||||
pkg_agent_spine_demo --> pkg_tool_skill
|
||||
pkg_agent_spine_demo --> pkg_tools
|
||||
pkg_experimental_webworker_runtime --> pkg_client_connection
|
||||
pkg_experimental_webworker_runtime --> pkg_client_modules
|
||||
pkg_experimental_webworker_runtime --> pkg_host_webserver
|
||||
pkg_experimental_webworker_runtime --> pkg_invariants
|
||||
pkg_host_frontend_static --> pkg_client_connection
|
||||
pkg_host_frontend_static --> pkg_host_webserver
|
||||
pkg_host_frontend_static --> pkg_invariants
|
||||
pkg_webhook_github --> pkg_credentials
|
||||
pkg_webhook_github --> pkg_host_webserver
|
||||
pkg_webhook_github --> pkg_invariants
|
||||
@@ -1263,14 +1244,6 @@ flowchart TD
|
||||
pkg_api_session_controller --> pkg_util_time
|
||||
pkg_api_session_controller --> pkg_util_workspace_path
|
||||
pkg_api_session_controller --> pkg_workspace
|
||||
pkg_api_workspace_controller --> pkg_api_gateway
|
||||
pkg_api_workspace_controller --> pkg_client_connection
|
||||
pkg_api_workspace_controller --> pkg_host_directory_picker
|
||||
pkg_api_workspace_controller --> pkg_invariants
|
||||
pkg_api_workspace_controller --> pkg_session
|
||||
pkg_api_workspace_controller --> pkg_storage_domain
|
||||
pkg_api_workspace_controller --> pkg_typert_protocol
|
||||
pkg_api_workspace_controller --> pkg_workspace
|
||||
pkg_experimental_agent_team --> pkg_agent
|
||||
pkg_experimental_agent_team --> pkg_brand
|
||||
pkg_experimental_agent_team --> pkg_invariants
|
||||
@@ -1307,30 +1280,18 @@ flowchart TD
|
||||
pkg_subagent_spawn_in_process --> pkg_invariants
|
||||
pkg_subagent_spawn_in_process --> pkg_subagent
|
||||
pkg_subagent_spawn_in_process --> pkg_subagent_in_process_driver
|
||||
pkg_api_remotes --> pkg_agent_presets
|
||||
pkg_api_remotes --> pkg_api_gateway
|
||||
pkg_api_remotes --> pkg_api_session_controller
|
||||
pkg_api_remotes --> pkg_api_settings_controller
|
||||
pkg_api_remotes --> pkg_api_workspace_controller
|
||||
pkg_api_remotes --> pkg_commands
|
||||
pkg_api_remotes --> pkg_cordis_host_runner
|
||||
pkg_api_remotes --> pkg_credentials
|
||||
pkg_api_remotes --> pkg_file_reference
|
||||
pkg_api_remotes --> pkg_goal
|
||||
pkg_api_remotes --> pkg_host_plugin_inventory
|
||||
pkg_api_remotes --> pkg_invariants
|
||||
pkg_api_remotes --> pkg_llm
|
||||
pkg_api_remotes --> pkg_message_feedback
|
||||
pkg_api_remotes --> pkg_session
|
||||
pkg_api_remotes --> pkg_session_reference
|
||||
pkg_api_remotes --> pkg_settings
|
||||
pkg_api_remotes --> pkg_subagent
|
||||
pkg_api_remotes --> pkg_user_approval
|
||||
pkg_api_remotes --> pkg_user_questions
|
||||
pkg_client_ui_session --> pkg_api_session_controller
|
||||
pkg_client_ui_session --> pkg_client_ui_renderer
|
||||
pkg_client_ui_session --> pkg_invariants
|
||||
pkg_client_ui_session --> pkg_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_remotes
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_session_controller
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_locale
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_conversation
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_primitives
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_renderer
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_slots
|
||||
pkg_experimental_client_ui_agent_team --> pkg_experimental_agent_team
|
||||
pkg_experimental_client_ui_agent_team --> pkg_invariants
|
||||
pkg_experimental_client_ui_agent_team --> pkg_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_typert_protocol
|
||||
pkg_experimental_tool_agent_team --> pkg_agent
|
||||
pkg_experimental_tool_agent_team --> pkg_experimental_agent_team
|
||||
pkg_experimental_tool_agent_team --> pkg_invariants
|
||||
@@ -1350,358 +1311,6 @@ flowchart TD
|
||||
pkg_sdk_jsonrpc_server --> pkg_sdk_protocol
|
||||
pkg_sdk_jsonrpc_server --> pkg_session
|
||||
pkg_sdk_jsonrpc_server --> pkg_subagent
|
||||
pkg_subagent_dsh_sdk --> pkg_agent
|
||||
pkg_subagent_dsh_sdk --> pkg_invariants
|
||||
pkg_subagent_dsh_sdk --> pkg_llm
|
||||
pkg_subagent_dsh_sdk --> pkg_sdk_client
|
||||
pkg_subagent_dsh_sdk --> pkg_session
|
||||
pkg_subagent_dsh_sdk --> pkg_subagent
|
||||
pkg_subagent_dsh_sdk --> pkg_subprocess
|
||||
pkg_client_ui_settings --> pkg_api_remotes
|
||||
pkg_client_ui_settings --> pkg_invariants
|
||||
pkg_client_ui_settings --> pkg_settings
|
||||
pkg_client_locale --> pkg_api_remotes
|
||||
pkg_client_locale --> pkg_client_connection
|
||||
pkg_client_locale --> pkg_client_ui_renderer
|
||||
pkg_client_locale --> pkg_client_ui_settings
|
||||
pkg_client_locale --> pkg_invariants
|
||||
pkg_client_locale --> pkg_settings
|
||||
pkg_client_ui_settings_models --> pkg_api_remotes
|
||||
pkg_client_ui_settings_models --> pkg_client_locale
|
||||
pkg_client_ui_settings_models --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_models --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_models --> pkg_invariants
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_api_remotes
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_client_locale
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_plugin_inventory --> pkg_invariants
|
||||
pkg_client_ui_settings_plugins --> pkg_api_remotes
|
||||
pkg_client_ui_settings_plugins --> pkg_client_locale
|
||||
pkg_client_ui_settings_plugins --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_plugins --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_plugins --> pkg_invariants
|
||||
pkg_client_ui_theme --> pkg_api_remotes
|
||||
pkg_client_ui_theme --> pkg_client_connection
|
||||
pkg_client_ui_theme --> pkg_client_locale
|
||||
pkg_client_ui_theme --> pkg_client_ui_renderer
|
||||
pkg_client_ui_theme --> pkg_client_ui_settings
|
||||
pkg_client_ui_theme --> pkg_host_webserver
|
||||
pkg_client_ui_theme --> pkg_invariants
|
||||
pkg_client_ui_theme --> pkg_settings
|
||||
pkg_client_ui_layout --> pkg_client_locale
|
||||
pkg_client_ui_layout --> pkg_client_ui_renderer
|
||||
pkg_client_ui_layout --> pkg_client_ui_session
|
||||
pkg_client_ui_layout --> pkg_client_ui_theme
|
||||
pkg_client_ui_layout --> pkg_invariants
|
||||
pkg_cordis_client_runner --> pkg_api_remotes
|
||||
pkg_cordis_client_runner --> pkg_client_modules
|
||||
pkg_cordis_client_runner --> pkg_client_ui_renderer
|
||||
pkg_cordis_client_runner --> pkg_client_ui_theme
|
||||
pkg_cordis_client_runner --> pkg_invariants
|
||||
pkg_client_ui_conversation --> pkg_api_remotes
|
||||
pkg_client_ui_conversation --> pkg_api_session_controller
|
||||
pkg_client_ui_conversation --> pkg_api_workspace_controller
|
||||
pkg_client_ui_conversation --> pkg_attachment
|
||||
pkg_client_ui_conversation --> pkg_brand
|
||||
pkg_client_ui_conversation --> pkg_client_locale
|
||||
pkg_client_ui_conversation --> pkg_client_ui_layout
|
||||
pkg_client_ui_conversation --> pkg_client_ui_renderer
|
||||
pkg_client_ui_conversation --> pkg_client_ui_session
|
||||
pkg_client_ui_conversation --> pkg_client_ui_settings
|
||||
pkg_client_ui_conversation --> pkg_client_ui_workspace
|
||||
pkg_client_ui_conversation --> pkg_commands
|
||||
pkg_client_ui_conversation --> pkg_goal
|
||||
pkg_client_ui_conversation --> pkg_invariants
|
||||
pkg_client_ui_conversation --> pkg_llm
|
||||
pkg_client_ui_conversation --> pkg_llm_retry
|
||||
pkg_client_ui_conversation --> pkg_permission_presets
|
||||
pkg_client_ui_conversation --> pkg_plan_mode
|
||||
pkg_client_ui_conversation --> pkg_session
|
||||
pkg_client_ui_conversation --> pkg_settings
|
||||
pkg_client_ui_conversation --> pkg_token_meter
|
||||
pkg_client_ui_conversation --> pkg_tool_todo
|
||||
pkg_client_ui_conversation --> pkg_util_crypto
|
||||
pkg_client_ui_conversation --> pkg_util_workspace_path
|
||||
pkg_client_ui_conversation --> pkg_workspace
|
||||
pkg_client_ui_sidebar --> pkg_api_workspace_controller
|
||||
pkg_client_ui_sidebar --> pkg_client_locale
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_layout
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_renderer
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_session
|
||||
pkg_client_ui_sidebar --> pkg_client_ui_workspace
|
||||
pkg_client_ui_sidebar --> pkg_invariants
|
||||
pkg_client_ui_workspace --> pkg_api_remotes
|
||||
pkg_client_ui_workspace --> pkg_api_session_controller
|
||||
pkg_client_ui_workspace --> pkg_api_workspace_controller
|
||||
pkg_client_ui_workspace --> pkg_client_connection
|
||||
pkg_client_ui_workspace --> pkg_client_locale
|
||||
pkg_client_ui_workspace --> pkg_client_ui_conversation
|
||||
pkg_client_ui_workspace --> pkg_client_ui_renderer
|
||||
pkg_client_ui_workspace --> pkg_client_ui_session
|
||||
pkg_client_ui_workspace --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_workspace --> pkg_invariants
|
||||
pkg_client_ui_workspace --> pkg_schedule
|
||||
pkg_client_ui_workspace --> pkg_session
|
||||
pkg_client_ui_workspace --> pkg_typert_protocol
|
||||
pkg_client_ui_workspace --> pkg_util_workspace_path
|
||||
pkg_client_ui_agent_preset --> pkg_agent_presets
|
||||
pkg_client_ui_agent_preset --> pkg_api_remotes
|
||||
pkg_client_ui_agent_preset --> pkg_api_session_controller
|
||||
pkg_client_ui_agent_preset --> pkg_client_connection
|
||||
pkg_client_ui_agent_preset --> pkg_client_locale
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_conversation
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_renderer
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_session
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_settings
|
||||
pkg_client_ui_agent_preset --> pkg_client_ui_workspace
|
||||
pkg_client_ui_agent_preset --> pkg_invariants
|
||||
pkg_client_ui_agent_preset --> pkg_session
|
||||
pkg_client_ui_approval --> pkg_api_remotes
|
||||
pkg_client_ui_approval --> pkg_api_session_controller
|
||||
pkg_client_ui_approval --> pkg_client_locale
|
||||
pkg_client_ui_approval --> pkg_client_ui_conversation
|
||||
pkg_client_ui_approval --> pkg_client_ui_renderer
|
||||
pkg_client_ui_approval --> pkg_client_ui_session
|
||||
pkg_client_ui_approval --> pkg_invariants
|
||||
pkg_client_ui_approval --> pkg_llm
|
||||
pkg_client_ui_approval --> pkg_session
|
||||
pkg_client_ui_approval --> pkg_typert_protocol
|
||||
pkg_client_ui_brand_official --> pkg_client_ui_renderer
|
||||
pkg_client_ui_brand_official --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_brand_official --> pkg_invariants
|
||||
pkg_client_ui_directory_picker_browse --> pkg_api_remotes
|
||||
pkg_client_ui_directory_picker_browse --> pkg_client_locale
|
||||
pkg_client_ui_directory_picker_browse --> pkg_client_ui_renderer
|
||||
pkg_client_ui_directory_picker_browse --> pkg_client_ui_workspace
|
||||
pkg_client_ui_directory_picker_browse --> pkg_invariants
|
||||
pkg_client_ui_directory_picker_native --> pkg_client_ui_renderer
|
||||
pkg_client_ui_directory_picker_native --> pkg_client_ui_workspace
|
||||
pkg_client_ui_directory_picker_native --> pkg_invariants
|
||||
pkg_client_ui_input_trigger --> pkg_api_session_controller
|
||||
pkg_client_ui_input_trigger --> pkg_client_locale
|
||||
pkg_client_ui_input_trigger --> pkg_client_ui_conversation
|
||||
pkg_client_ui_input_trigger --> pkg_client_ui_renderer
|
||||
pkg_client_ui_input_trigger --> pkg_client_ui_session
|
||||
pkg_client_ui_input_trigger --> pkg_file_reference
|
||||
pkg_client_ui_input_trigger --> pkg_invariants
|
||||
pkg_client_ui_input_trigger --> pkg_session
|
||||
pkg_client_ui_jobs --> pkg_api_session_controller
|
||||
pkg_client_ui_jobs --> pkg_client_locale
|
||||
pkg_client_ui_jobs --> pkg_client_ui_conversation
|
||||
pkg_client_ui_jobs --> pkg_client_ui_renderer
|
||||
pkg_client_ui_jobs --> pkg_client_ui_session
|
||||
pkg_client_ui_jobs --> pkg_invariants
|
||||
pkg_client_ui_plan --> pkg_api_remotes
|
||||
pkg_client_ui_plan --> pkg_client_locale
|
||||
pkg_client_ui_plan --> pkg_client_ui_conversation
|
||||
pkg_client_ui_plan --> pkg_client_ui_renderer
|
||||
pkg_client_ui_plan --> pkg_client_ui_session
|
||||
pkg_client_ui_plan --> pkg_invariants
|
||||
pkg_client_ui_plan --> pkg_plan_mode
|
||||
pkg_client_ui_plan --> pkg_session
|
||||
pkg_client_ui_schedule --> pkg_api_session_controller
|
||||
pkg_client_ui_schedule --> pkg_client_locale
|
||||
pkg_client_ui_schedule --> pkg_client_ui_conversation
|
||||
pkg_client_ui_schedule --> pkg_client_ui_renderer
|
||||
pkg_client_ui_schedule --> pkg_client_ui_session
|
||||
pkg_client_ui_schedule --> pkg_invariants
|
||||
pkg_client_ui_schedule --> pkg_schedule
|
||||
pkg_client_ui_settings_general --> pkg_api_remotes
|
||||
pkg_client_ui_settings_general --> pkg_client_connection
|
||||
pkg_client_ui_settings_general --> pkg_client_locale
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_renderer
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_session
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_settings
|
||||
pkg_client_ui_settings_general --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_settings_general --> pkg_invariants
|
||||
pkg_client_ui_settings_general --> pkg_settings
|
||||
pkg_client_ui_trajectory --> pkg_agent
|
||||
pkg_client_ui_trajectory --> pkg_api_session_controller
|
||||
pkg_client_ui_trajectory --> pkg_attachment
|
||||
pkg_client_ui_trajectory --> pkg_client_locale
|
||||
pkg_client_ui_trajectory --> pkg_client_ui_conversation
|
||||
pkg_client_ui_trajectory --> pkg_client_ui_renderer
|
||||
pkg_client_ui_trajectory --> pkg_client_ui_session
|
||||
pkg_client_ui_trajectory --> pkg_compaction
|
||||
pkg_client_ui_trajectory --> pkg_invariants
|
||||
pkg_client_ui_trajectory --> pkg_llm
|
||||
pkg_client_ui_trajectory --> pkg_session
|
||||
pkg_client_ui_trajectory --> pkg_tools
|
||||
pkg_client_ui_user_questions --> pkg_api_remotes
|
||||
pkg_client_ui_user_questions --> pkg_api_session_controller
|
||||
pkg_client_ui_user_questions --> pkg_client_locale
|
||||
pkg_client_ui_user_questions --> pkg_client_ui_conversation
|
||||
pkg_client_ui_user_questions --> pkg_client_ui_renderer
|
||||
pkg_client_ui_user_questions --> pkg_client_ui_session
|
||||
pkg_client_ui_user_questions --> pkg_invariants
|
||||
pkg_client_ui_user_questions --> pkg_session
|
||||
pkg_client_ui_user_questions --> pkg_typert_protocol
|
||||
pkg_client_ui_user_questions --> pkg_user_questions
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_remotes
|
||||
pkg_experimental_client_ui_agent_team --> pkg_api_session_controller
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_locale
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_conversation
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_primitives
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_renderer
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_client_ui_slots
|
||||
pkg_experimental_client_ui_agent_team --> pkg_experimental_agent_team
|
||||
pkg_experimental_client_ui_agent_team --> pkg_invariants
|
||||
pkg_experimental_client_ui_agent_team --> pkg_session
|
||||
pkg_experimental_client_ui_agent_team --> pkg_typert_protocol
|
||||
pkg_client_ui_chat --> pkg_agent
|
||||
pkg_client_ui_chat --> pkg_api_remotes
|
||||
pkg_client_ui_chat --> pkg_api_session_controller
|
||||
pkg_client_ui_chat --> pkg_api_workspace_controller
|
||||
pkg_client_ui_chat --> pkg_attachment
|
||||
pkg_client_ui_chat --> pkg_client_locale
|
||||
pkg_client_ui_chat --> pkg_client_ui_approval
|
||||
pkg_client_ui_chat --> pkg_client_ui_conversation
|
||||
pkg_client_ui_chat --> pkg_client_ui_layout
|
||||
pkg_client_ui_chat --> pkg_client_ui_renderer
|
||||
pkg_client_ui_chat --> pkg_client_ui_session
|
||||
pkg_client_ui_chat --> pkg_client_ui_settings
|
||||
pkg_client_ui_chat --> pkg_client_ui_workspace
|
||||
pkg_client_ui_chat --> pkg_commands
|
||||
pkg_client_ui_chat --> pkg_compaction
|
||||
pkg_client_ui_chat --> pkg_invariants
|
||||
pkg_client_ui_chat --> pkg_llm
|
||||
pkg_client_ui_chat --> pkg_llm_retry
|
||||
pkg_client_ui_chat --> pkg_session
|
||||
pkg_client_ui_chat --> pkg_session_stats
|
||||
pkg_client_ui_chat --> pkg_settings
|
||||
pkg_client_ui_chat --> pkg_token_meter
|
||||
pkg_client_ui_chat --> pkg_tools
|
||||
pkg_client_ui_chat --> pkg_util_workspace_path
|
||||
pkg_client_ui_commands --> pkg_api_remotes
|
||||
pkg_client_ui_commands --> pkg_api_session_controller
|
||||
pkg_client_ui_commands --> pkg_client_locale
|
||||
pkg_client_ui_commands --> pkg_client_ui_conversation
|
||||
pkg_client_ui_commands --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_commands --> pkg_client_ui_renderer
|
||||
pkg_client_ui_commands --> pkg_client_ui_session
|
||||
pkg_client_ui_commands --> pkg_commands
|
||||
pkg_client_ui_commands --> pkg_invariants
|
||||
pkg_client_ui_commands --> pkg_session
|
||||
pkg_client_ui_reference --> pkg_api_remotes
|
||||
pkg_client_ui_reference --> pkg_api_session_controller
|
||||
pkg_client_ui_reference --> pkg_client_connection
|
||||
pkg_client_ui_reference --> pkg_client_locale
|
||||
pkg_client_ui_reference --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_reference --> pkg_file_reference
|
||||
pkg_client_ui_reference --> pkg_invariants
|
||||
pkg_client_ui_reference --> pkg_session_reference
|
||||
pkg_client_ui_reference --> pkg_typert_protocol
|
||||
pkg_client_ui_reference --> pkg_util_workspace_path
|
||||
pkg_client_ui_subagent --> pkg_api_session_controller
|
||||
pkg_client_ui_subagent --> pkg_client_connection
|
||||
pkg_client_ui_subagent --> pkg_client_locale
|
||||
pkg_client_ui_subagent --> pkg_client_ui_conversation
|
||||
pkg_client_ui_subagent --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_subagent --> pkg_client_ui_renderer
|
||||
pkg_client_ui_subagent --> pkg_client_ui_session
|
||||
pkg_client_ui_subagent --> pkg_invariants
|
||||
pkg_client_ui_subagent --> pkg_session
|
||||
pkg_client_ui_subagent --> pkg_subagent
|
||||
pkg_client_ui_subagent --> pkg_token_meter
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_client_ui_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_browse
|
||||
pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
|
||||
pkg_host_directory_picker_auto --> pkg_host_webserver
|
||||
pkg_host_directory_picker_auto --> pkg_invariants
|
||||
pkg_session_log_export --> pkg_attachment
|
||||
pkg_session_log_export --> pkg_client_connection
|
||||
pkg_session_log_export --> pkg_client_locale
|
||||
pkg_session_log_export --> pkg_client_ui_commands
|
||||
pkg_session_log_export --> pkg_client_ui_conversation
|
||||
pkg_session_log_export --> pkg_client_ui_renderer
|
||||
pkg_session_log_export --> pkg_client_ui_session
|
||||
pkg_session_log_export --> pkg_commands
|
||||
pkg_session_log_export --> pkg_invariants
|
||||
pkg_session_log_export --> pkg_session
|
||||
pkg_session_log_export --> pkg_session_persistence
|
||||
pkg_session_log_export --> pkg_session_query
|
||||
pkg_client_ui_attachment --> pkg_attachment
|
||||
pkg_client_ui_attachment --> pkg_client_ui_chat
|
||||
pkg_client_ui_attachment --> pkg_client_ui_conversation
|
||||
pkg_client_ui_attachment --> pkg_client_ui_renderer
|
||||
pkg_client_ui_attachment --> pkg_client_ui_trajectory
|
||||
pkg_client_ui_attachment --> pkg_invariants
|
||||
pkg_client_ui_deliverables --> pkg_api_remotes
|
||||
pkg_client_ui_deliverables --> pkg_client_connection
|
||||
pkg_client_ui_deliverables --> pkg_client_locale
|
||||
pkg_client_ui_deliverables --> pkg_client_ui_chat
|
||||
pkg_client_ui_deliverables --> pkg_client_ui_conversation
|
||||
pkg_client_ui_deliverables --> pkg_client_ui_renderer
|
||||
pkg_client_ui_deliverables --> pkg_invariants
|
||||
pkg_client_ui_deliverables --> pkg_session
|
||||
pkg_client_ui_deliverables --> pkg_system_prompt
|
||||
pkg_client_ui_goal --> pkg_api_remotes
|
||||
pkg_client_ui_goal --> pkg_api_session_controller
|
||||
pkg_client_ui_goal --> pkg_client_locale
|
||||
pkg_client_ui_goal --> pkg_client_ui_chat
|
||||
pkg_client_ui_goal --> pkg_client_ui_conversation
|
||||
pkg_client_ui_goal --> pkg_client_ui_renderer
|
||||
pkg_client_ui_goal --> pkg_client_ui_session
|
||||
pkg_client_ui_goal --> pkg_commands
|
||||
pkg_client_ui_goal --> pkg_goal
|
||||
pkg_client_ui_goal --> pkg_invariants
|
||||
pkg_client_ui_goal --> pkg_session
|
||||
pkg_client_ui_goal --> pkg_typert_protocol
|
||||
pkg_client_ui_message_feedback --> pkg_api_remotes
|
||||
pkg_client_ui_message_feedback --> pkg_client_connection
|
||||
pkg_client_ui_message_feedback --> pkg_client_locale
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_chat
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_conversation
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_renderer
|
||||
pkg_client_ui_message_feedback --> pkg_client_ui_session
|
||||
pkg_client_ui_message_feedback --> pkg_invariants
|
||||
pkg_client_ui_message_feedback --> pkg_message_feedback
|
||||
pkg_client_ui_message_feedback --> pkg_session
|
||||
pkg_client_ui_message_feedback --> pkg_typert_protocol
|
||||
pkg_client_ui_model_selection --> pkg_api_remotes
|
||||
pkg_client_ui_model_selection --> pkg_api_session_controller
|
||||
pkg_client_ui_model_selection --> pkg_client_locale
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_commands
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_conversation
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_renderer
|
||||
pkg_client_ui_model_selection --> pkg_client_ui_session
|
||||
pkg_client_ui_model_selection --> pkg_invariants
|
||||
pkg_client_ui_model_selection --> pkg_session
|
||||
pkg_client_ui_model_selection --> pkg_typert_protocol
|
||||
pkg_client_ui_permission_presets --> pkg_api_remotes
|
||||
pkg_client_ui_permission_presets --> pkg_api_session_controller
|
||||
pkg_client_ui_permission_presets --> pkg_client_locale
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_commands
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_renderer
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_session
|
||||
pkg_client_ui_permission_presets --> pkg_client_ui_settings
|
||||
pkg_client_ui_permission_presets --> pkg_invariants
|
||||
pkg_client_ui_permission_presets --> pkg_permission_presets
|
||||
pkg_client_ui_tool --> pkg_api_remotes
|
||||
pkg_client_ui_tool --> pkg_api_workspace_controller
|
||||
pkg_client_ui_tool --> pkg_client_connection
|
||||
pkg_client_ui_tool --> pkg_client_locale
|
||||
pkg_client_ui_tool --> pkg_client_ui_chat
|
||||
pkg_client_ui_tool --> pkg_client_ui_conversation
|
||||
pkg_client_ui_tool --> pkg_client_ui_renderer
|
||||
pkg_client_ui_tool --> pkg_client_ui_session
|
||||
pkg_client_ui_tool --> pkg_invariants
|
||||
pkg_client_ui_tool --> pkg_util_workspace_path
|
||||
pkg_client_ui_workflow_run --> pkg_api_session_controller
|
||||
pkg_client_ui_workflow_run --> pkg_client_locale
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_chat
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_conversation
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_renderer
|
||||
pkg_client_ui_workflow_run --> pkg_client_ui_session
|
||||
pkg_client_ui_workflow_run --> pkg_invariants
|
||||
pkg_client_ui_workflow_run --> pkg_session
|
||||
pkg_client_ui_workflow_run --> pkg_tool_workflow
|
||||
pkg_client_ui_workflow_run --> pkg_workflow
|
||||
pkg_client_test_runtime --> pkg_api_session_controller
|
||||
pkg_client_test_runtime --> pkg_api_workspace_controller
|
||||
pkg_client_test_runtime --> pkg_attachment
|
||||
@@ -1717,30 +1326,66 @@ flowchart TD
|
||||
pkg_client_test_runtime --> pkg_session
|
||||
pkg_client_test_runtime --> pkg_subagent
|
||||
pkg_client_test_runtime --> pkg_typert_protocol
|
||||
pkg_client_ui_skill --> pkg_api_remotes
|
||||
pkg_client_ui_skill --> pkg_api_session_controller
|
||||
pkg_client_ui_skill --> pkg_client_connection
|
||||
pkg_client_ui_skill --> pkg_client_locale
|
||||
pkg_client_ui_skill --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_skill --> pkg_client_ui_renderer
|
||||
pkg_client_ui_skill --> pkg_client_ui_tool
|
||||
pkg_client_ui_skill --> pkg_invariants
|
||||
pkg_client_ui_skill --> pkg_session
|
||||
pkg_client_ui_cordis --> pkg_api_remotes
|
||||
pkg_client_ui_cordis --> pkg_client_connection
|
||||
pkg_client_ui_cordis --> pkg_client_locale
|
||||
pkg_client_ui_cordis --> pkg_client_ui_input_trigger
|
||||
pkg_client_ui_cordis --> pkg_client_ui_renderer
|
||||
pkg_client_ui_cordis --> pkg_client_ui_session
|
||||
pkg_client_ui_cordis --> pkg_client_ui_sidebar
|
||||
pkg_client_ui_cordis --> pkg_client_ui_tool
|
||||
pkg_client_ui_cordis --> pkg_cordis_client_runner
|
||||
pkg_client_ui_cordis --> pkg_invariants
|
||||
pkg_subagent_dsh_sdk --> pkg_agent
|
||||
pkg_subagent_dsh_sdk --> pkg_invariants
|
||||
pkg_subagent_dsh_sdk --> pkg_llm
|
||||
pkg_subagent_dsh_sdk --> pkg_sdk_client
|
||||
pkg_subagent_dsh_sdk --> pkg_session
|
||||
pkg_subagent_dsh_sdk --> pkg_subagent
|
||||
pkg_subagent_dsh_sdk --> pkg_subprocess
|
||||
```
|
||||
|
||||
| Package | Group | Depends on |
|
||||
| 包 | 分组 | Peer 依赖 |
|
||||
| --- | --- | --- |
|
||||
| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | — |
|
||||
| [`client-connection`](../packages/client/connection) | `client` | — |
|
||||
| [`client-hmr`](../packages/client/hmr) | `client` | — |
|
||||
| [`client-locale`](../packages/client/locale) | `client` | — |
|
||||
| [`client-modules`](../packages/client/modules) | `client` | — |
|
||||
| [`client-store`](../packages/client/store) | `client` | — |
|
||||
| [`client-ui-agent-preset`](../packages/client/ui-agent-preset) | `client` | — |
|
||||
| [`client-ui-approval`](../packages/client/ui-approval) | `client` | — |
|
||||
| [`client-ui-attachment`](../packages/client/ui-attachment) | `client` | — |
|
||||
| [`client-ui-brand-official`](../packages/client/ui-brand-official) | `client` | — |
|
||||
| [`client-ui-chat`](../packages/client/ui-chat) | `client` | — |
|
||||
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | — |
|
||||
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | — |
|
||||
| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | — |
|
||||
| [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | — |
|
||||
| [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | — |
|
||||
| [`client-ui-goal`](../packages/client/ui-goal) | `client` | — |
|
||||
| [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | — |
|
||||
| [`client-ui-jobs`](../packages/client/ui-jobs) | `client` | — |
|
||||
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | — |
|
||||
| [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | — |
|
||||
| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | — |
|
||||
| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | — |
|
||||
| [`client-ui-plan`](../packages/client/ui-plan) | `client` | — |
|
||||
| [`client-ui-primitives`](../packages/client/ui-primitives) | `client` | — |
|
||||
| [`client-ui-reference`](../packages/client/ui-reference) | `client` | — |
|
||||
| [`client-ui-renderer`](../packages/client/ui-renderer) | `client` | — |
|
||||
| [`client-ui-schedule`](../packages/client/ui-schedule) | `client` | — |
|
||||
| [`client-ui-session`](../packages/client/ui-session) | `client` | — |
|
||||
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | — |
|
||||
| [`client-ui-settings-general`](../packages/client/ui-settings-general) | `client` | — |
|
||||
| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | — |
|
||||
| [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | — |
|
||||
| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | — |
|
||||
| [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | — |
|
||||
| [`client-ui-skill`](../packages/client/ui-skill) | `client` | — |
|
||||
| [`client-ui-slots`](../packages/client/ui-slots) | `client` | — |
|
||||
| [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | — |
|
||||
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | — |
|
||||
| [`client-ui-tool`](../packages/client/ui-tool) | `client` | — |
|
||||
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | — |
|
||||
| [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | — |
|
||||
| [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | — |
|
||||
| [`client-ui-workspace`](../packages/client/ui-workspace) | `client` | — |
|
||||
| [`client-web`](../packages/client/web) | `client` | — |
|
||||
| [`client-ui-cordis`](../packages/extensions/ui-cordis) | `extensions` | — |
|
||||
| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | — |
|
||||
| [`invariants`](../packages/runtime-diagnostics/invariants) | `runtime-diagnostics` | — |
|
||||
| [`typert-registry`](../packages/typert/registry) | `typert` | — |
|
||||
| [`atomic-write`](../packages/util/atomic-write) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`brand`](../packages/util/brand) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`home-paths`](../packages/util/home-paths) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
@@ -1758,11 +1403,6 @@ flowchart TD
|
||||
| [`base`](../packages/bundle/base) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`sdk-minimal`](../packages/bundle/sdk-minimal) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-store`](../packages/client/store) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-primitives`](../packages/client/ui-primitives) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-renderer`](../packages/client/ui-renderer) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-slots`](../packages/client/ui-slots) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-web`](../packages/client/web) | `client` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`code-runtime`](../packages/code-runtime/code-runtime) | `code-runtime` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`code-runtime-python`](../packages/code-runtime/code-runtime-python) | `code-runtime` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`e2b`](../packages/e2b/e2b) | `e2b` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
@@ -1779,38 +1419,34 @@ flowchart TD
|
||||
| [`win32-process`](../packages/subprocess/win32-process) | `subprocess` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`llm-mock-server`](../packages/test-support/llm-mock-server) | `test-support` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`typert-generator`](../packages/typert/generator) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`typert-loader`](../packages/typert/loader) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
|
||||
| [`typert-protocol`](../packages/typert/protocol) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`typert-registry`](../packages/typert/registry) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`llm`](../packages/llm/llm) | `llm` | [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`session`](../packages/core/session) | `core` | [`scope`](../packages/core/scope) |
|
||||
| [`api-gateway`](../packages/api/gateway) | `api` | [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`api-remotes`](../packages/api/remotes) | `api` | [`scope`](../packages/core/scope) |
|
||||
| [`attachment`](../packages/attachment/attachment) | `attachment` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-modules`](../packages/client/modules) | `client` | [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`credentials`](../packages/credentials/credentials) | `credentials` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`subprocess-e2b`](../packages/e2b/subprocess-e2b) | `e2b` | [`e2b`](../packages/e2b/e2b), [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-plugin-inventory`](../packages/host/plugin-inventory) | `host` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`anonymous-user-id`](../packages/identity/anonymous-user-id) | `identity` | [`brand`](../packages/util/brand), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`storage-domain`](../packages/storage/storage-domain) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
|
||||
| [`storage-json`](../packages/storage/storage-json) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
|
||||
| [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) |
|
||||
| [`subprocess-local`](../packages/subprocess/subprocess-local) | `subprocess` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
| [`typert-loader`](../packages/typert/loader) | `typert` | [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
|
||||
| [`llm`](../packages/llm/llm) | `llm` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-hmr`](../packages/client/hmr) | `client` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) |
|
||||
| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`session`](../packages/core/session) | `core` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`system-prompt`](../packages/core/system-prompt) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
|
||||
| [`skill`](../packages/skill/skill) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) |
|
||||
| [`web`](../packages/web/web) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`authorization`](../packages/credentials/authorization) | `credentials` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`lsp`](../packages/lsp/lsp) | `lsp` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`skill-badge`](../packages/skill/skill-badge) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`skill`](../packages/skill/skill) |
|
||||
| [`web-fetch-http`](../packages/web/web-fetch-http) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`web`](../packages/web/web) |
|
||||
| [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`spill`](../packages/spill/spill) | `spill` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
|
||||
| [`app-boot`](../packages/boot/app-boot) | `boot` | [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`code-runtime-worker-thread`](../packages/code-runtime/code-runtime-worker-thread) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) |
|
||||
| [`persona`](../packages/preset/persona) | `preset` | [`invariants`](../packages/runtime-diagnostics/invariants), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`authorization`](../packages/credentials/authorization) | `credentials` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) |
|
||||
| [`lsp`](../packages/lsp/lsp) | `lsp` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) |
|
||||
| [`sandbox`](../packages/sandbox/sandbox) | `sandbox` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
|
||||
| [`session-log-deepseek`](../packages/session/session-log-deepseek) | `session` | [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`session-persistence`](../packages/session/session-persistence) | `session` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) |
|
||||
@@ -1819,8 +1455,14 @@ flowchart TD
|
||||
| [`session-snapshot`](../packages/test-support/session-snapshot) | `test-support` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`agent`](../packages/core/agent) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`system-prompt`](../packages/core/system-prompt), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) |
|
||||
| [`skill-badge`](../packages/skill/skill-badge) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`skill`](../packages/skill/skill) |
|
||||
| [`web-fetch-http`](../packages/web/web-fetch-http) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`timeout`](../packages/util/timeout), [`web`](../packages/web/web) |
|
||||
| [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`spill-local`](../packages/spill/spill-local) | `spill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`spill`](../packages/spill/spill) |
|
||||
| [`app-boot`](../packages/boot/app-boot) | `boot` | [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`message-feedback`](../packages/feedback/message-feedback) | `feedback` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`persona`](../packages/preset/persona) | `preset` | [`invariants`](../packages/runtime-diagnostics/invariants), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`sandbox-local`](../packages/sandbox/sandbox-local) | `sandbox` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`session`](../packages/core/session) |
|
||||
| [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence) |
|
||||
| [`session-persistence-sqlite`](../packages/session/session-persistence-sqlite) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence) |
|
||||
@@ -1839,6 +1481,7 @@ flowchart TD
|
||||
| [`skill-filesystem`](../packages/skill/skill-filesystem) | `skill` | [`fs`](../packages/fs/fs), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`skill`](../packages/skill/skill) |
|
||||
| [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`web`](../packages/web/web) |
|
||||
| [`hook-protocol`](../packages/hooks/hook-protocol) | `hooks` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`shell`](../packages/shell/shell) |
|
||||
| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) |
|
||||
| [`tmux-context`](../packages/context/tmux-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`shell`](../packages/shell/shell) |
|
||||
@@ -1910,7 +1553,6 @@ flowchart TD
|
||||
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
|
||||
| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`native-command`](../packages/util/native-command), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) |
|
||||
| [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | `compaction` | [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
|
||||
| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`agent`](../packages/core/agent), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
|
||||
| [`tool-bash`](../packages/shell/tool-bash) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
|
||||
@@ -1919,12 +1561,9 @@ flowchart TD
|
||||
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time) |
|
||||
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
|
||||
| [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
|
||||
| [`api-gateway`](../packages/api/gateway) | `api` | [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-registry`](../packages/typert/registry) |
|
||||
| [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
|
||||
| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
|
||||
| [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`host-frontend-static`](../packages/host/frontend-static) | `host` | [`client-connection`](../packages/client/connection), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`webhook-github`](../packages/webhook/webhook-github) | `webhook` | [`credentials`](../packages/credentials/credentials), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`webhook`](../packages/webhook/webhook) |
|
||||
| [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
| [`subagent-claude-code`](../packages/subagent/subagent-claude-code) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
|
||||
@@ -1935,57 +1574,15 @@ flowchart TD
|
||||
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
|
||||
| [`hooks-claude-code`](../packages/hooks/hooks-claude-code) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
|
||||
| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`native-command`](../packages/util/native-command), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`skill`](../packages/skill/skill), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-time`](../packages/util/time), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`api-workspace-controller`](../packages/api/workspace-controller) | `api` | [`api-gateway`](../packages/api/gateway), [`client-connection`](../packages/client/connection), [`host-directory-picker`](../packages/host/directory-picker), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`experimental-agent-team`](../packages/experimental/agent-team) | `experimental` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
|
||||
| [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
|
||||
| [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
|
||||
| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) |
|
||||
| [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team) | `experimental` | [`agent`](../packages/core/agent), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
|
||||
| [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
|
||||
| [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
|
||||
| [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
|
||||
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-modules`](../packages/client/modules), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-locale`](../packages/client/locale), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`token-meter`](../packages/llm/token-meter), [`tool-todo`](../packages/todo/tool-todo), [`util-crypto`](../packages/util/crypto), [`util-workspace-path`](../packages/util/workspace-path), [`workspace`](../packages/workspace/workspace) |
|
||||
| [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | [`api-workspace-controller`](../packages/api/workspace-controller), [`client-locale`](../packages/client/locale), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-workspace`](../packages/client/ui-workspace) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`invariants`](../packages/runtime-diagnostics/invariants), [`schedule`](../packages/schedule/schedule), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-agent-preset`](../packages/client/ui-agent-preset) | `client` | [`agent-presets`](../packages/preset/agent-presets), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-approval`](../packages/client/ui-approval) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-brand-official`](../packages/client/ui-brand-official) | `client` | [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-jobs`](../packages/client/ui-jobs) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-plan`](../packages/client/ui-plan) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`plan-mode`](../packages/plan/plan-mode), [`session`](../packages/core/session) |
|
||||
| [`client-ui-schedule`](../packages/client/ui-schedule) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`schedule`](../packages/schedule/schedule) |
|
||||
| [`client-ui-settings-general`](../packages/client/ui-settings-general) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
|
||||
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`agent`](../packages/core/agent), [`api-session-controller`](../packages/api/session-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
|
||||
| [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol), [`user-questions`](../packages/interaction/user-questions) |
|
||||
| [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`settings`](../packages/settings/settings), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter) |
|
||||
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
|
||||
| [`client-ui-attachment`](../packages/client/ui-attachment) | `client` | [`attachment`](../packages/attachment/attachment), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-trajectory`](../packages/client/ui-trajectory), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
|
||||
| [`client-ui-goal`](../packages/client/ui-goal) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) |
|
||||
| [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`util-workspace-path`](../packages/util/workspace-path) |
|
||||
| [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-store`](../packages/client/store), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`client-ui-skill`](../packages/client/ui-skill) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-tool`](../packages/client/ui-tool), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) |
|
||||
| [`client-ui-cordis`](../packages/extensions/ui-cordis) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`client-ui-tool`](../packages/client/ui-tool), [`cordis-client-runner`](../packages/extensions/cordis-client-runner), [`invariants`](../packages/runtime-diagnostics/invariants) |
|
||||
| [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
"test:web:perf": "npm run build && npm run test:web:perf:built",
|
||||
"test:web:perf:built": "DSH_SNAPSHOT=replay vitest run --config vitest.web.perf.config.ts",
|
||||
"test:web:stress": "npm run build && vitest run --config vitest.web-stress.config.ts",
|
||||
"benchmark:npm-resolution": "tsx scripts/benchmark-npm-resolution.ts",
|
||||
"benchmark:npm-resolution:next": "tsx scripts/benchmark-next-package-dependency.ts",
|
||||
"test:gui": "vitest run packages/client packages/host",
|
||||
"check:all": "tsx scripts/run-gates.ts check-all",
|
||||
"check:ci": "tsx scripts/run-gates.ts ci-primary",
|
||||
@@ -104,6 +106,8 @@
|
||||
"verify-optional-dependency-imports": "tsx scripts/verify-optional-dependency-imports.ts",
|
||||
"verify-runtime-closure": "tsx scripts/verify-runtime-closure.ts",
|
||||
"verify-application-entrypoints": "tsx scripts/verify-application-entrypoints.ts",
|
||||
"verify-package-dependencies": "tsx scripts/verify-package-dependencies.ts",
|
||||
"verify-npm-install-layout": "tsx scripts/verify-npm-install-layout.ts",
|
||||
"verify-client-packages": "tsx scripts/verify-client-packages.ts",
|
||||
"verify-client-ui-i18n": "tsx scripts/verify-client-ui-i18n.ts",
|
||||
"verify-vendored-links": "tsx scripts/verify-vendored-links.ts",
|
||||
|
||||
@@ -57,17 +57,12 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-timeout": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"ws": "^8.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-registry": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
@@ -78,6 +73,7 @@
|
||||
"@deepseek-ai/dsh-util-crypto": "workspace:^",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"zod": "^4.4.3"
|
||||
"zod": "^4.4.3",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,37 +55,17 @@
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-scope": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^"
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-presets": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-gateway": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-settings-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-cordis-host-runner": "workspace:^",
|
||||
"@deepseek-ai/dsh-credentials": "workspace:^",
|
||||
"@deepseek-ai/dsh-file-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-plugin-inventory": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-message-feedback": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-subagent": "workspace:^",
|
||||
"@deepseek-ai/dsh-user-approval": "workspace:^",
|
||||
"@deepseek-ai/dsh-user-questions": "workspace:^"
|
||||
"@deepseek-ai/dsh-scope": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-presets": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-gateway": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-settings-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
@@ -97,11 +77,13 @@
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-message-feedback": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-subagent": "workspace:^",
|
||||
"@deepseek-ai/dsh-user-approval": "workspace:^",
|
||||
"@deepseek-ai/dsh-user-questions": "workspace:^"
|
||||
"@deepseek-ai/dsh-user-questions": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/dsh-scope": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +56,13 @@ Non-negotiables across the layers:
|
||||
|
||||
## Dependency declaration
|
||||
|
||||
Npm sections describe installation and development relationships; each build face independently decides what its artifact contains. [`verify-client-packages`](../../scripts/verify-client-packages.ts) checks the client-specific rules and can repair unambiguous manifest drift with `--fix`.
|
||||
Npm sections describe installation and development relationships; each build face independently decides what its artifact contains. [`verify-package-dependencies`](../../scripts/verify-package-dependencies.ts) checks and repairs these rules; [`verify-client-packages`](../../scripts/verify-client-packages.ts) owns Client loading and module requests.
|
||||
|
||||
1. **Every client package keeps Cordis in matching `peerDependencies` and `devDependencies`.** This includes the static packages because their Node face participates in the same Cordis plugin contract.
|
||||
2. **A dynamic package declares internal dynamic relationships as peer plus dev.** Production source imports, re-exports, module augmentations, and type-only references to an `@deepseek-ai/dsh-*` package count, as does a package named by `dsh.client.inject`. A test-only internal dependency stays dev-only.
|
||||
3. **Static client inputs are dev-only for a dynamic consumer.** A package without `dsh.client`, plus the React modules seeded by the web shell, belongs only in the consumer's `devDependencies`; it never belongs in that dynamic package's `dependencies` or `peerDependencies`. `packages/client/web` likewise keeps Loader, modules, and static UI inputs as development inputs; Cordis remains peer plus dev.
|
||||
4. **Ordinary installed libraries stay in `dependencies`.** This includes private implementation libraries bundled into `lib/client.js` and bare imports left in a statically linked `lib/index.js`; the final Vite host, not the library build, merges and splits the latter. A dynamic package never puts an `@deepseek-ai/dsh-*` package in `dependencies`.
|
||||
5. **Every peer has a matching development range.** npm dependency and peer cycles are allowed; only the synchronous module-request graph has the separate acyclicity rule below.
|
||||
2. **A package under `packages/client/` is always covered; `dsh.client` marks a Client/Host package outside that directory.** Explicit include/exclude entries handle exceptions. Every covered package's Host entry is scanned, while a `./client` export alone does not select dependency policy.
|
||||
3. **Browser and type relationships are development-only.** Client imports, type-only imports, module augmentations, TypeScript project references, `dsh.client.inject`, invariant companions, and metadata-only peers belong only in `devDependencies`. Configuration-only entries that Knip cannot infer from imports are listed in the dependency policy and projected into `knip.json` by `--fix`.
|
||||
4. **Host value imports require classified exports.** A workspace value reached from the package's Host entry belongs only in `dependencies` when its exact module specifier and runtime export appear in `safeHostDependencyExports`. Exports whose identity or module state must be shared appear in `peerRequiredHostExports` and keep the whole package edge in matching `peerDependencies` and `devDependencies`. The verifier rejects unclassified exports before `--fix` writes manifests.
|
||||
5. **Ordinary installed libraries stay in `dependencies`.** This includes private implementation libraries bundled into `lib/client.js` and bare imports left in a statically linked `lib/index.js`; the final Vite host, not the library build, merges and splits the latter.
|
||||
6. **Browser and Node build faces declare externality independently.** A dynamic browser half uses the baseline plus `dsh.client.external`; a statically linked face externalizes every bare specifier; a Node face externalizes its production dependencies ([`tsdown.client.ts`](tsdown.client.ts)). Moving a name between npm sections must not silently change bundle contents.
|
||||
7. **Keep the published payload closed.** Every relative runtime import and emitted asset must be covered by `files`; the repository publint pass checks the exact publication view.
|
||||
|
||||
@@ -140,7 +140,7 @@ Bringing up a new `packages/client/<name>` plugin package (ui-workspace is a com
|
||||
3. **dsh.client manifest semantics**: `platform: 'web'` always, and the declaration requires a `./client` export (the scan throws without one); `immediately: true` only for stage-one-prefetch infrastructure rows. `inject` lists package-name dependency edges — they are **informational only** (preflight display, HMR diffing); they do not sequence entry activation or apply order. Activation order is Cordis fiber inject waiting on *services*, nothing else. A non-baseline `external` request sequences its dynamic supplier ahead of the consumer — see [shared modules](#shared-modules-and-the-module-graph).
|
||||
4. **Registering into another package's slot**: apply order is unconstrained, and a business service is not a declaration barrier. Use `ctx.slots.inject(name, () => ctx.slots.register(...))`; it waits on the actual declaration, removes the contribution when that declaration collapses, reruns after redeclaration, and leaves with the caller's plugin fiber. Return a generator yielding each registration when several contributions must install and roll back atomically. A bare `slots.register` into an undeclared slot remains an error; keep service edges only for services the contribution actually reads.
|
||||
5. Rebuild the bundle (`pnpm --filter <pkg> bundle`) before probing a live `dsh web` server — the registry serves `lib/client.js`, not sources.
|
||||
6. **Declaration decisions**, each settled by [dependency declaration](#dependency-declaration) and [shared modules](#shared-modules-and-the-module-graph): does the package ship a `./client` export; which non-baseline value imports require `dsh.client.external`; which dynamic value dependencies are peer plus dev; which static compile inputs are dev-only; and whether `files` covers every relative runtime import and emitted asset.
|
||||
6. **Declaration decisions**, each settled by [dependency declaration](#dependency-declaration) and [shared modules](#shared-modules-and-the-module-graph): does the package ship a `./client` export; which non-baseline value imports require `dsh.client.external`; which Host value imports are ordinary dependencies; which Browser and type inputs are dev-only; and whether `files` covers every relative runtime import and emitted asset.
|
||||
|
||||
## New component checklist
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"zod": "^4.4.3"
|
||||
"zod": "^4.4.3",
|
||||
"@deepseek-ai/dsh-credentials": "workspace:^"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
@@ -48,24 +49,12 @@
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-credentials": "workspace:^",
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-directory-picker": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-todo": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-credentials": "workspace:^",
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-directory-picker": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
|
||||
@@ -41,10 +41,6 @@
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-modules": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -43,13 +43,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
@@ -63,11 +57,11 @@
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@types/react": "~18.3.1",
|
||||
"react": "^18.2.0",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
|
||||
@@ -54,9 +54,6 @@
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
"zustand": "~4.4.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -50,19 +50,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-presets": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-workspace": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -48,17 +48,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -70,12 +70,6 @@
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-chat": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-trajectory": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-sidebar": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -51,31 +51,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-approval": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-layout": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-workspace": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-compaction": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm-retry": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-stats": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-workspace-path": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
@@ -102,7 +78,6 @@
|
||||
"@deepseek-ai/dsh-llm-retry": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-stats": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-workspace-path": "workspace:^",
|
||||
@@ -112,7 +87,8 @@
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
|
||||
@@ -49,17 +49,7 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -55,35 +55,11 @@
|
||||
"@lexical/plain-text": "^0.49.0",
|
||||
"@lexical/text": "^0.49.0",
|
||||
"@lexical/utils": "^0.49.0",
|
||||
"lexical": "^0.49.0"
|
||||
"lexical": "^0.49.0",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-layout": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-workspace": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm-retry": "workspace:^",
|
||||
"@deepseek-ai/dsh-permission-presets": "workspace:^",
|
||||
"@deepseek-ai/dsh-plan-mode": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-todo": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-crypto": "workspace:^",
|
||||
"@deepseek-ai/dsh-workspace": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-workspace-path": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
@@ -110,7 +86,6 @@
|
||||
"@deepseek-ai/dsh-permission-presets": "workspace:^",
|
||||
"@deepseek-ai/dsh-plan-mode": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-todo": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-crypto": "workspace:^",
|
||||
|
||||
@@ -48,16 +48,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-chat": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
@@ -70,7 +61,6 @@
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-slots": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
||||
"@types/react": "~18.3.1",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"react": "^18.2.0",
|
||||
@@ -82,5 +72,8 @@
|
||||
"lib/invariant.js",
|
||||
"lib/client.js",
|
||||
"lib/types/**/*.d.ts"
|
||||
]
|
||||
],
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,11 +49,6 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-workspace": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -44,9 +44,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-workspace": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -49,19 +49,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-chat": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -49,15 +49,7 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-file-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
|
||||
@@ -45,13 +45,7 @@
|
||||
"access": "public"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
|
||||
@@ -46,11 +46,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-theme": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -46,18 +46,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-message-feedback": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-chat": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -46,18 +46,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -47,17 +47,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-permission-presets": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -45,15 +45,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-plan-mode": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,16 +47,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-file-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-workspace-path": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
"use-sync-external-store": "1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -45,13 +45,6 @@
|
||||
"access": "public"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-schedule": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -44,11 +44,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -48,19 +48,11 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"clsx": "^2.0.0"
|
||||
"clsx": "^2.0.0",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-sidebar": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
@@ -76,7 +68,6 @@
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@types/react": "~18.3.1",
|
||||
"react": "^18.2.0",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
},
|
||||
|
||||
@@ -45,12 +45,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -45,12 +45,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -45,12 +45,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -42,14 +42,8 @@
|
||||
"watch": "tsdown --watch"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
@@ -60,7 +54,8 @@
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@types/react": "~18.3.1",
|
||||
"react": "^18.2.0"
|
||||
"react": "^18.2.0",
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
|
||||
@@ -51,14 +51,7 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-workspace": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-layout": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
|
||||
@@ -48,15 +48,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-tool": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,18 +47,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-subagent": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
|
||||
@@ -44,15 +44,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
@@ -67,7 +59,6 @@
|
||||
"@deepseek-ai/dsh-client-ui-slots": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^",
|
||||
"@types/react": "~18.3.1",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
@@ -84,6 +75,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"clsx": "^2.0.0",
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"@deepseek-ai/dsh-settings": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,17 +49,7 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-chat": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-workspace-path": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -51,19 +51,7 @@
|
||||
"diff": "^9.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-compaction": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
|
||||
@@ -51,17 +51,7 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/dsh-user-questions": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
|
||||
@@ -54,16 +54,6 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-chat": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-workflow": "workspace:^",
|
||||
"@deepseek-ai/dsh-workflow": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -54,21 +54,7 @@
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-session-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-workspace-controller": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-sidebar": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-schedule": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-util-workspace-path": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -45,20 +45,18 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-scope": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-scope": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-registry": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-llm": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +46,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-modules": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-theme": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -51,16 +51,6 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-cordis-client-runner": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-sidebar": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-tool": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -57,23 +57,19 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-timeout": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-util-crypto": "workspace:^",
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"zod": "^4.4.3"
|
||||
"zod": "^4.4.3",
|
||||
"@deepseek-ai/dsh-timeout": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-brand": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-timeout": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
"name": "@deepseek-ai/dsh-session-log-export",
|
||||
"description": "Web Session-log export command and shared download dialog",
|
||||
"version": "0.1.2-alpha.1",
|
||||
"publishConfig": { "access": "public" },
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
||||
@@ -12,33 +14,39 @@
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"exports": {
|
||||
".": { "types": "./lib/types/index.d.ts", "default": "./lib/index.js" },
|
||||
"./invariant": { "types": "./lib/types/invariant.d.ts", "default": "./lib/invariant.js" },
|
||||
"./client": { "types": "./lib/types/client/index.d.ts", "default": "./lib/client.js" },
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./lib/types/client/index.d.ts",
|
||||
"default": "./lib/client.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": ["lib/index.js", "lib/invariant.js", "lib/client.js", "lib/types/**/*.d.ts"],
|
||||
"scripts": { "bundle": "tsdown", "watch": "tsdown --watch" },
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/client.js",
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"bundle": "tsdown",
|
||||
"watch": "tsdown --watch"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"fflate": "^0.8.2"
|
||||
"fflate": "^0.8.2",
|
||||
"@deepseek-ai/dsh-session": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-attachment": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-conversation": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-renderer": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-persistence": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-query": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
@@ -56,7 +64,6 @@
|
||||
"@deepseek-ai/dsh-client-ui-slots": "workspace:^",
|
||||
"@deepseek-ai/dsh-commands": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-persistence": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-query": "workspace:^",
|
||||
"@types/react": "~18.3.1",
|
||||
|
||||
@@ -53,15 +53,14 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-protocol": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+53
-49
@@ -627,9 +627,6 @@ importers:
|
||||
'@deepseek-ai/dsh-timeout':
|
||||
specifier: workspace:^
|
||||
version: link:../../util/timeout
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
specifier: workspace:^
|
||||
version: link:../../typert/protocol
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -652,6 +649,9 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
specifier: workspace:^
|
||||
version: link:../../typert/protocol
|
||||
'@deepseek-ai/dsh-typert-registry':
|
||||
specifier: workspace:^
|
||||
version: link:../../typert/registry
|
||||
@@ -667,12 +667,12 @@ importers:
|
||||
|
||||
packages/api/remotes:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-scope':
|
||||
'@deepseek-ai/dsh-api-session-controller':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/scope
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
version: link:../session-controller
|
||||
'@deepseek-ai/dsh-session':
|
||||
specifier: workspace:^
|
||||
version: link:../../typert/protocol
|
||||
version: link:../../core/session
|
||||
devDependencies:
|
||||
'@deepseek-ai/cordis':
|
||||
specifier: workspace:^
|
||||
@@ -683,15 +683,15 @@ importers:
|
||||
'@deepseek-ai/dsh-api-gateway':
|
||||
specifier: workspace:^
|
||||
version: link:../gateway
|
||||
'@deepseek-ai/dsh-api-session-controller':
|
||||
specifier: workspace:^
|
||||
version: link:../session-controller
|
||||
'@deepseek-ai/dsh-api-settings-controller':
|
||||
specifier: workspace:^
|
||||
version: link:../settings-controller
|
||||
'@deepseek-ai/dsh-api-workspace-controller':
|
||||
specifier: workspace:^
|
||||
version: link:../workspace-controller
|
||||
'@deepseek-ai/dsh-client-connection':
|
||||
specifier: workspace:^
|
||||
version: link:../../client/connection
|
||||
'@deepseek-ai/dsh-commands':
|
||||
specifier: workspace:^
|
||||
version: link:../../interaction/commands
|
||||
@@ -719,9 +719,9 @@ importers:
|
||||
'@deepseek-ai/dsh-message-feedback':
|
||||
specifier: workspace:^
|
||||
version: link:../../feedback/message-feedback
|
||||
'@deepseek-ai/dsh-session':
|
||||
'@deepseek-ai/dsh-scope':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/session
|
||||
version: link:../../core/scope
|
||||
'@deepseek-ai/dsh-session-reference':
|
||||
specifier: workspace:^
|
||||
version: link:../../context/session-reference
|
||||
@@ -731,6 +731,9 @@ importers:
|
||||
'@deepseek-ai/dsh-subagent':
|
||||
specifier: workspace:^
|
||||
version: link:../../subagent/subagent
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
specifier: workspace:^
|
||||
version: link:../../typert/protocol
|
||||
'@deepseek-ai/dsh-user-approval':
|
||||
specifier: workspace:^
|
||||
version: link:../../interaction/user-approval
|
||||
@@ -1663,6 +1666,9 @@ importers:
|
||||
|
||||
packages/client/connection:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-credentials':
|
||||
specifier: workspace:^
|
||||
version: link:../../credentials/credentials
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -1682,9 +1688,6 @@ importers:
|
||||
'@deepseek-ai/dsh-commands':
|
||||
specifier: workspace:^
|
||||
version: link:../../interaction/commands
|
||||
'@deepseek-ai/dsh-credentials':
|
||||
specifier: workspace:^
|
||||
version: link:../../credentials/credentials
|
||||
'@deepseek-ai/dsh-host-directory-picker':
|
||||
specifier: workspace:^
|
||||
version: link:../../host/directory-picker
|
||||
@@ -1731,6 +1734,9 @@ importers:
|
||||
|
||||
packages/client/locale:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -1765,9 +1771,6 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@types/react':
|
||||
specifier: ~18.3.1
|
||||
version: 18.3.31
|
||||
@@ -1992,6 +1995,9 @@ importers:
|
||||
|
||||
packages/client/ui-chat:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -2068,9 +2074,6 @@ importers:
|
||||
'@deepseek-ai/dsh-session-stats':
|
||||
specifier: workspace:^
|
||||
version: link:../../session/session-stats
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/dsh-token-meter':
|
||||
specifier: workspace:^
|
||||
version: link:../../llm/token-meter
|
||||
@@ -2156,6 +2159,9 @@ importers:
|
||||
|
||||
packages/client/ui-conversation:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -2250,9 +2256,6 @@ importers:
|
||||
'@deepseek-ai/dsh-session':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/session
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/dsh-token-meter':
|
||||
specifier: workspace:^
|
||||
version: link:../../llm/token-meter
|
||||
@@ -2288,6 +2291,10 @@ importers:
|
||||
version: 4.4.3
|
||||
|
||||
packages/client/ui-deliverables:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-system-prompt':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/system-prompt
|
||||
devDependencies:
|
||||
'@deepseek-ai/cordis':
|
||||
specifier: workspace:^
|
||||
@@ -2328,9 +2335,6 @@ importers:
|
||||
'@deepseek-ai/dsh-session':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/session
|
||||
'@deepseek-ai/dsh-system-prompt':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/system-prompt
|
||||
'@types/react':
|
||||
specifier: ~18.3.1
|
||||
version: 18.3.31
|
||||
@@ -3058,10 +3062,6 @@ importers:
|
||||
version: 18.3.1
|
||||
|
||||
packages/client/ui-settings:
|
||||
dependencies:
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
devDependencies:
|
||||
'@deepseek-ai/cordis':
|
||||
specifier: workspace:^
|
||||
@@ -3084,6 +3084,9 @@ importers:
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
'@types/react':
|
||||
specifier: ~18.3.1
|
||||
version: 18.3.31
|
||||
@@ -3093,6 +3096,9 @@ importers:
|
||||
|
||||
packages/client/ui-settings-general:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -3139,9 +3145,6 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@types/react':
|
||||
specifier: ~18.3.1
|
||||
version: 18.3.31
|
||||
@@ -3450,6 +3453,9 @@ importers:
|
||||
|
||||
packages/client/ui-theme:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -3493,9 +3499,6 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-settings':
|
||||
specifier: workspace:^
|
||||
version: link:../../settings/settings
|
||||
'@types/react':
|
||||
specifier: ~18.3.1
|
||||
version: 18.3.31
|
||||
@@ -4422,6 +4425,10 @@ importers:
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
|
||||
packages/core/session:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-llm':
|
||||
specifier: workspace:^
|
||||
version: link:../../llm/llm
|
||||
devDependencies:
|
||||
'@deepseek-ai/cordis':
|
||||
specifier: workspace:^
|
||||
@@ -4432,9 +4439,6 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-llm':
|
||||
specifier: workspace:^
|
||||
version: link:../../llm/llm
|
||||
'@deepseek-ai/dsh-scope':
|
||||
specifier: workspace:^
|
||||
version: link:../scope
|
||||
@@ -6369,6 +6373,9 @@ importers:
|
||||
|
||||
packages/llm/llm:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-timeout':
|
||||
specifier: workspace:^
|
||||
version: link:../../util/timeout
|
||||
'@deepseek-ai/dsh-util-crypto':
|
||||
specifier: workspace:^
|
||||
version: link:../../util/crypto
|
||||
@@ -6391,9 +6398,6 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-timeout':
|
||||
specifier: workspace:^
|
||||
version: link:../../util/timeout
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
specifier: workspace:^
|
||||
version: link:../../typert/protocol
|
||||
@@ -7162,6 +7166,9 @@ importers:
|
||||
|
||||
packages/session-query/session-log-export:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-session':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/session
|
||||
'@deepseek-ai/schemastery':
|
||||
specifier: link:../../../vendor/schemastery
|
||||
version: link:../../../vendor/schemastery
|
||||
@@ -7214,9 +7221,6 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-session':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/session
|
||||
'@deepseek-ai/dsh-session-persistence':
|
||||
specifier: workspace:^
|
||||
version: link:../../session/session-persistence
|
||||
@@ -9645,9 +9649,6 @@ importers:
|
||||
|
||||
packages/typert/registry:
|
||||
dependencies:
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
specifier: workspace:^
|
||||
version: link:../protocol
|
||||
zod:
|
||||
specifier: ^4.4.3
|
||||
version: 4.4.3
|
||||
@@ -9658,6 +9659,9 @@ importers:
|
||||
'@deepseek-ai/dsh-invariants':
|
||||
specifier: workspace:^
|
||||
version: link:../../runtime-diagnostics/invariants
|
||||
'@deepseek-ai/dsh-typert-protocol':
|
||||
specifier: workspace:^
|
||||
version: link:../protocol
|
||||
|
||||
packages/util/atomic-write:
|
||||
devDependencies:
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
applyFactsToRegistry,
|
||||
discoverBenchmarkCandidates,
|
||||
parseNextPackageBenchmarkOptions,
|
||||
type MutableRegistryManifest,
|
||||
} from './benchmark-next-package-dependency.ts'
|
||||
import type {
|
||||
PackageDependencyFacts,
|
||||
PackageDependencyManifest,
|
||||
WorkspacePackageManifest,
|
||||
} from './verify-package-dependencies.ts'
|
||||
import type { RegistryIndex } from './benchmark-npm-resolution.ts'
|
||||
|
||||
describe('next package benchmark options', () => {
|
||||
it('parses candidate and repetition controls', () => {
|
||||
expect(parseNextPackageBenchmarkOptions([
|
||||
'--',
|
||||
'--candidates=@f/a,@f/b',
|
||||
'--runs=2',
|
||||
'--finalist-runs=4',
|
||||
'--finalists=3',
|
||||
'--jobs=6',
|
||||
'--timeout-ms=9000',
|
||||
])).toEqual({
|
||||
candidates: ['@f/a', '@f/b'],
|
||||
coarseRuns: 2,
|
||||
finalistRuns: 4,
|
||||
finalists: 3,
|
||||
jobs: 6,
|
||||
timeoutMs: 9000,
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects invalid positive integers', () => {
|
||||
expect(() => parseNextPackageBenchmarkOptions(['--jobs=0'])).toThrow('--jobs must be a positive integer')
|
||||
})
|
||||
})
|
||||
|
||||
describe('next package benchmark graph', () => {
|
||||
it('applies a source-derived candidate without changing the filesystem', () => {
|
||||
const manifest: PackageDependencyManifest & { version: string } = {
|
||||
name: '@f/probe',
|
||||
version: '1.0.0',
|
||||
peerDependencies: {
|
||||
'@deepseek-ai/cordis': 'workspace:^',
|
||||
'@f/runtime': 'workspace:^',
|
||||
'@f/types': 'workspace:^',
|
||||
},
|
||||
devDependencies: {
|
||||
'@deepseek-ai/cordis': 'workspace:^',
|
||||
'@f/runtime': 'workspace:^',
|
||||
'@f/types': 'workspace:^',
|
||||
},
|
||||
}
|
||||
const facts: PackageDependencyFacts = {
|
||||
manifestPath: 'packages/g/probe/package.json',
|
||||
role: 'configured-host',
|
||||
manifest,
|
||||
workspaceNames: new Set(['@deepseek-ai/cordis', '@f/probe', '@f/runtime', '@f/types']),
|
||||
allSourceUses: new Map([
|
||||
['@f/runtime', ['packages/g/probe/src/index.ts']],
|
||||
['@f/types', ['packages/g/probe/src/types.ts']],
|
||||
]),
|
||||
hostRuntimeSourceUses: new Map([['@f/runtime', ['packages/g/probe/src/index.ts']]]),
|
||||
hostRuntimeExportUses: [{
|
||||
packageName: '@f/runtime',
|
||||
specifier: '@f/runtime',
|
||||
exportName: 'runtimeValue',
|
||||
sourcePath: 'packages/g/probe/src/index.ts',
|
||||
line: 1,
|
||||
column: 10,
|
||||
sourceLine: "import { runtimeValue } from '@f/runtime'",
|
||||
}],
|
||||
peerRequiredHostDependencies: new Set(),
|
||||
configurationOnlyDevDependencies: new Set(),
|
||||
clientInject: new Set(),
|
||||
}
|
||||
const index = new Map<string, Map<string, MutableRegistryManifest>>([
|
||||
['@f/probe', new Map([['1.0.0', structuredClone(manifest) as MutableRegistryManifest]])],
|
||||
])
|
||||
applyFactsToRegistry(index, facts, new Map([
|
||||
['@deepseek-ai/cordis', '4.0.1'],
|
||||
['@f/probe', '1.0.0'],
|
||||
['@f/runtime', '2.0.0'],
|
||||
['@f/types', '3.0.0'],
|
||||
]))
|
||||
|
||||
expect(index.get('@f/probe')?.get('1.0.0')).toMatchObject({
|
||||
dependencies: { '@f/runtime': '^2.0.0' },
|
||||
peerDependencies: { '@deepseek-ai/cordis': '^4.0.1' },
|
||||
})
|
||||
expect(index.get('@f/probe')?.get('1.0.0')?.dependencies).not.toHaveProperty('@f/types')
|
||||
})
|
||||
|
||||
it('finds reachable unconfigured packages with non-Cordis peers', () => {
|
||||
const index = new Map([
|
||||
['@deepseek-ai/dsh', new Map([['1.0.0', {
|
||||
name: '@deepseek-ai/dsh', version: '1.0.0', dependencies: { '@f/a': '^1.0.0', '@f/b': '^1.0.0' },
|
||||
}]])],
|
||||
['@f/a', new Map([['1.0.0', {
|
||||
name: '@f/a', version: '1.0.0', peerDependencies: { '@f/runtime': '^1.0.0' },
|
||||
}]])],
|
||||
['@f/b', new Map([['1.0.0', {
|
||||
name: '@f/b', version: '1.0.0', peerDependencies: { '@deepseek-ai/cordis': '^4.0.0' },
|
||||
}]])],
|
||||
['@f/runtime', new Map([['1.0.0', { name: '@f/runtime', version: '1.0.0' }]])],
|
||||
]) as RegistryIndex
|
||||
const release = new Map<string, WorkspacePackageManifest>([
|
||||
['@f/a', {
|
||||
name: '@f/a', dir: 'packages/g/a', manifestPath: 'packages/g/a/package.json', manifest: { name: '@f/a' },
|
||||
}],
|
||||
['@f/b', {
|
||||
name: '@f/b', dir: 'packages/g/b', manifestPath: 'packages/g/b/package.json', manifest: { name: '@f/b' },
|
||||
}],
|
||||
])
|
||||
|
||||
expect(discoverBenchmarkCandidates(
|
||||
index,
|
||||
new Map([['@deepseek-ai/dsh', '1.0.0'], ['@f/a', '1.0.0'], ['@f/b', '1.0.0']]),
|
||||
release,
|
||||
new Set(),
|
||||
)).toEqual(['@f/a'])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,271 @@
|
||||
/** Benchmark which additional Host package most reduces npm peer resolution. */
|
||||
|
||||
import { availableParallelism } from 'node:os'
|
||||
import { resolve } from 'node:path'
|
||||
import { parseArgs } from 'node:util'
|
||||
import {
|
||||
benchmarkNpmResolution,
|
||||
buildRegistryIndex,
|
||||
parsePositiveIntegerOption,
|
||||
publishWorkspaceRange,
|
||||
type RegistryIndex,
|
||||
} from './benchmark-npm-resolution.ts'
|
||||
import {
|
||||
readPackageDependencyFacts,
|
||||
readPackageDependencyState,
|
||||
readWorkspacePackageManifests,
|
||||
repairPackageDependencyManifest,
|
||||
type PackageDependencyFacts,
|
||||
type WorkspacePackageManifest,
|
||||
} from './verify-package-dependencies.ts'
|
||||
|
||||
const TARGET_PACKAGE = '@deepseek-ai/dsh'
|
||||
const CORDIS = '@deepseek-ai/cordis'
|
||||
|
||||
interface Options {
|
||||
readonly candidates?: readonly string[]
|
||||
readonly coarseRuns: number
|
||||
readonly finalistRuns: number
|
||||
readonly finalists: number
|
||||
readonly jobs: number
|
||||
readonly timeoutMs: number
|
||||
}
|
||||
|
||||
export interface MutableRegistryManifest {
|
||||
name: string
|
||||
version: string
|
||||
dependencies?: Record<string, string>
|
||||
optionalDependencies?: Record<string, string>
|
||||
peerDependencies?: Record<string, string>
|
||||
peerDependenciesMeta?: Record<string, { optional?: boolean }>
|
||||
}
|
||||
|
||||
interface Measurement {
|
||||
readonly package: string
|
||||
readonly seconds: readonly number[]
|
||||
readonly medianSeconds: number
|
||||
}
|
||||
|
||||
/** Parse benchmark selection and repetition options. */
|
||||
export function parseNextPackageBenchmarkOptions(args: readonly string[]): Options {
|
||||
const normalized = args[0] === '--' ? args.slice(1) : args
|
||||
const { values } = parseArgs({
|
||||
args: [...normalized],
|
||||
options: {
|
||||
candidates: { type: 'string' },
|
||||
runs: { type: 'string' },
|
||||
'finalist-runs': { type: 'string' },
|
||||
finalists: { type: 'string' },
|
||||
jobs: { type: 'string' },
|
||||
'timeout-ms': { type: 'string' },
|
||||
},
|
||||
allowPositionals: false,
|
||||
})
|
||||
return {
|
||||
...(values.candidates === undefined
|
||||
? {}
|
||||
: { candidates: values.candidates.split(',').filter(Boolean) }),
|
||||
coarseRuns: parsePositiveIntegerOption(values.runs, 1, '--runs'),
|
||||
finalistRuns: parsePositiveIntegerOption(values['finalist-runs'], 3, '--finalist-runs'),
|
||||
finalists: parsePositiveIntegerOption(values.finalists, 5, '--finalists'),
|
||||
jobs: parsePositiveIntegerOption(values.jobs, Math.min(8, availableParallelism()), '--jobs'),
|
||||
timeoutMs: parsePositiveIntegerOption(values['timeout-ms'], 120_000, '--timeout-ms'),
|
||||
}
|
||||
}
|
||||
|
||||
function median(values: readonly number[]): number {
|
||||
const sorted = [...values].sort((left, right) => left - right)
|
||||
const middle = Math.floor(sorted.length / 2)
|
||||
return sorted.length % 2 === 0
|
||||
? ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2
|
||||
: sorted[middle] ?? 0
|
||||
}
|
||||
|
||||
function cloneIndex(index: RegistryIndex): Map<string, Map<string, MutableRegistryManifest>> {
|
||||
return new Map([...index].map(([name, versions]) => [
|
||||
name,
|
||||
new Map([...versions].map(([version, manifest]) => [
|
||||
version,
|
||||
structuredClone(manifest) as MutableRegistryManifest,
|
||||
])),
|
||||
]))
|
||||
}
|
||||
|
||||
function publishedSection(
|
||||
values: Readonly<Record<string, string>> | undefined,
|
||||
workspaceVersions: ReadonlyMap<string, string>,
|
||||
): Record<string, string> | undefined {
|
||||
if (values === undefined) return undefined
|
||||
return Object.fromEntries(Object.entries(values).map(([name, range]) => {
|
||||
const version = workspaceVersions.get(name)
|
||||
return [name, version === undefined ? range : publishWorkspaceRange(range, version)]
|
||||
}))
|
||||
}
|
||||
|
||||
/** Apply one source-derived policy result to an in-memory registry manifest. */
|
||||
export function applyFactsToRegistry(
|
||||
index: Map<string, Map<string, MutableRegistryManifest>>,
|
||||
facts: PackageDependencyFacts,
|
||||
workspaceVersions: ReadonlyMap<string, string>,
|
||||
): void {
|
||||
const source = structuredClone(facts.manifest)
|
||||
repairPackageDependencyManifest({ ...facts, manifest: source })
|
||||
const version = workspaceVersions.get(source.name ?? '')
|
||||
const target = version === undefined ? undefined : index.get(source.name ?? '')?.get(version)
|
||||
if (target === undefined) throw new Error(`local registry has no ${source.name ?? 'unnamed package'}@${version ?? 'unknown'}`)
|
||||
for (const field of ['dependencies', 'optionalDependencies', 'peerDependencies'] as const) {
|
||||
const values = publishedSection(source[field], workspaceVersions)
|
||||
if (values !== undefined) target[field] = values
|
||||
else if (field === 'dependencies') delete target.dependencies
|
||||
else if (field === 'optionalDependencies') delete target.optionalDependencies
|
||||
else delete target.peerDependencies
|
||||
}
|
||||
if (source.peerDependenciesMeta === undefined) delete target.peerDependenciesMeta
|
||||
else target.peerDependenciesMeta = structuredClone(source.peerDependenciesMeta) as Record<string, { optional?: boolean }>
|
||||
}
|
||||
|
||||
function currentVersion(pkg: WorkspacePackageManifest): string {
|
||||
const version = pkg.manifest.version
|
||||
if (typeof version !== 'string') throw new Error(`${pkg.manifestPath}: missing package version`)
|
||||
return version
|
||||
}
|
||||
|
||||
/** Find reachable Host candidates whose published manifests still carry non-Cordis peers. */
|
||||
export function discoverBenchmarkCandidates(
|
||||
index: RegistryIndex,
|
||||
workspaceVersions: ReadonlyMap<string, string>,
|
||||
releasePackages: ReadonlyMap<string, WorkspacePackageManifest>,
|
||||
policyPackages: ReadonlySet<string>,
|
||||
): string[] {
|
||||
const reached = new Set<string>()
|
||||
const queue = [TARGET_PACKAGE]
|
||||
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
||||
const name = queue[cursor]
|
||||
if (name === undefined || reached.has(name)) continue
|
||||
const version = workspaceVersions.get(name)
|
||||
const manifest = version === undefined ? undefined : index.get(name)?.get(version)
|
||||
if (manifest === undefined) continue
|
||||
reached.add(name)
|
||||
const installed = {
|
||||
...manifest.dependencies,
|
||||
...manifest.optionalDependencies,
|
||||
...Object.fromEntries(Object.entries(manifest.peerDependencies ?? {})
|
||||
.filter(([peer]) => (manifest.peerDependenciesMeta?.[peer] as { optional?: boolean } | undefined)?.optional !== true)),
|
||||
}
|
||||
for (const dependency of Object.keys(installed).sort()) {
|
||||
if (!reached.has(dependency)) queue.push(dependency)
|
||||
}
|
||||
}
|
||||
return [...reached].filter((name) => {
|
||||
if (policyPackages.has(name) || !releasePackages.has(name)) return false
|
||||
const version = workspaceVersions.get(name)
|
||||
const manifest = version === undefined ? undefined : index.get(name)?.get(version)
|
||||
return Object.keys(manifest?.peerDependencies ?? {}).some(peer => peer !== CORDIS)
|
||||
}).sort()
|
||||
}
|
||||
|
||||
async function measure(
|
||||
index: RegistryIndex,
|
||||
targetVersion: string,
|
||||
runs: number,
|
||||
timeoutMs: number,
|
||||
): Promise<number[]> {
|
||||
const seconds: number[] = []
|
||||
for (let run = 0; run < runs; run += 1) {
|
||||
const result = await benchmarkNpmResolution(index, targetVersion, timeoutMs)
|
||||
if (result.archiveRequests > 0) throw new Error('metadata-only benchmark requested package archives')
|
||||
seconds.push(Number((result.durationMs / 1000).toFixed(2)))
|
||||
}
|
||||
return seconds
|
||||
}
|
||||
|
||||
async function mapConcurrent<T, R>(
|
||||
values: readonly T[],
|
||||
jobs: number,
|
||||
operation: (value: T) => Promise<R>,
|
||||
): Promise<R[]> {
|
||||
const results: R[] = []
|
||||
let next = 0
|
||||
await Promise.all(Array.from({ length: Math.min(jobs, values.length) }, async () => {
|
||||
while (next < values.length) {
|
||||
const index = next
|
||||
next += 1
|
||||
const value = values[index]
|
||||
if (value === undefined) return
|
||||
results[index] = await operation(value)
|
||||
}
|
||||
}))
|
||||
return results
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const options = parseNextPackageBenchmarkOptions(process.argv.slice(2))
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const packages = readWorkspacePackageManifests(root)
|
||||
const workspaceVersions = new Map(packages.all.map(pkg => [pkg.name, currentVersion(pkg)]))
|
||||
const releaseByName = new Map(packages.release.map(pkg => [pkg.name, pkg]))
|
||||
const state = readPackageDependencyState(root)
|
||||
if (state.policyViolations.length > 0) throw new Error(state.policyViolations.join('\n'))
|
||||
const base = cloneIndex(buildRegistryIndex(root))
|
||||
for (const facts of state.facts) applyFactsToRegistry(base, facts, workspaceVersions)
|
||||
const targetVersion = workspaceVersions.get(TARGET_PACKAGE)
|
||||
if (targetVersion === undefined) throw new Error(`workspace has no ${TARGET_PACKAGE}`)
|
||||
const policyNames = new Set(state.facts.map(facts => facts.manifest.name).filter(name => name !== undefined))
|
||||
const discovered = discoverBenchmarkCandidates(base, workspaceVersions, releaseByName, policyNames)
|
||||
const candidates = options.candidates ?? discovered
|
||||
for (const name of candidates) {
|
||||
if (!discovered.includes(name)) throw new Error(`${name} is not a reachable unconfigured Host candidate`)
|
||||
}
|
||||
const candidateFacts = new Map(candidates.map((name) => {
|
||||
const pkg = releaseByName.get(name)
|
||||
if (pkg === undefined) throw new Error(`release set has no ${name}`)
|
||||
return [name, readPackageDependencyFacts(root, pkg, 'configured-host', state.workspaceNames)]
|
||||
}))
|
||||
|
||||
const baselineSeconds = await measure(base, targetVersion, options.finalistRuns, options.timeoutMs)
|
||||
const baseline = median(baselineSeconds)
|
||||
console.log(JSON.stringify({ type: 'baseline', seconds: baselineSeconds, medianSeconds: baseline }))
|
||||
|
||||
const coarse = await mapConcurrent(candidates, options.jobs, async (name): Promise<Measurement> => {
|
||||
const index = cloneIndex(base)
|
||||
const facts = candidateFacts.get(name)
|
||||
if (facts === undefined) throw new Error(`missing source facts for ${name}`)
|
||||
applyFactsToRegistry(index, facts, workspaceVersions)
|
||||
const seconds = await measure(index, targetVersion, options.coarseRuns, options.timeoutMs)
|
||||
const result = { package: name, seconds, medianSeconds: median(seconds) }
|
||||
console.log(JSON.stringify({ type: 'coarse', ...result }))
|
||||
return result
|
||||
})
|
||||
const finalists = coarse.sort((left, right) => left.medianSeconds - right.medianSeconds)
|
||||
.slice(0, options.finalists)
|
||||
const measured: Measurement[] = []
|
||||
for (const finalist of finalists) {
|
||||
const index = cloneIndex(base)
|
||||
const facts = candidateFacts.get(finalist.package)
|
||||
if (facts === undefined) throw new Error(`missing source facts for ${finalist.package}`)
|
||||
applyFactsToRegistry(index, facts, workspaceVersions)
|
||||
const seconds = await measure(index, targetVersion, options.finalistRuns, options.timeoutMs)
|
||||
measured.push({ package: finalist.package, seconds, medianSeconds: median(seconds) })
|
||||
}
|
||||
const ranking = measured.sort((left, right) => left.medianSeconds - right.medianSeconds)
|
||||
.map(result => ({
|
||||
...result,
|
||||
gainSeconds: Number((baseline - result.medianSeconds).toFixed(2)),
|
||||
}))
|
||||
console.log(JSON.stringify({
|
||||
type: 'result',
|
||||
baselineSeconds,
|
||||
baselineMedianSeconds: baseline,
|
||||
candidateCount: candidates.length,
|
||||
ranking,
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
try {
|
||||
await main()
|
||||
} catch (error) {
|
||||
console.error(`benchmark-next-package-dependency: ${error instanceof Error ? error.message : String(error)}`)
|
||||
process.exitCode = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
benchmarkNpmResolution,
|
||||
buildRegistryIndex,
|
||||
parseBenchmarkOptions,
|
||||
publishWorkspaceRange,
|
||||
resolveNpmPackageLock,
|
||||
runCommandWithTimeout,
|
||||
type RegistryIndex,
|
||||
} from './benchmark-npm-resolution.ts'
|
||||
|
||||
const roots: string[] = []
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
function writeJson(root: string, path: string, value: unknown): void {
|
||||
const absolute = join(root, path)
|
||||
mkdirSync(dirname(absolute), { recursive: true })
|
||||
writeFileSync(absolute, `${JSON.stringify(value, null, 2)}\n`)
|
||||
}
|
||||
|
||||
describe('npm resolution benchmark', () => {
|
||||
it('parses repeat, timeout, threshold, and ref options', () => {
|
||||
expect(parseBenchmarkOptions([])).toEqual({ runs: 1, timeoutMs: 300_000 })
|
||||
expect(parseBenchmarkOptions([
|
||||
'--runs', '3', '--timeout-ms', '45000', '--max-ms', '20000', '--ref', 'master',
|
||||
])).toEqual({ runs: 3, timeoutMs: 45_000, maxMs: 20_000, ref: 'master' })
|
||||
expect(parseBenchmarkOptions(['--', '--runs', '2'])).toEqual({ runs: 2, timeoutMs: 300_000 })
|
||||
expect(() => parseBenchmarkOptions(['--runs', '0'])).toThrow('--runs must be a positive integer')
|
||||
})
|
||||
|
||||
it('projects workspace protocols to published ranges', () => {
|
||||
expect(publishWorkspaceRange('workspace:^', '1.2.3')).toBe('^1.2.3')
|
||||
expect(publishWorkspaceRange('workspace:~', '1.2.3')).toBe('~1.2.3')
|
||||
expect(publishWorkspaceRange('workspace:*', '1.2.3')).toBe('1.2.3')
|
||||
expect(publishWorkspaceRange('^4.0.0', '1.2.3')).toBe('^4.0.0')
|
||||
})
|
||||
|
||||
it('combines installed metadata with current publishable workspace fields', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-npm-registry-index-'))
|
||||
roots.push(root)
|
||||
writeJson(root, 'node_modules/.pnpm/external@2.0.0/node_modules/external/package.json', {
|
||||
name: 'external',
|
||||
version: '2.0.0',
|
||||
dependencies: { child: '^1.0.0' },
|
||||
devDependencies: { ignored: '^1.0.0' },
|
||||
})
|
||||
writeJson(root, 'apps/cli/package.json', {
|
||||
name: '@deepseek-ai/dsh',
|
||||
version: '0.1.0',
|
||||
dependencies: { '@deepseek-ai/dsh-child': 'workspace:^', external: '^2.0.0' },
|
||||
devDependencies: { ignored: 'workspace:^' },
|
||||
})
|
||||
writeJson(root, 'packages/core/child/package.json', {
|
||||
name: '@deepseek-ai/dsh-child',
|
||||
version: '0.1.0',
|
||||
})
|
||||
|
||||
const index = buildRegistryIndex(root)
|
||||
|
||||
expect(index.get('external')?.get('2.0.0')).toMatchObject({ dependencies: { child: '^1.0.0' } })
|
||||
expect(index.get('@deepseek-ai/dsh')?.get('0.1.0')).toEqual({
|
||||
name: '@deepseek-ai/dsh',
|
||||
version: '0.1.0',
|
||||
dependencies: { '@deepseek-ai/dsh-child': '^0.1.0', external: '^2.0.0' },
|
||||
})
|
||||
})
|
||||
|
||||
it('runs npm against the local registry without requesting an archive', async () => {
|
||||
const index: RegistryIndex = new Map([[
|
||||
'@deepseek-ai/dsh',
|
||||
new Map([['0.1.0', { name: '@deepseek-ai/dsh', version: '0.1.0' }]]),
|
||||
]])
|
||||
const result = await benchmarkNpmResolution(index, '0.1.0', 10_000)
|
||||
|
||||
expect(result.durationMs).toBeGreaterThan(0)
|
||||
expect(result.registryRequests).toBeGreaterThan(0)
|
||||
expect(result.archiveRequests).toBe(0)
|
||||
expect(result.unknownPackages).toEqual([])
|
||||
})
|
||||
|
||||
it('returns npm placement for two aliased package versions without requesting archives', async () => {
|
||||
const index: RegistryIndex = new Map([[
|
||||
'@deepseek-ai/dsh',
|
||||
new Map([
|
||||
['0.1.0', { name: '@deepseek-ai/dsh', version: '0.1.0' }],
|
||||
['0.2.0', { name: '@deepseek-ai/dsh', version: '0.2.0' }],
|
||||
]),
|
||||
]])
|
||||
|
||||
const result = await resolveNpmPackageLock(index, {
|
||||
'@deepseek-ai/dsh': '0.2.0',
|
||||
'dsh-previous': 'npm:@deepseek-ai/dsh@0.1.0',
|
||||
}, 10_000)
|
||||
|
||||
expect(result.archiveRequests).toBe(0)
|
||||
expect(result.packageLock.packages['node_modules/@deepseek-ai/dsh']?.version).toBe('0.2.0')
|
||||
expect(result.packageLock.packages['node_modules/dsh-previous']).toMatchObject({
|
||||
name: '@deepseek-ai/dsh',
|
||||
version: '0.1.0',
|
||||
})
|
||||
})
|
||||
|
||||
it('isolates peer resolution from inherited npm configuration', async () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-hostile-npm-config-'))
|
||||
roots.push(root)
|
||||
const userConfig = join(root, 'user.npmrc')
|
||||
writeFileSync(userConfig, '@deepseek-ai:registry=http://127.0.0.1:1/\nlegacy-peer-deps=true\nomit=peer\n')
|
||||
const previous = {
|
||||
userConfig: process.env.npm_config_userconfig,
|
||||
legacyPeerDeps: process.env.npm_config_legacy_peer_deps,
|
||||
omit: process.env.npm_config_omit,
|
||||
}
|
||||
process.env.npm_config_userconfig = userConfig
|
||||
process.env.npm_config_legacy_peer_deps = 'true'
|
||||
process.env.npm_config_omit = 'peer'
|
||||
try {
|
||||
const index: RegistryIndex = new Map([
|
||||
['@deepseek-ai/dsh', new Map([['0.1.0', {
|
||||
name: '@deepseek-ai/dsh',
|
||||
version: '0.1.0',
|
||||
peerDependencies: { '@deepseek-ai/dsh-peer': '1.0.0' },
|
||||
}]])],
|
||||
['@deepseek-ai/dsh-peer', new Map([['1.0.0', {
|
||||
name: '@deepseek-ai/dsh-peer',
|
||||
version: '1.0.0',
|
||||
}]])],
|
||||
])
|
||||
|
||||
const result = await resolveNpmPackageLock(index, { '@deepseek-ai/dsh': '0.1.0' }, 10_000)
|
||||
|
||||
expect(result.archiveRequests).toBe(0)
|
||||
expect(result.packageLock.packages['node_modules/@deepseek-ai/dsh-peer']?.version).toBe('1.0.0')
|
||||
} finally {
|
||||
if (previous.userConfig === undefined) delete process.env.npm_config_userconfig
|
||||
else process.env.npm_config_userconfig = previous.userConfig
|
||||
if (previous.legacyPeerDeps === undefined) delete process.env.npm_config_legacy_peer_deps
|
||||
else process.env.npm_config_legacy_peer_deps = previous.legacyPeerDeps
|
||||
if (previous.omit === undefined) delete process.env.npm_config_omit
|
||||
else process.env.npm_config_omit = previous.omit
|
||||
}
|
||||
})
|
||||
|
||||
it.skipIf(process.platform === 'win32')('force-kills a timed-out process tree', async () => {
|
||||
const source = [
|
||||
"const { spawn } = require('node:child_process')",
|
||||
"process.on('SIGTERM', () => {})",
|
||||
'const child = spawn(process.execPath, [\'-e\', "process.on(\'SIGTERM\', () => {}); setInterval(() => {}, 1000)"], { stdio: \'ignore\' })',
|
||||
'console.log(child.pid)',
|
||||
'setInterval(() => {}, 1000)',
|
||||
].join(';')
|
||||
let descendantPid: number | undefined
|
||||
try {
|
||||
const result = await runCommandWithTimeout(process.execPath, ['-e', source], {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
timeoutMs: 1_000,
|
||||
terminationGraceMs: 100,
|
||||
})
|
||||
const reportedPid = Number.parseInt(result.output.trim(), 10)
|
||||
if (!Number.isSafeInteger(reportedPid)) throw new Error(`child reported invalid pid ${result.output.trim()}`)
|
||||
descendantPid = reportedPid
|
||||
|
||||
expect(result.timedOut).toBe(true)
|
||||
expect(result.signal).toBe('SIGKILL')
|
||||
expect(() => { process.kill(reportedPid, 0) }).toThrow()
|
||||
} finally {
|
||||
if (descendantPid !== undefined && Number.isSafeInteger(descendantPid)) {
|
||||
try {
|
||||
process.kill(descendantPid, 'SIGKILL')
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,551 @@
|
||||
/** Benchmark npm's dependency-tree resolution against an all-local registry. */
|
||||
|
||||
import { execFileSync, spawn, spawnSync, type ChildProcess } from 'node:child_process'
|
||||
import { globSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { createServer, type Server } from 'node:http'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { parseArgs } from 'node:util'
|
||||
|
||||
const TARGET_PACKAGE = '@deepseek-ai/dsh'
|
||||
const DEFAULT_TIMEOUT_MS = 300_000
|
||||
const TERMINATION_GRACE_MS = 1_000
|
||||
const FORCED_EXIT_TIMEOUT_MS = 5_000
|
||||
const WORKSPACE_MANIFEST_GLOBS = [
|
||||
'apps/*/package.json',
|
||||
'packages/*/*/package.json',
|
||||
'vendor/*/package.json',
|
||||
'native/landlock-run/package.json',
|
||||
'native/landlock-run/packages/*/package.json',
|
||||
]
|
||||
const INSTALLED_MANIFEST_GLOBS = [
|
||||
'node_modules/.pnpm/*/node_modules/*/package.json',
|
||||
'node_modules/.pnpm/*/node_modules/@*/*/package.json',
|
||||
]
|
||||
const PUBLISHED_FIELDS = [
|
||||
'dependencies',
|
||||
'optionalDependencies',
|
||||
'peerDependencies',
|
||||
'peerDependenciesMeta',
|
||||
'engines',
|
||||
'os',
|
||||
'cpu',
|
||||
'bin',
|
||||
] as const
|
||||
|
||||
interface PackageManifest {
|
||||
readonly name?: unknown
|
||||
readonly version?: unknown
|
||||
readonly dependencies?: Record<string, string>
|
||||
readonly optionalDependencies?: Record<string, string>
|
||||
readonly peerDependencies?: Record<string, string>
|
||||
readonly peerDependenciesMeta?: Record<string, unknown>
|
||||
readonly engines?: unknown
|
||||
readonly os?: unknown
|
||||
readonly cpu?: unknown
|
||||
readonly bin?: unknown
|
||||
}
|
||||
|
||||
interface RegistryVersion extends PackageManifest {
|
||||
readonly name: string
|
||||
readonly version: string
|
||||
}
|
||||
|
||||
/** Package versions served by the local benchmark registry. */
|
||||
export type RegistryIndex = ReadonlyMap<string, ReadonlyMap<string, RegistryVersion>>
|
||||
|
||||
/** Parsed command-line options for one benchmark invocation. */
|
||||
export interface BenchmarkOptions {
|
||||
readonly ref?: string
|
||||
readonly runs: number
|
||||
readonly timeoutMs: number
|
||||
readonly maxMs?: number
|
||||
}
|
||||
|
||||
/** One measured npm resolution. */
|
||||
export interface BenchmarkRun {
|
||||
readonly durationMs: number
|
||||
readonly registryRequests: number
|
||||
readonly archiveRequests: number
|
||||
readonly unknownPackages: readonly string[]
|
||||
}
|
||||
|
||||
/** Published-package fields retained in npm's package-lock layout. */
|
||||
export interface NpmLockPackage {
|
||||
readonly name?: string
|
||||
readonly version?: string
|
||||
readonly dependencies?: Readonly<Record<string, string>>
|
||||
readonly optionalDependencies?: Readonly<Record<string, string>>
|
||||
readonly peerDependencies?: Readonly<Record<string, string>>
|
||||
readonly peerDependenciesMeta?: Readonly<Record<string, { readonly optional?: boolean }>>
|
||||
}
|
||||
|
||||
/** The installed paths selected by npm without materializing package archives. */
|
||||
export interface NpmPackageLock {
|
||||
readonly lockfileVersion: number
|
||||
readonly packages: Readonly<Record<string, NpmLockPackage>>
|
||||
}
|
||||
|
||||
/** npm resolution observations together with its computed install layout. */
|
||||
export interface NpmPackageLockResolution extends BenchmarkRun {
|
||||
readonly packageLock: NpmPackageLock
|
||||
}
|
||||
|
||||
/** Parse one positive-integer command-line option or use its default. */
|
||||
export function parsePositiveIntegerOption(raw: string | undefined, fallback: number, name: string): number {
|
||||
if (raw === undefined) return fallback
|
||||
const value = Number.parseInt(raw, 10)
|
||||
if (!Number.isSafeInteger(value) || value < 1 || String(value) !== raw) {
|
||||
throw new Error(`${name} must be a positive integer, got ${JSON.stringify(raw)}`)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse supported benchmark arguments.
|
||||
* @param args - Command-line arguments after the script path.
|
||||
* @returns Validated benchmark options.
|
||||
*/
|
||||
export function parseBenchmarkOptions(args: readonly string[]): BenchmarkOptions {
|
||||
const normalized = args[0] === '--' ? args.slice(1) : args
|
||||
const { values } = parseArgs({
|
||||
args: [...normalized],
|
||||
options: {
|
||||
ref: { type: 'string' },
|
||||
runs: { type: 'string' },
|
||||
'timeout-ms': { type: 'string' },
|
||||
'max-ms': { type: 'string' },
|
||||
},
|
||||
allowPositionals: false,
|
||||
})
|
||||
const maxMs = values['max-ms'] === undefined
|
||||
? undefined
|
||||
: parsePositiveIntegerOption(values['max-ms'], 0, '--max-ms')
|
||||
return {
|
||||
runs: parsePositiveIntegerOption(values.runs, 1, '--runs'),
|
||||
timeoutMs: parsePositiveIntegerOption(values['timeout-ms'], DEFAULT_TIMEOUT_MS, '--timeout-ms'),
|
||||
...(values.ref === undefined ? {} : { ref: values.ref }),
|
||||
...(maxMs === undefined ? {} : { maxMs }),
|
||||
}
|
||||
}
|
||||
|
||||
function workspaceManifestPath(path: string): boolean {
|
||||
return /^(?:apps\/[^/]+|packages\/[^/]+\/[^/]+|vendor\/[^/]+|native\/landlock-run(?:\/packages\/[^/]+)?)\/package\.json$/.test(path)
|
||||
}
|
||||
|
||||
function workspaceManifestPaths(root: string, ref: string | undefined): string[] {
|
||||
if (ref === undefined) return globSync(WORKSPACE_MANIFEST_GLOBS, { cwd: root }).sort()
|
||||
return execFileSync('git', ['ls-tree', '-r', '--name-only', ref, '--', 'apps', 'packages', 'vendor', 'native'], {
|
||||
cwd: root,
|
||||
encoding: 'utf8',
|
||||
}).split('\n').filter(workspaceManifestPath).sort()
|
||||
}
|
||||
|
||||
function readGitFiles(root: string, ref: string, paths: readonly string[]): ReadonlyMap<string, string> {
|
||||
const output = execFileSync('git', ['cat-file', '--batch'], {
|
||||
cwd: root,
|
||||
input: paths.map(path => `${ref}:${path}\n`).join(''),
|
||||
maxBuffer: 64 * 1024 * 1024,
|
||||
})
|
||||
const contents = new Map<string, string>()
|
||||
let offset = 0
|
||||
for (const path of paths) {
|
||||
const headerEnd = output.indexOf(0x0a, offset)
|
||||
if (headerEnd < 0) throw new Error(`git cat-file returned no header for ${ref}:${path}`)
|
||||
const header = output.subarray(offset, headerEnd).toString('utf8')
|
||||
if (header.endsWith(' missing')) throw new Error(`git ref ${ref} has no ${path}`)
|
||||
const size = Number.parseInt(header.split(' ')[2] ?? '', 10)
|
||||
if (!Number.isSafeInteger(size) || size < 0) {
|
||||
throw new Error(`git cat-file returned an invalid size for ${ref}:${path}`)
|
||||
}
|
||||
const contentStart = headerEnd + 1
|
||||
const contentEnd = contentStart + size
|
||||
if (output[contentEnd] !== 0x0a) throw new Error(`git cat-file truncated ${ref}:${path}`)
|
||||
contents.set(path, output.subarray(contentStart, contentEnd).toString('utf8'))
|
||||
offset = contentEnd + 1
|
||||
}
|
||||
return contents
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a workspace protocol range to the range published by pnpm pack.
|
||||
* @param range - Dependency range from a workspace manifest.
|
||||
* @param targetVersion - Current version of the referenced workspace package.
|
||||
* @returns The registry-facing semver range.
|
||||
*/
|
||||
export function publishWorkspaceRange(range: string, targetVersion: string): string {
|
||||
if (range === 'workspace:*') return targetVersion
|
||||
if (range === 'workspace:^') return `^${targetVersion}`
|
||||
if (range === 'workspace:~') return `~${targetVersion}`
|
||||
if (range.startsWith('workspace:')) return range.slice('workspace:'.length)
|
||||
return range
|
||||
}
|
||||
|
||||
function copyPublishedManifest(
|
||||
source: PackageManifest,
|
||||
workspaceVersions: ReadonlyMap<string, string>,
|
||||
): RegistryVersion | undefined {
|
||||
if (typeof source.name !== 'string' || typeof source.version !== 'string') return undefined
|
||||
const output: Record<string, unknown> = { name: source.name, version: source.version }
|
||||
for (const field of PUBLISHED_FIELDS) {
|
||||
const value = source[field]
|
||||
if (value === undefined) continue
|
||||
if (field === 'dependencies' || field === 'optionalDependencies' || field === 'peerDependencies') {
|
||||
output[field] = Object.fromEntries(Object.entries(value as Record<string, string>).map(([name, range]) => {
|
||||
const targetVersion = workspaceVersions.get(name)
|
||||
return [name, targetVersion === undefined ? range : publishWorkspaceRange(range, targetVersion)]
|
||||
}))
|
||||
} else {
|
||||
output[field] = structuredClone(value)
|
||||
}
|
||||
}
|
||||
return output as unknown as RegistryVersion
|
||||
}
|
||||
|
||||
function addManifest(index: Map<string, Map<string, RegistryVersion>>, manifest: RegistryVersion): void {
|
||||
const versions = index.get(manifest.name) ?? new Map<string, RegistryVersion>()
|
||||
versions.set(manifest.version, manifest)
|
||||
index.set(manifest.name, versions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Build registry metadata from installed external packages and workspace manifests.
|
||||
* @param root - Repository root containing the pnpm virtual store.
|
||||
* @param ref - Optional Git ref used instead of working-tree workspace manifests.
|
||||
* @returns Package metadata served by the benchmark registry.
|
||||
*/
|
||||
export function buildRegistryIndex(root: string, ref?: string): RegistryIndex {
|
||||
const index = new Map<string, Map<string, RegistryVersion>>()
|
||||
for (const path of globSync(INSTALLED_MANIFEST_GLOBS, { cwd: root }).sort()) {
|
||||
const manifest = JSON.parse(readFileSync(resolve(root, path), 'utf8')) as PackageManifest
|
||||
const copied = copyPublishedManifest(manifest, new Map())
|
||||
if (copied !== undefined) addManifest(index, copied)
|
||||
}
|
||||
|
||||
const paths = workspaceManifestPaths(root, ref)
|
||||
const refContents = ref === undefined ? undefined : readGitFiles(root, ref, paths)
|
||||
const workspace = paths.map(path =>
|
||||
JSON.parse(refContents?.get(path) ?? readFileSync(resolve(root, path), 'utf8')) as PackageManifest)
|
||||
const workspaceVersions = new Map(workspace.flatMap(manifest =>
|
||||
typeof manifest.name === 'string' && typeof manifest.version === 'string'
|
||||
? [[manifest.name, manifest.version] as const]
|
||||
: []))
|
||||
for (const manifest of workspace) {
|
||||
const copied = copyPublishedManifest(manifest, workspaceVersions)
|
||||
if (copied !== undefined) addManifest(index, copied)
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
function latestVersion(versions: ReadonlyMap<string, RegistryVersion>): string {
|
||||
const sorted = [...versions.keys()].sort((left, right) => left.localeCompare(right, 'en', { numeric: true }))
|
||||
const latest = sorted.at(-1)
|
||||
if (latest === undefined) throw new Error('local registry package has no versions')
|
||||
return latest
|
||||
}
|
||||
|
||||
function listen(server: Server): Promise<number> {
|
||||
return new Promise((resolveListen, reject) => {
|
||||
server.once('error', reject)
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
server.off('error', reject)
|
||||
const address = server.address()
|
||||
if (address === null || typeof address === 'string') {
|
||||
reject(new Error('local registry did not expose a TCP port'))
|
||||
return
|
||||
}
|
||||
resolveListen(address.port)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function close(server: Server): Promise<void> {
|
||||
return new Promise((resolveClose, reject) => {
|
||||
server.close((error) => {
|
||||
if (error === undefined) resolveClose()
|
||||
else reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function npmExecutable(): string {
|
||||
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
||||
}
|
||||
|
||||
function delay(ms: number): Promise<void> {
|
||||
return new Promise(resolveDelay => setTimeout(resolveDelay, ms))
|
||||
}
|
||||
|
||||
function signalProcessTree(child: ChildProcess, signal: 'SIGTERM' | 'SIGKILL'): void {
|
||||
if (child.pid === undefined) {
|
||||
child.kill(signal)
|
||||
return
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
const force = signal === 'SIGKILL' ? ['/F'] : []
|
||||
const result = spawnSync('taskkill', ['/PID', String(child.pid), '/T', ...force], {
|
||||
stdio: 'ignore',
|
||||
windowsHide: true,
|
||||
})
|
||||
if (result.error !== undefined) throw result.error
|
||||
if (result.status !== 0 && child.exitCode === null && child.signalCode === null) child.kill(signal)
|
||||
return
|
||||
}
|
||||
try {
|
||||
process.kill(-child.pid, signal)
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run one command with bounded process-tree termination after its deadline.
|
||||
* @param command - Executable path or name.
|
||||
* @param args - Arguments passed without shell interpolation on POSIX.
|
||||
* @param options - Working directory, environment, timeout, and termination grace.
|
||||
* @returns Exit facts, captured output, duration, and whether timeout handling began.
|
||||
*/
|
||||
export async function runCommandWithTimeout(
|
||||
command: string,
|
||||
args: readonly string[],
|
||||
options: {
|
||||
readonly cwd: string
|
||||
readonly env: NodeJS.ProcessEnv
|
||||
readonly timeoutMs: number
|
||||
readonly terminationGraceMs?: number
|
||||
},
|
||||
): Promise<{ status: number | null; signal: NodeJS.Signals | null; durationMs: number; output: string; timedOut: boolean }> {
|
||||
const started = performance.now()
|
||||
const child = spawn(command, [...args], {
|
||||
cwd: options.cwd,
|
||||
detached: process.platform !== 'win32',
|
||||
env: options.env,
|
||||
shell: process.platform === 'win32',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
})
|
||||
let output = ''
|
||||
child.stdout.setEncoding('utf8')
|
||||
child.stderr.setEncoding('utf8')
|
||||
child.stdout.on('data', (chunk) => { output += String(chunk) })
|
||||
child.stderr.on('data', (chunk) => { output += String(chunk) })
|
||||
const exited = new Promise<{ status: number | null; signal: NodeJS.Signals | null }>((resolveExit, reject) => {
|
||||
child.once('error', reject)
|
||||
child.once('close', (status, signal) => { resolveExit({ status, signal }) })
|
||||
})
|
||||
let timeout: NodeJS.Timeout | undefined
|
||||
try {
|
||||
const first = await Promise.race([
|
||||
exited.then(outcome => ({ type: 'exit' as const, outcome })),
|
||||
new Promise<{ type: 'timeout' }>((resolveTimeout) => {
|
||||
timeout = setTimeout(() => { resolveTimeout({ type: 'timeout' }) }, options.timeoutMs)
|
||||
}),
|
||||
])
|
||||
if (first.type === 'exit') {
|
||||
return { ...first.outcome, durationMs: performance.now() - started, output, timedOut: false }
|
||||
}
|
||||
|
||||
signalProcessTree(child, 'SIGTERM')
|
||||
await delay(options.terminationGraceMs ?? TERMINATION_GRACE_MS)
|
||||
signalProcessTree(child, 'SIGKILL')
|
||||
const forced = await Promise.race([
|
||||
exited,
|
||||
delay(FORCED_EXIT_TIMEOUT_MS).then(() => undefined),
|
||||
])
|
||||
if (forced === undefined) throw new Error('timed-out process tree did not exit after SIGKILL')
|
||||
return { ...forced, durationMs: performance.now() - started, output, timedOut: true }
|
||||
} finally {
|
||||
if (timeout !== undefined) clearTimeout(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
function readNpmPackageLock(path: string): NpmPackageLock {
|
||||
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'))
|
||||
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
||||
throw new Error('npm produced an invalid package-lock.json')
|
||||
}
|
||||
const { lockfileVersion, packages } = parsed as Record<string, unknown>
|
||||
if (!Number.isSafeInteger(lockfileVersion) || packages === null
|
||||
|| typeof packages !== 'object' || Array.isArray(packages)) {
|
||||
throw new Error('npm produced an invalid package-lock.json')
|
||||
}
|
||||
return parsed as NpmPackageLock
|
||||
}
|
||||
|
||||
async function runNpm(
|
||||
cwd: string,
|
||||
registry: string,
|
||||
timeoutMs: number,
|
||||
): Promise<{ durationMs: number; output: string; timedOut: boolean }> {
|
||||
const npmrc = join(cwd, '.npmrc')
|
||||
const globalNpmrc = join(cwd, '.npmrc-global')
|
||||
writeFileSync(npmrc, `registry=${registry}\n@deepseek-ai:registry=${registry}\n`)
|
||||
writeFileSync(globalNpmrc, '')
|
||||
const inheritedEnvironment = Object.fromEntries(Object.entries(process.env)
|
||||
.filter(([name]) => !name.toLowerCase().startsWith('npm_config_')))
|
||||
const result = await runCommandWithTimeout(npmExecutable(), [
|
||||
'install',
|
||||
'--package-lock-only',
|
||||
'--ignore-scripts',
|
||||
'--no-audit',
|
||||
'--no-fund',
|
||||
'--loglevel=error',
|
||||
'--include=peer',
|
||||
'--install-strategy=hoisted',
|
||||
'--legacy-peer-deps=false',
|
||||
`--registry=${registry}`,
|
||||
], {
|
||||
cwd,
|
||||
env: {
|
||||
...inheritedEnvironment,
|
||||
npm_config_cache: join(cwd, '.npm-cache'),
|
||||
npm_config_globalconfig: globalNpmrc,
|
||||
npm_config_userconfig: npmrc,
|
||||
npm_config_update_notifier: 'false',
|
||||
},
|
||||
timeoutMs,
|
||||
})
|
||||
if (result.timedOut) return result
|
||||
if (result.status !== 0) {
|
||||
throw new Error(`npm install exited ${String(result.status)} after ${result.durationMs.toFixed(0)} ms\n${result.output.trim()}`)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask npm to compute an install layout without downloading package archives.
|
||||
* @param index - Package metadata exposed through the local registry.
|
||||
* @param dependencies - Root dependencies whose install layout npm computes.
|
||||
* @param timeoutMs - Hard wall-clock limit for the npm child process.
|
||||
* @returns The package lock plus timing and registry-request observations.
|
||||
*/
|
||||
export async function resolveNpmPackageLock(
|
||||
index: RegistryIndex,
|
||||
dependencies: Readonly<Record<string, string>>,
|
||||
timeoutMs: number,
|
||||
): Promise<NpmPackageLockResolution> {
|
||||
let registryRequests = 0
|
||||
let archiveRequests = 0
|
||||
const unknownPackages = new Set<string>()
|
||||
let registry = ''
|
||||
const server = createServer((request, response) => {
|
||||
registryRequests++
|
||||
const pathname = new URL(request.url ?? '/', registry).pathname
|
||||
if (pathname.startsWith('/tarballs/')) {
|
||||
archiveRequests++
|
||||
response.writeHead(500, { 'content-type': 'application/json' })
|
||||
response.end(JSON.stringify({ error: 'package-lock-only benchmark requested an archive' }))
|
||||
return
|
||||
}
|
||||
const name = decodeURIComponent(pathname.slice(1))
|
||||
const versions = index.get(name)
|
||||
if (versions === undefined) {
|
||||
unknownPackages.add(name)
|
||||
response.writeHead(404, { 'content-type': 'application/json' })
|
||||
response.end(JSON.stringify({ error: 'not_found' }))
|
||||
return
|
||||
}
|
||||
const materialized = Object.fromEntries([...versions].map(([version, manifest]) => [version, {
|
||||
...manifest,
|
||||
dist: { tarball: `${registry}tarballs/${encodeURIComponent(name)}-${version}.tgz` },
|
||||
}]))
|
||||
const body = JSON.stringify({
|
||||
name,
|
||||
'dist-tags': { latest: latestVersion(versions) },
|
||||
versions: materialized,
|
||||
})
|
||||
response.writeHead(200, {
|
||||
'content-type': 'application/json',
|
||||
'content-length': Buffer.byteLength(body),
|
||||
})
|
||||
response.end(body)
|
||||
})
|
||||
const port = await listen(server)
|
||||
registry = `http://127.0.0.1:${String(port)}/`
|
||||
const consumer = mkdtempSync(join(tmpdir(), 'dsh-npm-resolution-'))
|
||||
try {
|
||||
writeFileSync(join(consumer, 'package.json'), `${JSON.stringify({
|
||||
name: 'dsh-npm-resolution-benchmark',
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
dependencies,
|
||||
}, null, 2)}\n`)
|
||||
const result = await runNpm(consumer, registry, timeoutMs)
|
||||
if (result.timedOut) throw new Error(`npm resolution exceeded ${String(timeoutMs)} ms`)
|
||||
return {
|
||||
durationMs: result.durationMs,
|
||||
registryRequests,
|
||||
archiveRequests,
|
||||
unknownPackages: [...unknownPackages].sort(),
|
||||
packageLock: readNpmPackageLock(join(consumer, 'package-lock.json')),
|
||||
}
|
||||
} finally {
|
||||
server.closeAllConnections()
|
||||
await close(server)
|
||||
rmSync(consumer, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the CLI install graph once without downloading package archives.
|
||||
* @param index - Package metadata exposed through the local registry.
|
||||
* @param targetVersion - Version of `@deepseek-ai/dsh` to install.
|
||||
* @param timeoutMs - Hard wall-clock limit for the npm child process.
|
||||
* @returns Timing and registry-request observations.
|
||||
*/
|
||||
export async function benchmarkNpmResolution(
|
||||
index: RegistryIndex,
|
||||
targetVersion: string,
|
||||
timeoutMs: number,
|
||||
): Promise<BenchmarkRun> {
|
||||
const result = await resolveNpmPackageLock(index, { [TARGET_PACKAGE]: targetVersion }, timeoutMs)
|
||||
return {
|
||||
durationMs: result.durationMs,
|
||||
registryRequests: result.registryRequests,
|
||||
archiveRequests: result.archiveRequests,
|
||||
unknownPackages: result.unknownPackages,
|
||||
}
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const options = parseBenchmarkOptions(process.argv.slice(2))
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const started = performance.now()
|
||||
const index = buildRegistryIndex(root, options.ref)
|
||||
const targetVersions = index.get(TARGET_PACKAGE)
|
||||
if (targetVersions === undefined) throw new Error(`local registry contains no ${TARGET_PACKAGE}`)
|
||||
const targetVersion = latestVersion(targetVersions)
|
||||
const npmVersion = execFileSync(npmExecutable(), ['--version'], { encoding: 'utf8' }).trim()
|
||||
console.log(
|
||||
`benchmark-npm-resolution: npm ${npmVersion}, ${options.ref === undefined ? 'working tree' : options.ref}, `
|
||||
+ `${String(index.size)} package name(s), setup ${(performance.now() - started).toFixed(0)} ms.`,
|
||||
)
|
||||
const durations: number[] = []
|
||||
for (let run = 1; run <= options.runs; run++) {
|
||||
const result = await benchmarkNpmResolution(index, targetVersion, options.timeoutMs)
|
||||
durations.push(result.durationMs)
|
||||
console.log(
|
||||
`benchmark-npm-resolution: run ${String(run)}/${String(options.runs)} resolved ${TARGET_PACKAGE}@${targetVersion}`
|
||||
+ ` in ${(result.durationMs / 1000).toFixed(2)} s with ${String(result.registryRequests)} metadata request(s)`
|
||||
+ ` and ${String(result.unknownPackages.length)} local 404 package name(s).`,
|
||||
)
|
||||
if (result.archiveRequests > 0) throw new Error('npm requested package archives during the metadata-only benchmark')
|
||||
}
|
||||
const minimum = Math.min(...durations)
|
||||
const maximum = Math.max(...durations)
|
||||
console.log(
|
||||
`benchmark-npm-resolution: ${String(options.runs)} run(s), min ${(minimum / 1000).toFixed(2)} s, max ${(maximum / 1000).toFixed(2)} s.`,
|
||||
)
|
||||
if (options.maxMs !== undefined && maximum > options.maxMs) {
|
||||
throw new Error(`npm resolution exceeded --max-ms=${String(options.maxMs)} (max ${maximum.toFixed(0)} ms)`)
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
try {
|
||||
await main()
|
||||
} catch (error) {
|
||||
console.error(`benchmark-npm-resolution: ${error instanceof Error ? error.message : String(error)}`)
|
||||
process.exitCode = 1
|
||||
}
|
||||
}
|
||||
@@ -603,7 +603,7 @@ describe('npm release workflows', () => {
|
||||
for (const file of ['release.yml', 'release-vendor.yml']) {
|
||||
const workflow = loadWorkflow(`.github/workflows/${file}`)
|
||||
if (!isRecord(workflow.jobs)) throw new TypeError(`${file} must define jobs`)
|
||||
expect(Object.keys(workflow.jobs).sort()).toEqual(['pack'])
|
||||
expect(Object.keys(workflow.jobs).sort()).toEqual(file === 'release.yml' ? ['dependencies', 'pack'] : ['pack'])
|
||||
}
|
||||
|
||||
// publication is workflow_dispatch-only (never a PR check) and keeps the
|
||||
@@ -618,6 +618,20 @@ describe('npm release workflows', () => {
|
||||
expect(publish.concurrency).toMatchObject({ group: 'Release-publish' })
|
||||
}
|
||||
})
|
||||
|
||||
it('runs dependency policy and npm layout checks in the DSH release workflow', () => {
|
||||
const workflow = loadWorkflow('.github/workflows/release.yml')
|
||||
const dependencies = workflowJob(workflow, 'dependencies')
|
||||
if (!isRecord(workflow.on) || !Array.isArray(dependencies.steps)) {
|
||||
throw new TypeError('DSH release workflow must define triggers and dependency steps')
|
||||
}
|
||||
const commands = dependencies.steps.flatMap(step =>
|
||||
isRecord(step) && typeof step.run === 'string' ? [step.run] : [])
|
||||
|
||||
expect(Object.keys(workflow.on).sort()).toEqual(['pull_request', 'push', 'workflow_dispatch'])
|
||||
expect(commands).toContain('pnpm run verify-package-dependencies')
|
||||
expect(commands).toContain('pnpm run verify-npm-install-layout')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Documentation site publication', () => {
|
||||
|
||||
+106
-48
@@ -1,21 +1,21 @@
|
||||
/**
|
||||
* Generate `docs/module-graph.md` from in-repo `peerDependencies`, the canonical
|
||||
* runtime edges. The deterministic output groups packages by directory and
|
||||
* renders both Mermaid and a dependency table; `--check` verifies freshness.
|
||||
*/
|
||||
/** Generate the paired shared-instance package graph from workspace peer dependencies. */
|
||||
|
||||
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import {
|
||||
collectPackageGraph,
|
||||
escapeMermaidLabel as escLabel,
|
||||
graphNodeId as nodeId,
|
||||
type PackageGraphNode,
|
||||
} from './package-graph.ts'
|
||||
import { gitBlobHash, storeGitBlob } from './translation-pairing-git.ts'
|
||||
import { renderTranslationPairingRecord, translationPairPaths } from './translation-pairing-record.ts'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const OUT = 'docs/module-graph.md'
|
||||
const SOURCE = 'docs/module-graph.md'
|
||||
const PATHS = translationPairPaths(SOURCE)
|
||||
type Pkg = PackageGraphNode
|
||||
type Locale = 'en' | 'zh'
|
||||
|
||||
const GROUP_ORDER = [
|
||||
'util',
|
||||
@@ -46,42 +46,55 @@ function packageLink(pkg: Pkg): string {
|
||||
return `[\`${pkg.short}\`](../${pkg.rel})`
|
||||
}
|
||||
|
||||
/** Render the full docs/module-graph.md content (pure, deterministic). */
|
||||
function render(pkgs: Pkg[]): string {
|
||||
/**
|
||||
* Render one locale of the complete deterministic package graph.
|
||||
* @param pkgs - Dependency-first package nodes.
|
||||
* @param locale - Output document language.
|
||||
* @returns Complete generated Markdown.
|
||||
*/
|
||||
export function renderModuleGraph(pkgs: readonly Pkg[], locale: Locale): string {
|
||||
const edges: string[] = []
|
||||
for (const p of pkgs) {
|
||||
for (const d of p.deps) edges.push(` ${nodeId('pkg', p.short)} --> ${nodeId('pkg', d)}`)
|
||||
for (const pkg of pkgs) {
|
||||
for (const dependency of pkg.deps) edges.push(` ${nodeId('pkg', pkg.short)} --> ${nodeId('pkg', dependency)}`)
|
||||
}
|
||||
const byShort = new Map(pkgs.map(pkg => [pkg.short, pkg]))
|
||||
const groups = [...new Set(pkgs.map(pkg => pkg.group))].sort((a, b) => {
|
||||
const ia = GROUP_ORDER.indexOf(a)
|
||||
const ib = GROUP_ORDER.indexOf(b)
|
||||
const na = ia === -1 ? Number.MAX_SAFE_INTEGER : ia
|
||||
const nb = ib === -1 ? Number.MAX_SAFE_INTEGER : ib
|
||||
return na - nb || a.localeCompare(b)
|
||||
const groups = [...new Set(pkgs.map(pkg => pkg.group))].sort((left, right) => {
|
||||
const leftIndex = GROUP_ORDER.indexOf(left)
|
||||
const rightIndex = GROUP_ORDER.indexOf(right)
|
||||
const normalizedLeft = leftIndex === -1 ? Number.MAX_SAFE_INTEGER : leftIndex
|
||||
const normalizedRight = rightIndex === -1 ? Number.MAX_SAFE_INTEGER : rightIndex
|
||||
return normalizedLeft - normalizedRight || left.localeCompare(right)
|
||||
})
|
||||
const groupBlocks: string[] = []
|
||||
for (const group of groups) {
|
||||
groupBlocks.push(` subgraph ${nodeId('group', group)}["packages/${escLabel(group)}"]`)
|
||||
for (const pkg of pkgs.filter(p => p.group === group).sort((a, b) => a.short.localeCompare(b.short))) {
|
||||
for (const pkg of pkgs.filter(candidate => candidate.group === group)
|
||||
.sort((left, right) => left.short.localeCompare(right.short))) {
|
||||
groupBlocks.push(` ${nodeId('pkg', pkg.short)}["${escLabel(pkg.short)}"]`)
|
||||
}
|
||||
groupBlocks.push(' end')
|
||||
}
|
||||
const rows = pkgs.map((p) => {
|
||||
const deps = p.deps.length ? p.deps.map((d) => {
|
||||
const dep = byShort.get(d)
|
||||
return dep ? packageLink(dep) : `\`${d}\``
|
||||
}).join(', ') : '—'
|
||||
return `| ${packageLink(p)} | \`${p.group}\` | ${deps} |`
|
||||
const rows = pkgs.map((pkg) => {
|
||||
const dependencies = pkg.deps.length > 0
|
||||
? pkg.deps.map((dependency) => {
|
||||
const target = byShort.get(dependency)
|
||||
return target ? packageLink(target) : `\`${dependency}\``
|
||||
}).join(', ')
|
||||
: '—'
|
||||
return `| ${packageLink(pkg)} | \`${pkg.group}\` | ${dependencies} |`
|
||||
})
|
||||
const chinese = locale === 'zh'
|
||||
return [
|
||||
'<!-- Generated by scripts/gen-module-graph.ts — do not edit by hand.',
|
||||
' Run `pnpm run gen-module-graph` to regenerate. -->',
|
||||
chinese
|
||||
? '<!-- 由 scripts/gen-module-graph.ts 生成——请勿手工编辑。\n 运行 `pnpm run gen-module-graph` 重新生成。 -->'
|
||||
: '<!-- Generated by scripts/gen-module-graph.ts — do not edit by hand.\n Run `pnpm run gen-module-graph` to regenerate. -->',
|
||||
'',
|
||||
'# Module dependency graph',
|
||||
chinese ? '# 共享实例依赖关系图' : '# Shared-instance dependency graph',
|
||||
'',
|
||||
'Inter-package dependencies among the `@deepseek-ai/dsh-*` harness packages, derived from each package\'s `peerDependencies` (the canonical runtime-dependency signal) and grouped by the `packages/<group>/<pkg>` hierarchy. An edge `a --> b` means package `a` depends on package `b`. Names have the `@deepseek-ai/dsh-` prefix stripped.',
|
||||
...(chinese ? ['[English](module-graph.md) | 中文', ''] : []),
|
||||
chinese
|
||||
? '`@deepseek-ai/dsh-*` harness 包之间的 peer 依赖关系。peer 表示消费端需要提供共享实例,不包括普通运行时 dependency 或仅开发期关系。该图按 `packages/<group>/<pkg>` 层级分组;边 `a --> b` 表示包 `a` peer 依赖包 `b`。名称中的 `@deepseek-ai/dsh-` 前缀已移除。'
|
||||
: 'Peer dependencies among the `@deepseek-ai/dsh-*` harness packages. A peer means the consumer requires a shared instance; ordinary runtime dependencies and development-only relationships are not shown. The graph is grouped by the `packages/<group>/<pkg>` hierarchy. An edge `a --> b` means package `a` has package `b` as a peer. Names omit the `@deepseek-ai/dsh-` prefix.',
|
||||
'',
|
||||
'```mermaid',
|
||||
'flowchart TD',
|
||||
@@ -89,31 +102,76 @@ function render(pkgs: Pkg[]): string {
|
||||
...edges,
|
||||
'```',
|
||||
'',
|
||||
'| Package | Group | Depends on |',
|
||||
chinese ? '| 包 | 分组 | Peer 依赖 |' : '| Package | Group | Peer dependencies |',
|
||||
'| --- | --- | --- |',
|
||||
...rows,
|
||||
'',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
const content = render(collectPackageGraph(root, GROUP_ORDER, 'gen-module-graph'))
|
||||
|
||||
if (process.argv.includes('--check')) {
|
||||
let committed: string | null = null
|
||||
try {
|
||||
committed = readFileSync(resolve(root, OUT), 'utf8')
|
||||
} catch {
|
||||
// A missing artifact is the expected read failure. Any read failure has the
|
||||
// same remedy here—regenerate—so it is reported as stale below.
|
||||
committed = null
|
||||
}
|
||||
if (committed === content) {
|
||||
console.log(`gen-module-graph: ${OUT} is up to date.`)
|
||||
process.exit(0)
|
||||
}
|
||||
console.error(`gen-module-graph: ${OUT} is stale. Run \`pnpm run gen-module-graph\` and commit ${OUT}.`)
|
||||
process.exit(1)
|
||||
/**
|
||||
* Compute both localized graph documents from the current workspace manifests.
|
||||
* @param scanRoot - Repository root containing packages and documentation.
|
||||
* @returns Repository-relative output paths and exact generated content.
|
||||
*/
|
||||
export function computeModuleGraphOutputs(scanRoot: string = root): ReadonlyMap<string, string> {
|
||||
const packages = collectPackageGraph(scanRoot, GROUP_ORDER, 'gen-module-graph')
|
||||
return new Map([
|
||||
[PATHS.source, renderModuleGraph(packages, 'en')],
|
||||
[PATHS.zh, renderModuleGraph(packages, 'zh')],
|
||||
])
|
||||
}
|
||||
|
||||
writeFileSync(resolve(root, OUT), content)
|
||||
console.log(`gen-module-graph: wrote ${OUT}.`)
|
||||
/**
|
||||
* Write both graph documents and their recovery record.
|
||||
* @param scanRoot - Repository root containing packages and documentation.
|
||||
* @returns Repository-relative paths whose content changed.
|
||||
*/
|
||||
export function writeModuleGraph(scanRoot: string = root): string[] {
|
||||
const outputs = computeModuleGraphOutputs(scanRoot)
|
||||
const changed: string[] = []
|
||||
for (const [path, content] of outputs) {
|
||||
const destination = resolve(scanRoot, path)
|
||||
if (existsSync(destination) && readFileSync(destination, 'utf8') === content) continue
|
||||
writeFileSync(destination, content)
|
||||
changed.push(path)
|
||||
}
|
||||
const source = Buffer.from(outputs.get(PATHS.source) ?? '')
|
||||
const zh = Buffer.from(outputs.get(PATHS.zh) ?? '')
|
||||
const record = renderTranslationPairingRecord(PATHS, {
|
||||
sourceHash: storeGitBlob(scanRoot, source),
|
||||
zhHash: storeGitBlob(scanRoot, zh),
|
||||
})
|
||||
const recordPath = resolve(scanRoot, PATHS.meta)
|
||||
if (!existsSync(recordPath) || readFileSync(recordPath, 'utf8') !== record) {
|
||||
writeFileSync(recordPath, record)
|
||||
changed.push(PATHS.meta)
|
||||
}
|
||||
return changed.sort()
|
||||
}
|
||||
|
||||
/** CLI entry: regenerate by default, or verify all paired outputs with `--check`. @returns Nothing. */
|
||||
export function main(): void {
|
||||
const outputs = computeModuleGraphOutputs(root)
|
||||
const record = renderTranslationPairingRecord(PATHS, {
|
||||
sourceHash: gitBlobHash(Buffer.from(outputs.get(PATHS.source) ?? '')),
|
||||
zhHash: gitBlobHash(Buffer.from(outputs.get(PATHS.zh) ?? '')),
|
||||
})
|
||||
const expected = new Map([...outputs, [PATHS.meta, record]])
|
||||
if (process.argv.includes('--check')) {
|
||||
const stale = [...expected].filter(([path, content]) => (
|
||||
!existsSync(resolve(root, path)) || readFileSync(resolve(root, path), 'utf8') !== content
|
||||
)).map(([path]) => path)
|
||||
if (stale.length === 0) {
|
||||
console.log(`gen-module-graph: ${expected.size} artifact(s) are up to date.`)
|
||||
return
|
||||
}
|
||||
console.error(`gen-module-graph: stale — ${stale.join(', ')}. Run \`pnpm run gen-module-graph\` and commit the result.`)
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
const changed = writeModuleGraph(root)
|
||||
console.log(`gen-module-graph: ${expected.size} artifact(s) computed, ${String(changed.length)} written.`)
|
||||
}
|
||||
|
||||
if (process.argv[1] !== undefined && import.meta.filename === resolve(process.argv[1])) main()
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/** Explicit exceptions and Host packages for the published dependency policy. */
|
||||
|
||||
/** Packages treated as Client/Host packages without declaring `dsh.client`. */
|
||||
const CLIENT_FACE_INCLUDE: readonly string[] = []
|
||||
|
||||
/** Packages exempted from automatic Client/Host treatment despite declaring `dsh.client`. */
|
||||
const CLIENT_FACE_EXCLUDE: readonly string[] = [
|
||||
'@deepseek-ai/dsh-api-session-controller',
|
||||
'@deepseek-ai/dsh-api-workspace-controller',
|
||||
]
|
||||
|
||||
/** Host-only packages whose peer relays are deliberately flattened. */
|
||||
const HOST_DEPENDENCY_PACKAGES: readonly string[] = [
|
||||
'@deepseek-ai/dsh-llm',
|
||||
'@deepseek-ai/dsh-session',
|
||||
]
|
||||
|
||||
/** Development-only package relationships not represented by source imports. */
|
||||
const CONFIGURATION_ONLY_DEV_DEPENDENCIES = {
|
||||
'@deepseek-ai/dsh-client-locale': ['@deepseek-ai/dsh-api-remotes'],
|
||||
'@deepseek-ai/dsh-client-ui-conversation': [
|
||||
'@deepseek-ai/dsh-api-remotes',
|
||||
'@deepseek-ai/dsh-client-ui-workspace',
|
||||
],
|
||||
'@deepseek-ai/dsh-client-ui-model-selection': ['@deepseek-ai/dsh-client-ui-input-trigger'],
|
||||
'@deepseek-ai/dsh-client-ui-sidebar': ['@deepseek-ai/dsh-client-ui-workspace'],
|
||||
'@deepseek-ai/dsh-client-ui-subagent': ['@deepseek-ai/dsh-client-ui-input-trigger'],
|
||||
'@deepseek-ai/dsh-client-ui-theme': ['@deepseek-ai/dsh-api-remotes'],
|
||||
'@deepseek-ai/dsh-client-ui-tool': ['@deepseek-ai/dsh-api-remotes'],
|
||||
} as const satisfies Readonly<Record<string, readonly string[]>>
|
||||
|
||||
/**
|
||||
* Runtime exports whose values remain valid when npm installs another package copy.
|
||||
*/
|
||||
const SAFE_HOST_DEPENDENCY_EXPORTS = {
|
||||
'@deepseek-ai/dsh-api-session-controller/remote-events': ['SESSION_CONTROLLER_REMOTE_EVENTS'],
|
||||
'@deepseek-ai/dsh-credentials': ['credentialKey'],
|
||||
'@deepseek-ai/dsh-llm': ['MessageId', 'callConfigEquals', 'deepFreeze', 'freezeMessage'],
|
||||
'@deepseek-ai/dsh-llm/brand': ['ToolCallId'],
|
||||
'@deepseek-ai/dsh-session': ['isJsonValue'],
|
||||
'@deepseek-ai/dsh-session/types': ['SessionId'],
|
||||
'@deepseek-ai/dsh-settings': ['settingsNamespace'],
|
||||
'@deepseek-ai/dsh-system-prompt': ['FIRST_PARTY_SECTION_ORDER'],
|
||||
'@deepseek-ai/dsh-timeout': ['MAX_TIMER_DELAY_MS'],
|
||||
'@deepseek-ai/dsh-typert-protocol': ['RemoteError', 'remoteErrorOf'],
|
||||
'@deepseek-ai/dsh-util-crypto': ['randomUUID'],
|
||||
'@deepseek-ai/schemastery': ['default'],
|
||||
} as const satisfies HostDependencyExports
|
||||
|
||||
/** Runtime exports that require every consumer to resolve the provider's shared peer instance. */
|
||||
const PEER_REQUIRED_HOST_EXPORTS = {
|
||||
'@deepseek-ai/dsh-scope': ['carrierKeyOf', 'scopeOf', 'scopeTarget'],
|
||||
'@deepseek-ai/dsh-typert-protocol': ['Remote', 'TypertRemoteService', 'remoteMethods'],
|
||||
} as const satisfies HostDependencyExports
|
||||
|
||||
/** Exact import specifier to reviewed runtime exports. */
|
||||
type HostDependencyExports = Readonly<Record<string, readonly string[]>>
|
||||
|
||||
/** Complete configurable input to package dependency classification. */
|
||||
export interface PackageDependencyPolicy {
|
||||
readonly clientFaceInclude: readonly string[]
|
||||
readonly clientFaceExclude: readonly string[]
|
||||
readonly hostPackages: readonly string[]
|
||||
readonly configurationOnlyDevDependencies: Readonly<Record<string, readonly string[]>>
|
||||
readonly safeHostDependencyExports: HostDependencyExports
|
||||
readonly peerRequiredHostExports: HostDependencyExports
|
||||
}
|
||||
|
||||
/** Repository dependency policy consumed by verification and benchmarking. */
|
||||
export const PACKAGE_DEPENDENCY_POLICY: PackageDependencyPolicy = {
|
||||
clientFaceInclude: CLIENT_FACE_INCLUDE,
|
||||
clientFaceExclude: CLIENT_FACE_EXCLUDE,
|
||||
hostPackages: HOST_DEPENDENCY_PACKAGES,
|
||||
configurationOnlyDevDependencies: CONFIGURATION_ONLY_DEV_DEPENDENCIES,
|
||||
safeHostDependencyExports: SAFE_HOST_DEPENDENCY_EXPORTS,
|
||||
peerRequiredHostExports: PEER_REQUIRED_HOST_EXPORTS,
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
/** Whether a package manifest declares a dynamically loaded Client entry. */
|
||||
export function hasClientDeclaration(dshField: unknown): boolean {
|
||||
return isRecord(dshField) && Object.hasOwn(dshField, 'client')
|
||||
}
|
||||
|
||||
/** Whether the repository policy flattens one package's non-Cordis peers. */
|
||||
export function usesFlattenedPackageDependencies(
|
||||
manifestPath: string,
|
||||
packageName: string,
|
||||
dshField: unknown,
|
||||
policy: PackageDependencyPolicy = PACKAGE_DEPENDENCY_POLICY,
|
||||
): boolean {
|
||||
if (!manifestPath.startsWith('packages/') || manifestPath.startsWith('packages/experimental/')) return false
|
||||
if (policy.hostPackages.includes(packageName)) return true
|
||||
if (manifestPath.startsWith('packages/client/')) return true
|
||||
const included = hasClientDeclaration(dshField) || policy.clientFaceInclude.includes(packageName)
|
||||
return included && !policy.clientFaceExclude.includes(packageName)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { renderModuleGraph } from './gen-module-graph.ts'
|
||||
import { collectPackageGraph } from './package-graph.ts'
|
||||
|
||||
const roots: string[] = []
|
||||
@@ -49,3 +50,23 @@ describe('collectPackageGraph', () => {
|
||||
.toThrow('fixture: @deepseek-ai/dsh-consumer references missing in-repo peer @deepseek-ai/dsh-missing')
|
||||
})
|
||||
})
|
||||
|
||||
describe('renderModuleGraph', () => {
|
||||
it('renders the same peer edge in both generated languages', () => {
|
||||
const packages = [
|
||||
{ short: 'provider', name: '@deepseek-ai/dsh-provider', group: 'core', rel: 'packages/core/provider', deps: [] },
|
||||
{ short: 'consumer', name: '@deepseek-ai/dsh-consumer', group: 'core', rel: 'packages/core/consumer', deps: ['provider'] },
|
||||
]
|
||||
|
||||
const english = renderModuleGraph(packages, 'en')
|
||||
const chinese = renderModuleGraph(packages, 'zh')
|
||||
|
||||
expect(english).toContain('# Shared-instance dependency graph')
|
||||
expect(chinese).toContain('# 共享实例依赖关系图')
|
||||
expect(chinese).toContain('[English](module-graph.md) | 中文')
|
||||
for (const output of [english, chinese]) {
|
||||
expect(output).toContain('pkg_consumer --> pkg_provider')
|
||||
expect(output).toContain('| [`consumer`](../packages/core/consumer) | `core` | [`provider`](../packages/core/provider) |')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import { afterEach, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
collectPackageInvariantViolations,
|
||||
} from './package-invariants.ts'
|
||||
import { usesFlattenedPackageDependencies } from './package-dependency-policy.ts'
|
||||
|
||||
const roots: string[] = []
|
||||
|
||||
@@ -28,7 +29,10 @@ export const apply = (ctx: { invariants: { register(name: string, install: typeo
|
||||
|
||||
function fixture(options: {
|
||||
packageName?: string
|
||||
packageDirectory?: string
|
||||
source?: string
|
||||
clientDeclaration?: boolean
|
||||
clientExport?: boolean
|
||||
invariantExport?: boolean
|
||||
invariantDependency?: boolean
|
||||
invariantReference?: boolean
|
||||
@@ -36,19 +40,34 @@ function fixture(options: {
|
||||
} = {}): string {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-package-invariants-'))
|
||||
roots.push(root)
|
||||
const dir = join(root, 'packages/core/probe')
|
||||
const packageDirectory = options.packageDirectory ?? 'packages/core/probe'
|
||||
const dir = join(root, packageDirectory)
|
||||
mkdirSync(join(dir, 'src'), { recursive: true })
|
||||
const packageName = options.packageName ?? '@deepseek-ai/dsh-probe'
|
||||
const exports = options.invariantExport === false ? {} : {
|
||||
'./invariant': {
|
||||
types: './lib/types/invariant.d.ts',
|
||||
default: './lib/invariant.js',
|
||||
},
|
||||
...(options.clientExport === true ? {
|
||||
'./client': {
|
||||
types: './lib/types/client/index.d.ts',
|
||||
default: './lib/client.js',
|
||||
},
|
||||
} : {}),
|
||||
}
|
||||
const dsh = options.clientDeclaration === true ? { client: {} } : undefined
|
||||
const developmentOnlyInvariant = usesFlattenedPackageDependencies(
|
||||
`${packageDirectory}/package.json`,
|
||||
packageName,
|
||||
dsh,
|
||||
)
|
||||
const manifest = {
|
||||
name: packageName,
|
||||
exports: options.invariantExport === false ? {} : {
|
||||
'./invariant': {
|
||||
types: './lib/types/invariant.d.ts',
|
||||
default: './lib/invariant.js',
|
||||
},
|
||||
},
|
||||
...(dsh === undefined ? {} : { dsh }),
|
||||
exports,
|
||||
files: ['lib/index.js', 'lib/invariant.js'],
|
||||
peerDependencies: options.invariantDependency === false ? {} : {
|
||||
peerDependencies: options.invariantDependency === false || developmentOnlyInvariant ? {} : {
|
||||
'@deepseek-ai/dsh-invariants': 'workspace:^',
|
||||
},
|
||||
devDependencies: options.invariantDependency === false ? {} : {
|
||||
@@ -72,6 +91,33 @@ describe('package invariant gate', () => {
|
||||
expect(collectPackageInvariantViolations(fixture())).toEqual([])
|
||||
})
|
||||
|
||||
it('accepts development-only invariants for configured Host dependencies', () => {
|
||||
expect(collectPackageInvariantViolations(fixture({ packageName: '@deepseek-ai/dsh-llm' }))).toEqual([])
|
||||
})
|
||||
|
||||
it('accepts development-only invariants for client packages', () => {
|
||||
expect(collectPackageInvariantViolations(fixture({
|
||||
packageName: '@deepseek-ai/dsh-client-probe',
|
||||
packageDirectory: 'packages/client/probe',
|
||||
}))).toEqual([])
|
||||
})
|
||||
|
||||
it('accepts development-only invariants for packages with a dsh.client entry', () => {
|
||||
expect(collectPackageInvariantViolations(fixture({ clientDeclaration: true, clientExport: true }))).toEqual([])
|
||||
})
|
||||
|
||||
it('keeps invariant peers for packages that only export a Client API', () => {
|
||||
expect(collectPackageInvariantViolations(fixture({ clientExport: true }))).toEqual([])
|
||||
})
|
||||
|
||||
it('keeps invariant peers for experimental packages with a dsh.client entry', () => {
|
||||
expect(collectPackageInvariantViolations(fixture({
|
||||
packageDirectory: 'packages/experimental/probe',
|
||||
clientDeclaration: true,
|
||||
clientExport: true,
|
||||
}))).toEqual([])
|
||||
})
|
||||
|
||||
it('accepts an invariant reference owned by a package-local leaf project', () => {
|
||||
const root = fixture({ invariantReference: false })
|
||||
const dir = join(root, 'packages/core/probe')
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
import { existsSync, globSync, readFileSync } from 'node:fs'
|
||||
import { dirname, relative, resolve, sep } from 'node:path'
|
||||
import ts from 'typescript'
|
||||
import { usesFlattenedPackageDependencies } from './package-dependency-policy.ts'
|
||||
|
||||
/** Required explanation marker for an intentionally empty installer. */
|
||||
const NO_RUNTIME_INVARIANT_MARKER = 'No runtime invariant:'
|
||||
|
||||
interface PackageManifest {
|
||||
name?: string
|
||||
dsh?: unknown
|
||||
exports?: Record<string, { types?: string; default?: string } | string | undefined>
|
||||
files?: string[]
|
||||
peerDependencies?: Record<string, string>
|
||||
@@ -96,18 +98,23 @@ function checkManifest(
|
||||
addViolation(violations, owner.manifestPath, 'files must publish lib/invariant.js')
|
||||
}
|
||||
if (owner.packageName === '@deepseek-ai/dsh-invariants') return
|
||||
if (manifest.peerDependencies?.['@deepseek-ai/dsh-invariants'] !== 'workspace:^') {
|
||||
addViolation(
|
||||
violations,
|
||||
owner.manifestPath,
|
||||
'@deepseek-ai/dsh-invariants must be a workspace:^ peerDependency',
|
||||
)
|
||||
const developmentOnlyInvariant = usesFlattenedPackageDependencies(
|
||||
owner.manifestPath,
|
||||
owner.packageName,
|
||||
manifest.dsh,
|
||||
)
|
||||
const expectedRange = 'workspace:^'
|
||||
const peerRange = manifest.peerDependencies?.['@deepseek-ai/dsh-invariants']
|
||||
if (developmentOnlyInvariant ? peerRange !== undefined : peerRange !== expectedRange) {
|
||||
addViolation(violations, owner.manifestPath, developmentOnlyInvariant
|
||||
? '@deepseek-ai/dsh-invariants must not be a peerDependency under this package dependency policy'
|
||||
: '@deepseek-ai/dsh-invariants must be a workspace:^ peerDependency')
|
||||
}
|
||||
if (manifest.devDependencies?.['@deepseek-ai/dsh-invariants'] !== 'workspace:^') {
|
||||
if (manifest.devDependencies?.['@deepseek-ai/dsh-invariants'] !== expectedRange) {
|
||||
addViolation(
|
||||
violations,
|
||||
owner.manifestPath,
|
||||
'@deepseek-ai/dsh-invariants must also be a workspace:^ devDependency',
|
||||
`@deepseek-ai/dsh-invariants must be a ${expectedRange} devDependency`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ describe('gate graph validation', () => {
|
||||
const ids = withPnpmEntrypoint(() => gatesForMode('hygiene').map(subject => subject.id))
|
||||
|
||||
expect(ids).toEqual([
|
||||
'rescope-vendor', 'publint', 'constraints', 'application-entrypoints',
|
||||
'rescope-vendor', 'publint', 'constraints', 'package-dependencies', 'application-entrypoints',
|
||||
'dsh-package-licenses', 'package-invariants', 'built-package-invariants', 'node-next-types',
|
||||
'optional-dependency-imports', 'client-packages', 'client-ui-i18n', 'cordis-config',
|
||||
'runtime-closure', 'vendored-links',
|
||||
@@ -141,6 +141,15 @@ describe('gate graph validation', () => {
|
||||
},
|
||||
)
|
||||
|
||||
it.each(['ci-primary', 'ci-static', 'check-all', 'hygiene'] as const)(
|
||||
'keeps package dependency enforcement in %s',
|
||||
(mode) => {
|
||||
const ids = withPnpmEntrypoint(() => gatesForMode(mode).map(subject => subject.id))
|
||||
|
||||
expect(ids).toContain('package-dependencies')
|
||||
},
|
||||
)
|
||||
|
||||
it.each(['ci-primary', 'ci-static', 'check-all'] as const)(
|
||||
'keeps the client dependency policy in %s',
|
||||
(mode) => {
|
||||
|
||||
@@ -278,6 +278,7 @@ function ciSharedStaticGates(): Gate[] {
|
||||
pnpmScript('runtime-closure', 'verify-runtime-closure', { label: 'runtime closure' }),
|
||||
pnpmScript('application-entrypoints', 'verify-application-entrypoints', { label: 'application entrypoints' }),
|
||||
pnpmScript('constraints', 'constraints'),
|
||||
pnpmScript('package-dependencies', 'verify-package-dependencies', { label: 'package dependencies' }),
|
||||
pnpmScript('dsh-package-licenses', 'verify-dsh-package-licenses', { label: 'DSH package licenses' }),
|
||||
pnpmScript('package-invariants', 'verify-package-invariants', { label: 'package invariants' }),
|
||||
pnpmScript('cordis-config', 'verify-cordis-config', { label: 'Cordis config' }),
|
||||
@@ -667,6 +668,7 @@ function hygieneLeafGates(options: { artifactNeeds?: string[] } = {}): Gate[] {
|
||||
pnpmScript('rescope-vendor', 'rescope-vendor:check', { label: 'vendor rescope' }),
|
||||
pnpmScript('publint', 'publint', artifactOptions),
|
||||
pnpmScript('constraints', 'constraints'),
|
||||
pnpmScript('package-dependencies', 'verify-package-dependencies', { label: 'package dependencies' }),
|
||||
pnpmScript('application-entrypoints', 'verify-application-entrypoints', { label: 'application entrypoints' }),
|
||||
pnpmScript('dsh-package-licenses', 'verify-dsh-package-licenses', { label: 'DSH package licenses' }),
|
||||
pnpmScript('package-invariants', 'verify-package-invariants', { label: 'package invariants' }),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Tests for client package modes, dependency sections, and module requests. */
|
||||
/** Tests for client package modes and module requests. */
|
||||
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
@@ -6,6 +6,7 @@ import { dirname, join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
collectClientPackageViolations,
|
||||
collectLocalSourceSpecifiers,
|
||||
collectRuntimeSourcePackageUses,
|
||||
collectRuntimeSourceSpecifiers,
|
||||
collectSourcePackageUses,
|
||||
@@ -106,6 +107,19 @@ describe('source package uses', () => {
|
||||
'@deepseek-ai/dsh-b/remote',
|
||||
'react',
|
||||
])
|
||||
expect([...collectLocalSourceSpecifiers('feature.ts', [
|
||||
"import type { A } from './types.ts'",
|
||||
"export { value } from './value.ts'",
|
||||
"const load = () => import('./lazy.ts')",
|
||||
"const legacy = require('./legacy.ts')",
|
||||
"declare module './augmentation.ts' {}",
|
||||
"import '@deepseek-ai/dsh-a'",
|
||||
].join('\n'))].sort()).toEqual([
|
||||
'./lazy.ts',
|
||||
'./legacy.ts',
|
||||
'./types.ts',
|
||||
'./value.ts',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -152,109 +166,6 @@ describe('package modes', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('dependency sections', () => {
|
||||
it('accepts dynamic peer plus dev relationships, static dev inputs, and private dependencies', () => {
|
||||
const slots = pkg('ui-slots', { dynamic: false, staticLinked: true })
|
||||
const conversation = pkg('conversation', {
|
||||
inject: ['@deepseek-ai/dsh-client-feature'],
|
||||
sourceUses: {
|
||||
'@deepseek-ai/dsh-agent': ['packages/client/conversation/src/index.ts'],
|
||||
'@deepseek-ai/dsh-client-ui-slots': ['packages/client/conversation/src/client/slots.ts'],
|
||||
react: ['packages/client/conversation/src/client/view.tsx'],
|
||||
},
|
||||
dependencies: { immer: '^10.1.1' },
|
||||
peerDependencies: {
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-agent': 'workspace:^',
|
||||
'@deepseek-ai/dsh-client-feature': 'workspace:^',
|
||||
},
|
||||
devDependencies: {
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-agent': 'workspace:^',
|
||||
'@deepseek-ai/dsh-client-feature': 'workspace:^',
|
||||
'@deepseek-ai/dsh-client-ui-slots': 'workspace:^',
|
||||
react: '^18.2.0',
|
||||
},
|
||||
})
|
||||
expect(collectClientPackageViolations(facts([slots, conversation], {
|
||||
platformModules: ['react', slots.name],
|
||||
}))).toEqual([])
|
||||
})
|
||||
|
||||
it('rejects internal dependencies, static peers, and mismatched peer development ranges', () => {
|
||||
const slots = pkg('ui-slots', { dynamic: false, staticLinked: true })
|
||||
const subject = pkg('feature', {
|
||||
sourceUses: {
|
||||
'@deepseek-ai/dsh-agent': ['packages/client/feature/src/index.ts'],
|
||||
[slots.name]: ['packages/client/feature/src/view.tsx'],
|
||||
},
|
||||
dependencies: { '@deepseek-ai/dsh-agent': 'workspace:^' },
|
||||
peerDependencies: { [CORDIS]: 'workspace:^', [slots.name]: 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', [slots.name]: 'workspace:*' },
|
||||
})
|
||||
const found = collectClientPackageViolations(facts([slots, subject]))
|
||||
expect(found).toHaveLength(2)
|
||||
expect(found.join('\n')).toContain('peer-installed DSH relationship')
|
||||
expect(found.join('\n')).toContain('static client input')
|
||||
})
|
||||
|
||||
it('requires every peer to have the same development range', () => {
|
||||
const subject = pkg('feature', {
|
||||
peerDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/cordis-plugin-loader': 'workspace:^' },
|
||||
})
|
||||
expect(collectClientPackageViolations(facts([subject]))).toEqual([
|
||||
'packages/client/feature/package.json: peerDependencies.@deepseek-ai/cordis-plugin-loader'
|
||||
+ ' is workspace:^, so devDependencies.@deepseek-ai/cordis-plugin-loader must use the same range;'
|
||||
+ ' found no declaration',
|
||||
])
|
||||
})
|
||||
|
||||
it('requires statically linked third-party runtime imports in dependencies', () => {
|
||||
const primitives = pkg('ui-primitives', {
|
||||
dynamic: false,
|
||||
staticLinked: true,
|
||||
runtimeSourceUses: { shiki: ['packages/client/ui-primitives/src/highlight.ts'] },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', shiki: '^4.3.1' },
|
||||
})
|
||||
const found = collectClientPackageViolations(facts([primitives]))
|
||||
expect(found).toHaveLength(1)
|
||||
expect(found[0]).toContain('runtime import retained by a statically linked artifact')
|
||||
expect(found[0]).toContain('declare it only in dependencies')
|
||||
|
||||
const valid = { ...primitives, dependencies: { shiki: '^4.3.1' }, devDependencies: { [CORDIS]: 'workspace:^' } }
|
||||
expect(collectClientPackageViolations(facts([valid]))).toEqual([])
|
||||
})
|
||||
|
||||
it('keeps the web shell runtime inputs development-only', () => {
|
||||
const web = pkg('web', {
|
||||
dynamic: false,
|
||||
staticLinked: true,
|
||||
runtimeSourceUses: {
|
||||
'@deepseek-ai/cordis-plugin-loader': ['packages/client/web/src/boot.ts'],
|
||||
react: ['packages/client/web/src/seed.ts'],
|
||||
},
|
||||
devDependencies: {
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/cordis-plugin-loader': 'workspace:^',
|
||||
react: '^18.2.0',
|
||||
},
|
||||
})
|
||||
expect(collectClientPackageViolations(facts([web]))).toEqual([])
|
||||
})
|
||||
|
||||
it('allows npm dependency cycles', () => {
|
||||
const a = pkg('a', {
|
||||
peerDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-client-b': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-client-b': 'workspace:^' },
|
||||
})
|
||||
const b = pkg('b', {
|
||||
peerDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-client-a': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-client-a': 'workspace:^' },
|
||||
})
|
||||
expect(collectClientPackageViolations(facts([a, b]))).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('module requests', () => {
|
||||
it('rejects runtime requests from one client feature package to another dynamic row', () => {
|
||||
const ui = declaration('ui', {
|
||||
@@ -378,7 +289,7 @@ describe('manifest declarations', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('fixes unambiguous dependency sections and declaration entries', () => {
|
||||
it('fixes malformed declaration entries without changing dependency sections', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'client-packages-fix-'))
|
||||
roots.push(root)
|
||||
const subject = pkg('feature', {
|
||||
@@ -426,43 +337,8 @@ describe('manifest declarations', () => {
|
||||
external: ['@deepseek-ai/dsh-missing'],
|
||||
inject: ['@deepseek-ai/dsh-agent'],
|
||||
})
|
||||
expect(fixed.dependencies).toBeUndefined()
|
||||
expect(fixed.peerDependencies).toEqual({
|
||||
'@deepseek-ai/cordis-plugin-loader': 'workspace:^',
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-agent': 'workspace:*',
|
||||
})
|
||||
expect(fixed.devDependencies).toEqual({
|
||||
'@deepseek-ai/dsh-client-ui-slots': 'workspace:^',
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-agent': 'workspace:*',
|
||||
'@deepseek-ai/cordis-plugin-loader': 'workspace:^',
|
||||
})
|
||||
})
|
||||
|
||||
it('fixes a statically linked runtime import into dependencies', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'client-packages-static-fix-'))
|
||||
roots.push(root)
|
||||
const subject = pkg('ui-primitives', {
|
||||
dynamic: false,
|
||||
staticLinked: true,
|
||||
runtimeSourceUses: { shiki: ['packages/client/ui-primitives/src/highlight.ts'] },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', shiki: '^4.3.1' },
|
||||
})
|
||||
mkdirSync(dirname(join(root, subject.manifest)), { recursive: true })
|
||||
writeFileSync(join(root, subject.manifest), JSON.stringify({
|
||||
name: subject.name,
|
||||
peerDependencies: subject.peerDependencies,
|
||||
devDependencies: subject.devDependencies,
|
||||
}))
|
||||
writeFileSync(join(root, 'package.json'), JSON.stringify({ private: true }))
|
||||
|
||||
expect(fixClientPackageManifests(root, facts([subject]))).toEqual([subject.manifest])
|
||||
const fixed = JSON.parse(readFileSync(join(root, subject.manifest), 'utf8')) as {
|
||||
dependencies: Record<string, string>
|
||||
devDependencies: Record<string, string>
|
||||
}
|
||||
expect(fixed.dependencies).toEqual({ shiki: '^4.3.1' })
|
||||
expect(fixed.devDependencies).toEqual({ [CORDIS]: 'workspace:^' })
|
||||
expect(fixed.dependencies).toEqual(subject.dependencies)
|
||||
expect(fixed.peerDependencies).toEqual(subject.peerDependencies)
|
||||
expect(fixed.devDependencies).toEqual(subject.devDependencies)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* Verify client package modes, npm dependency sections, and the synchronous
|
||||
* browser module-request graph.
|
||||
* Verify client package modes and the synchronous browser module-request graph.
|
||||
*/
|
||||
|
||||
import { globSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
@@ -17,8 +16,6 @@ const PLATFORM_SOURCE = 'packages/client/web/src/platform.ts'
|
||||
const PARSER_PRELOAD_SOURCE = 'packages/client/modules/src/index.ts'
|
||||
const STATIC_PRESET_SOURCE = 'packages/client/tsdown.client.ts'
|
||||
const CORDIS = '@deepseek-ai/cordis'
|
||||
const DSH_PREFIX = '@deepseek-ai/dsh-'
|
||||
const CLIENT_WEB = '@deepseek-ai/dsh-client-web'
|
||||
|
||||
/** One workspace package's browser-module declaration. */
|
||||
export interface ClientDeclaration {
|
||||
@@ -92,6 +89,28 @@ export function collectRuntimeSourceSpecifiers(path: string, source: string): Se
|
||||
return collectSourceFileUses(sourceFile, true, 'specifier')
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect relative module specifiers used to follow one source entry's local closure.
|
||||
* @param path - File path used to select TypeScript's parser mode.
|
||||
* @param source - Source text to inspect.
|
||||
* @returns Relative imports, exports, requires, and import types.
|
||||
*/
|
||||
export function collectLocalSourceSpecifiers(path: string, source: string): Set<string> {
|
||||
const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true)
|
||||
return collectSourceFileUses(sourceFile, false, 'local')
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect relative module specifiers retained by one production source file.
|
||||
* @param path - File path used to select TypeScript's parser mode.
|
||||
* @param source - Source text to inspect.
|
||||
* @returns Relative imports, exports, and requires that survive compilation.
|
||||
*/
|
||||
export function collectRuntimeLocalSourceSpecifiers(path: string, source: string): Set<string> {
|
||||
const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true)
|
||||
return collectSourceFileUses(sourceFile, true, 'local')
|
||||
}
|
||||
|
||||
function importCarriesRuntimeValue(node: ts.ImportDeclaration): boolean {
|
||||
const clause = node.importClause
|
||||
if (clause === undefined) return true
|
||||
@@ -114,12 +133,17 @@ function exportCarriesRuntimeValue(node: ts.ExportDeclaration): boolean {
|
||||
function collectSourceFileUses(
|
||||
sourceFile: ts.SourceFile,
|
||||
runtimeOnly: boolean,
|
||||
key: 'package' | 'specifier',
|
||||
key: 'local' | 'package' | 'specifier',
|
||||
): Set<string> {
|
||||
const uses = new Set<string>()
|
||||
|
||||
const add = (specifier: ts.Expression | undefined): void => {
|
||||
if (specifier === undefined || !ts.isStringLiteral(specifier) || !isBareSpecifier(specifier.text)) return
|
||||
if (specifier === undefined || !ts.isStringLiteralLike(specifier)) return
|
||||
if (key === 'local') {
|
||||
if (specifier.text.startsWith('.')) uses.add(specifier.text)
|
||||
return
|
||||
}
|
||||
if (!isBareSpecifier(specifier.text)) return
|
||||
uses.add(key === 'package' ? packageNameOf(specifier.text) : specifier.text)
|
||||
}
|
||||
const visit = (node: ts.Node): void => {
|
||||
@@ -135,9 +159,10 @@ function collectSourceFileUses(
|
||||
&& (node.expression.kind === ts.SyntaxKind.ImportKeyword
|
||||
|| ts.isIdentifier(node.expression) && node.expression.text === 'require')) {
|
||||
add(node.arguments[0])
|
||||
} else if (!runtimeOnly && ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) {
|
||||
} else if (!runtimeOnly && key !== 'local' && ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) {
|
||||
add(node.name)
|
||||
} else if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node)) {
|
||||
} else if (key !== 'local'
|
||||
&& (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node))) {
|
||||
uses.add('react')
|
||||
}
|
||||
ts.forEachChild(node, visit)
|
||||
@@ -170,7 +195,6 @@ export function collectClientPackageViolations(facts: ClientPackageFacts): strin
|
||||
return [
|
||||
...facts.malformed,
|
||||
...collectModeViolations(facts),
|
||||
...collectDependencyViolations(facts),
|
||||
...collectModuleViolations(facts),
|
||||
].sort((left, right) => left.localeCompare(right))
|
||||
}
|
||||
@@ -181,10 +205,8 @@ interface ManifestDocument {
|
||||
changed: boolean
|
||||
}
|
||||
|
||||
type DependencySection = 'dependencies' | 'peerDependencies' | 'devDependencies'
|
||||
|
||||
/**
|
||||
* Repair manifest declarations whose intended result follows uniquely from the policy.
|
||||
* Repair malformed or redundant `dsh.client` declaration entries.
|
||||
* @param root - Absolute repository root.
|
||||
* @param facts - Facts used by the verification pass.
|
||||
* @returns Repository-relative manifests written by the fixer.
|
||||
@@ -217,53 +239,6 @@ export function fixClientPackageManifests(root: string, facts: ClientPackageFact
|
||||
) || target.changed
|
||||
}
|
||||
|
||||
const staticInputs = new Set([
|
||||
...facts.staticLinkedPackages,
|
||||
...facts.platformModules.map(packageNameOf),
|
||||
])
|
||||
staticInputs.delete(CORDIS)
|
||||
const inferredRanges = dependencyRangeCandidates(root)
|
||||
for (const pkg of facts.packages) {
|
||||
const target = document(pkg.manifest)
|
||||
const expected = expectedSections(pkg, staticInputs)
|
||||
for (const [name, rule] of expected) {
|
||||
const range = preferredRange(target.manifest, name, rule.kind, inferredRanges)
|
||||
if (range === undefined) continue
|
||||
target.changed = rule.kind === 'dependency'
|
||||
? ensureDependencyOnly(target.manifest, name, range) || target.changed
|
||||
: rule.kind === 'dev'
|
||||
? ensureDevOnly(target.manifest, name, range) || target.changed
|
||||
: ensurePeerDev(target.manifest, name, range) || target.changed
|
||||
}
|
||||
|
||||
if (pkg.dynamic) {
|
||||
const productionNames = new Set([
|
||||
...Object.keys(section(target.manifest, 'dependencies')),
|
||||
...Object.keys(section(target.manifest, 'peerDependencies')),
|
||||
])
|
||||
for (const name of productionNames) {
|
||||
if (expected.has(name)) continue
|
||||
const range = preferredRange(
|
||||
target.manifest,
|
||||
name,
|
||||
staticInputs.has(name) ? 'dev' : 'peer-dev',
|
||||
inferredRanges,
|
||||
)
|
||||
if (range === undefined) continue
|
||||
if (staticInputs.has(name)) {
|
||||
target.changed = ensureDevOnly(target.manifest, name, range) || target.changed
|
||||
} else if (section(target.manifest, 'dependencies')[name] !== undefined && isInternalDsh(name)) {
|
||||
target.changed = ensurePeerDev(target.manifest, name, range) || target.changed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [name, range] of Object.entries(section(target.manifest, 'peerDependencies'))) {
|
||||
target.changed = setDependency(target.manifest, 'devDependencies', name, range) || target.changed
|
||||
}
|
||||
target.changed = deleteEmptySections(target.manifest) || target.changed
|
||||
}
|
||||
|
||||
const changed = [...documents.values()].filter(target => target.changed).sort((left, right) =>
|
||||
left.path.localeCompare(right.path))
|
||||
for (const target of changed) {
|
||||
@@ -295,102 +270,6 @@ function normalizeClientArray(
|
||||
return true
|
||||
}
|
||||
|
||||
function ensureDevOnly(manifest: Manifest, name: string, range: string): boolean {
|
||||
let changed = deleteDependency(manifest, 'dependencies', name)
|
||||
changed = deleteDependency(manifest, 'peerDependencies', name) || changed
|
||||
return setDependency(manifest, 'devDependencies', name, range) || changed
|
||||
}
|
||||
|
||||
function ensureDependencyOnly(manifest: Manifest, name: string, range: string): boolean {
|
||||
let changed = deleteDependency(manifest, 'peerDependencies', name)
|
||||
changed = deleteDependency(manifest, 'devDependencies', name) || changed
|
||||
return setDependency(manifest, 'dependencies', name, range) || changed
|
||||
}
|
||||
|
||||
function ensurePeerDev(manifest: Manifest, name: string, range: string): boolean {
|
||||
let changed = deleteDependency(manifest, 'dependencies', name)
|
||||
changed = setDependency(manifest, 'peerDependencies', name, range) || changed
|
||||
return setDependency(manifest, 'devDependencies', name, range) || changed
|
||||
}
|
||||
|
||||
function setDependency(manifest: Manifest, field: DependencySection, name: string, range: string): boolean {
|
||||
const dependencies = mutableSection(manifest, field)
|
||||
if (dependencies[name] === range) return false
|
||||
dependencies[name] = range
|
||||
return true
|
||||
}
|
||||
|
||||
function deleteDependency(manifest: Manifest, field: DependencySection, name: string): boolean {
|
||||
const dependencies = section(manifest, field)
|
||||
if (dependencies[name] === undefined) return false
|
||||
manifest[field] = Object.fromEntries(Object.entries(dependencies).filter(([key]) => key !== name))
|
||||
return true
|
||||
}
|
||||
|
||||
function deleteEmptySections(manifest: Manifest): boolean {
|
||||
let changed = false
|
||||
for (const field of ['dependencies', 'peerDependencies', 'devDependencies'] as const) {
|
||||
if (manifest[field] === undefined || Object.keys(section(manifest, field)).length > 0) continue
|
||||
if (field === 'dependencies') delete manifest.dependencies
|
||||
else if (field === 'peerDependencies') delete manifest.peerDependencies
|
||||
else delete manifest.devDependencies
|
||||
changed = true
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
function preferredRange(
|
||||
manifest: Manifest,
|
||||
name: string,
|
||||
kind: ExpectedRule['kind'],
|
||||
inferred: ReadonlyMap<string, ReadonlySet<string>>,
|
||||
): string | undefined {
|
||||
const order: readonly DependencySection[] = kind === 'dependency'
|
||||
? ['dependencies', 'devDependencies', 'peerDependencies']
|
||||
: kind === 'dev'
|
||||
? ['devDependencies', 'peerDependencies', 'dependencies']
|
||||
: ['peerDependencies', 'devDependencies', 'dependencies']
|
||||
for (const field of order) {
|
||||
const range = section(manifest, field)[name]
|
||||
if (range !== undefined) return range
|
||||
}
|
||||
if (isInternalDsh(name)) return 'workspace:^'
|
||||
const candidates = inferred.get(name)
|
||||
return candidates?.size === 1 ? [...candidates][0] : undefined
|
||||
}
|
||||
|
||||
function dependencyRangeCandidates(root: string): Map<string, Set<string>> {
|
||||
const candidates = new Map<string, Set<string>>()
|
||||
const paths = globSync([
|
||||
'package.json',
|
||||
...MANIFEST_GLOBS,
|
||||
'website/package.json',
|
||||
], { cwd: root }).map(normalizePath)
|
||||
for (const path of new Set(paths)) {
|
||||
const manifest = JSON.parse(readFileSync(resolve(root, path), 'utf8')) as Manifest
|
||||
for (const field of ['dependencies', 'peerDependencies', 'devDependencies'] as const) {
|
||||
for (const [name, range] of Object.entries(section(manifest, field))) {
|
||||
const ranges = candidates.get(name) ?? new Set<string>()
|
||||
ranges.add(range)
|
||||
candidates.set(name, ranges)
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
function section(manifest: Manifest, field: DependencySection): Record<string, string> {
|
||||
return manifest[field] ?? {}
|
||||
}
|
||||
|
||||
function mutableSection(manifest: Manifest, field: DependencySection): Record<string, string> {
|
||||
const value = manifest[field]
|
||||
if (value !== undefined) return value
|
||||
const created: Record<string, string> = {}
|
||||
manifest[field] = created
|
||||
return created
|
||||
}
|
||||
|
||||
function collectModeViolations(facts: ClientPackageFacts): string[] {
|
||||
const violations: string[] = []
|
||||
for (const pkg of facts.packages) {
|
||||
@@ -435,114 +314,6 @@ function collectModeViolations(facts: ClientPackageFacts): string[] {
|
||||
return violations
|
||||
}
|
||||
|
||||
interface ExpectedRule {
|
||||
readonly kind: 'dependency' | 'dev' | 'peer-dev'
|
||||
readonly origins: Set<string>
|
||||
}
|
||||
|
||||
function collectDependencyViolations(facts: ClientPackageFacts): string[] {
|
||||
const violations: string[] = []
|
||||
const staticInputs = new Set([
|
||||
...facts.staticLinkedPackages,
|
||||
...facts.platformModules.map(packageNameOf),
|
||||
])
|
||||
staticInputs.delete(CORDIS)
|
||||
|
||||
for (const pkg of [...facts.packages].sort((left, right) => left.manifest.localeCompare(right.manifest))) {
|
||||
const expected = expectedSections(pkg, staticInputs)
|
||||
for (const [name, rule] of [...expected].sort(([left], [right]) => left.localeCompare(right))) {
|
||||
const actual = declaredSections(pkg, name)
|
||||
if (rule.kind === 'dependency') {
|
||||
if (actual.length === 1 && actual[0] === 'dependencies') continue
|
||||
violations.push(
|
||||
pkg.manifest + ': ' + name + ' (' + describeOrigins(rule.origins) + ') is a runtime import'
|
||||
+ ' retained by a statically linked artifact; declare it only in dependencies, found '
|
||||
+ describeSections(actual),
|
||||
)
|
||||
continue
|
||||
}
|
||||
if (rule.kind === 'dev') {
|
||||
if (actual.length === 1 && actual[0] === 'devDependencies') continue
|
||||
violations.push(
|
||||
pkg.manifest + ': ' + name + ' (' + describeOrigins(rule.origins) + ') is a static client input;'
|
||||
+ ' declare it only in devDependencies, found ' + describeSections(actual),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
const peerRange = pkg.peerDependencies[name]
|
||||
const devRange = pkg.devDependencies[name]
|
||||
if (actual.length === 2
|
||||
&& actual.includes('peerDependencies')
|
||||
&& actual.includes('devDependencies')
|
||||
&& peerRange === devRange) continue
|
||||
violations.push(
|
||||
pkg.manifest + ': ' + name + ' (' + describeOrigins(rule.origins) + ')'
|
||||
+ ' is a peer-installed DSH relationship; declare it in peerDependencies and devDependencies'
|
||||
+ ' with matching ranges, not dependencies; found ' + describeSections(actual)
|
||||
+ describeRangeMismatch(peerRange, devRange),
|
||||
)
|
||||
}
|
||||
|
||||
for (const [name, peerRange] of Object.entries(pkg.peerDependencies).sort(([left], [right]) => left.localeCompare(right))) {
|
||||
if (expected.has(name)) continue
|
||||
const devRange = pkg.devDependencies[name]
|
||||
if (devRange === peerRange) continue
|
||||
violations.push(
|
||||
pkg.manifest + ': peerDependencies.' + name + ' is ' + peerRange + ', so devDependencies.' + name
|
||||
+ ' must use the same range; found ' + (devRange ?? 'no declaration'),
|
||||
)
|
||||
}
|
||||
|
||||
if (!pkg.dynamic) continue
|
||||
for (const section of ['dependencies', 'peerDependencies'] as const) {
|
||||
for (const name of Object.keys(pkg[section]).sort()) {
|
||||
if (expected.has(name)) continue
|
||||
if (staticInputs.has(name)) {
|
||||
violations.push(
|
||||
pkg.manifest + ': dynamic package declares static input ' + name + ' in ' + section + ';'
|
||||
+ ' move it to devDependencies or delete the stale declaration',
|
||||
)
|
||||
} else if (section === 'dependencies' && isInternalDsh(name)) {
|
||||
violations.push(
|
||||
pkg.manifest + ': dynamic package declares ' + name + ' in dependencies;'
|
||||
+ ' dynamic DSH relationships are peer plus dev, and static client inputs are dev-only',
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
function expectedSections(pkg: ClientPackage, staticInputs: ReadonlySet<string>): Map<string, ExpectedRule> {
|
||||
const expected = new Map<string, ExpectedRule>([
|
||||
[CORDIS, { kind: 'peer-dev', origins: new Set(['client package baseline']) }],
|
||||
])
|
||||
if (!pkg.dynamic) {
|
||||
if (pkg.name === CLIENT_WEB) return expected
|
||||
for (const [name, locations] of Object.entries(pkg.runtimeSourceUses)) {
|
||||
if (name === pkg.name || name === CORDIS || isInternalDsh(name)) continue
|
||||
expected.set(name, { kind: 'dependency', origins: new Set(locations) })
|
||||
}
|
||||
return expected
|
||||
}
|
||||
|
||||
const add = (name: string, origin: string): void => {
|
||||
if (name === pkg.name) return
|
||||
const kind = staticInputs.has(name) ? 'dev' : isInternalDsh(name) ? 'peer-dev' : undefined
|
||||
if (kind === undefined) return
|
||||
const current = expected.get(name)
|
||||
if (current !== undefined) current.origins.add(origin)
|
||||
else expected.set(name, { kind, origins: new Set([origin]) })
|
||||
}
|
||||
for (const [name, locations] of Object.entries(pkg.sourceUses)) {
|
||||
for (const location of locations) add(name, location)
|
||||
}
|
||||
for (const name of pkg.inject) add(name, 'dsh.client.inject')
|
||||
return expected
|
||||
}
|
||||
|
||||
interface ModuleEdge {
|
||||
readonly from: string
|
||||
readonly to: string
|
||||
@@ -895,32 +666,6 @@ function rowPackageOf(specifier: string, rows: ReadonlySet<string>): string | un
|
||||
return rows.has(stripped) ? stripped : undefined
|
||||
}
|
||||
|
||||
function declaredSections(pkg: ClientPackage, name: string): string[] {
|
||||
return (['dependencies', 'peerDependencies', 'devDependencies'] as const)
|
||||
.filter(section => pkg[section][name] !== undefined)
|
||||
}
|
||||
|
||||
function describeSections(sections: readonly string[]): string {
|
||||
return sections.length === 0 ? 'no dependency declaration' : sections.join(' + ')
|
||||
}
|
||||
|
||||
function describeRangeMismatch(peer: string | undefined, dev: string | undefined): string {
|
||||
if (peer === undefined || dev === undefined || peer === dev) return ''
|
||||
return ' (peer ' + peer + ', dev ' + dev + ')'
|
||||
}
|
||||
|
||||
function describeOrigins(origins: ReadonlySet<string>): string {
|
||||
const sorted = [...origins].sort()
|
||||
const [first, second, ...rest] = sorted
|
||||
if (first === undefined) return 'production use'
|
||||
if (second === undefined) return first
|
||||
return rest.length === 0 ? first + ', ' + second : first + ', ' + second + ', and ' + String(rest.length) + ' more'
|
||||
}
|
||||
|
||||
function isInternalDsh(name: string): boolean {
|
||||
return name === CORDIS || name.startsWith(DSH_PREFIX)
|
||||
}
|
||||
|
||||
function isBareSpecifier(specifier: string): boolean {
|
||||
return !specifier.startsWith('.') && !specifier.startsWith('/') && !specifier.startsWith('#')
|
||||
}
|
||||
@@ -956,7 +701,7 @@ async function main(): Promise<void> {
|
||||
const requests = facts.declarations.reduce((total, pkg) => total + pkg.external.length, 0)
|
||||
console.log(
|
||||
GATE + ': ' + String(facts.packages.length) + ' client packages (' + String(dynamic) + ' dynamic, '
|
||||
+ String(facts.packages.length - dynamic) + ' statically linked) satisfy dependency and module-request rules; '
|
||||
+ String(facts.packages.length - dynamic) + ' statically linked) satisfy package-mode and module-request rules; '
|
||||
+ String(requests) + ' explicit external request(s).',
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { NpmPackageLock, RegistryIndex } from './benchmark-npm-resolution.ts'
|
||||
import {
|
||||
assertDualDshInstallLayout,
|
||||
buildDualDshRegistry,
|
||||
} from './verify-npm-install-layout.ts'
|
||||
|
||||
function validLayout(): NpmPackageLock {
|
||||
return {
|
||||
lockfileVersion: 3,
|
||||
packages: {
|
||||
'': { dependencies: { '@deepseek-ai/dsh': '0.2.0', 'dsh-previous': 'npm:@deepseek-ai/dsh@0.1.0' } },
|
||||
'node_modules/@deepseek-ai/cordis': { version: '4.0.1' },
|
||||
'node_modules/@deepseek-ai/dsh': {
|
||||
version: '0.2.0',
|
||||
dependencies: { '@deepseek-ai/dsh-child': '^0.2.0' },
|
||||
peerDependencies: { '@deepseek-ai/cordis': '^4.0.1' },
|
||||
},
|
||||
'node_modules/@deepseek-ai/dsh-child': {
|
||||
version: '0.2.0',
|
||||
dependencies: { '@deepseek-ai/dsh-leaf': '^0.2.0' },
|
||||
},
|
||||
'node_modules/@deepseek-ai/dsh-leaf': { version: '0.2.0' },
|
||||
'node_modules/dsh-previous': {
|
||||
name: '@deepseek-ai/dsh',
|
||||
version: '0.1.0',
|
||||
dependencies: { '@deepseek-ai/dsh-child': '^0.1.0' },
|
||||
peerDependencies: { '@deepseek-ai/cordis': '^4.0.1' },
|
||||
},
|
||||
'node_modules/dsh-previous/node_modules/@deepseek-ai/dsh-child': {
|
||||
version: '0.1.0',
|
||||
dependencies: { '@deepseek-ai/dsh-leaf': '^0.1.0' },
|
||||
},
|
||||
'node_modules/dsh-previous/node_modules/@deepseek-ai/dsh-leaf': { version: '0.1.0' },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
describe('npm install layout verifier', () => {
|
||||
it('creates two incompatible versions of every DSH package', () => {
|
||||
const index: RegistryIndex = new Map([
|
||||
['@deepseek-ai/dsh', new Map([['0.1.1-rc.2', {
|
||||
name: '@deepseek-ai/dsh',
|
||||
version: '0.1.1-rc.2',
|
||||
dependencies: { '@deepseek-ai/dsh-child': '^0.1.1-rc.2' },
|
||||
peerDependencies: { '@deepseek-ai/cordis': '^4.0.1' },
|
||||
}]])],
|
||||
['@deepseek-ai/dsh-child', new Map([['0.1.1-rc.2', {
|
||||
name: '@deepseek-ai/dsh-child',
|
||||
version: '0.1.1-rc.2',
|
||||
}]])],
|
||||
['@deepseek-ai/cordis', new Map([['4.0.1', {
|
||||
name: '@deepseek-ai/cordis',
|
||||
version: '4.0.1',
|
||||
}]])],
|
||||
])
|
||||
|
||||
const dual = buildDualDshRegistry(index, '0.1.1-rc.2')
|
||||
|
||||
expect([...dual.get('@deepseek-ai/dsh')?.keys() ?? []]).toEqual(['0.1.0', '0.2.0'])
|
||||
expect(dual.get('@deepseek-ai/dsh')?.get('0.1.0')).toMatchObject({
|
||||
version: '0.1.0',
|
||||
dependencies: { '@deepseek-ai/dsh-child': '^0.1.0' },
|
||||
peerDependencies: { '@deepseek-ai/cordis': '^4.0.1' },
|
||||
})
|
||||
expect(dual.get('@deepseek-ai/dsh')?.get('0.2.0')).toMatchObject({
|
||||
version: '0.2.0',
|
||||
dependencies: { '@deepseek-ai/dsh-child': '^0.2.0' },
|
||||
})
|
||||
expect(dual.get('@deepseek-ai/cordis')).toBe(index.get('@deepseek-ai/cordis'))
|
||||
})
|
||||
|
||||
it('accepts isolated DSH releases with one shared Cordis installation', () => {
|
||||
expect(assertDualDshInstallLayout(validLayout())).toEqual({
|
||||
dshPackagesPerVersion: 3,
|
||||
checkedDshEdges: 4,
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects an internal edge that crosses release versions', () => {
|
||||
const layout = validLayout()
|
||||
const packages = { ...layout.packages }
|
||||
Reflect.deleteProperty(packages, 'node_modules/dsh-previous/node_modules/@deepseek-ai/dsh-leaf')
|
||||
|
||||
expect(() => assertDualDshInstallLayout({ ...layout, packages })).toThrow(
|
||||
'node_modules/dsh-previous/node_modules/@deepseek-ai/dsh-child: dependencies '
|
||||
+ '@deepseek-ai/dsh-leaf resolves to node_modules/@deepseek-ai/dsh-leaf@0.2.0, expected 0.1.0',
|
||||
)
|
||||
})
|
||||
|
||||
it('rejects a second Cordis installation', () => {
|
||||
const layout = validLayout()
|
||||
const packages = {
|
||||
...layout.packages,
|
||||
'node_modules/dsh-previous/node_modules/@deepseek-ai/cordis': { version: '4.0.1' },
|
||||
}
|
||||
|
||||
expect(() => assertDualDshInstallLayout({ ...layout, packages })).toThrow(
|
||||
'expected one shared @deepseek-ai/cordis',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,217 @@
|
||||
/** Verify npm's physical package placement for two incompatible DSH releases. */
|
||||
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { posix, resolve } from 'node:path'
|
||||
import {
|
||||
buildRegistryIndex,
|
||||
resolveNpmPackageLock,
|
||||
type NpmLockPackage,
|
||||
type NpmPackageLock,
|
||||
type RegistryIndex,
|
||||
} from './benchmark-npm-resolution.ts'
|
||||
|
||||
const DSH_PACKAGE = '@deepseek-ai/dsh'
|
||||
const CORDIS_PACKAGE = '@deepseek-ai/cordis'
|
||||
const NESTED_DSH_ALIAS = 'dsh-previous'
|
||||
const NESTED_DSH_PATH = `node_modules/${NESTED_DSH_ALIAS}`
|
||||
const DEPENDENCY_FIELDS = ['dependencies', 'optionalDependencies', 'peerDependencies'] as const
|
||||
const TIMEOUT_MS = 300_000
|
||||
|
||||
/** Synthetic incompatible versions used to expose cross-release placement errors. */
|
||||
export const SYNTHETIC_DSH_VERSIONS = ['0.1.0', '0.2.0'] as const
|
||||
|
||||
interface MutableRegistryManifest {
|
||||
name: string
|
||||
version: string
|
||||
dependencies?: Record<string, string>
|
||||
optionalDependencies?: Record<string, string>
|
||||
peerDependencies?: Record<string, string>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** Summary of a verified two-release npm layout. */
|
||||
export interface DshInstallLayoutSummary {
|
||||
readonly dshPackagesPerVersion: number
|
||||
readonly checkedDshEdges: number
|
||||
}
|
||||
|
||||
function isDshPackage(name: string): boolean {
|
||||
return name === DSH_PACKAGE || name.startsWith(`${DSH_PACKAGE}-`)
|
||||
}
|
||||
|
||||
function cloneForVersion(manifest: object, version: string): MutableRegistryManifest {
|
||||
const cloned = structuredClone(manifest) as MutableRegistryManifest
|
||||
cloned.version = version
|
||||
for (const field of DEPENDENCY_FIELDS) {
|
||||
const dependencies = cloned[field]
|
||||
if (dependencies === undefined) continue
|
||||
for (const name of Object.keys(dependencies)) {
|
||||
if (isDshPackage(name)) dependencies[name] = `^${version}`
|
||||
}
|
||||
}
|
||||
return cloned
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the working release with two incompatible, internally consistent DSH releases.
|
||||
* @param index - Registry metadata containing the working release.
|
||||
* @param sourceVersion - Workspace version copied into each synthetic release.
|
||||
* @returns Registry metadata containing both synthetic DSH releases and unchanged external packages.
|
||||
*/
|
||||
export function buildDualDshRegistry(index: RegistryIndex, sourceVersion: string): RegistryIndex {
|
||||
const output = new Map(index)
|
||||
let dshPackages = 0
|
||||
for (const [name, versions] of index) {
|
||||
if (!isDshPackage(name)) {
|
||||
output.set(name, versions)
|
||||
continue
|
||||
}
|
||||
const source = versions.get(sourceVersion)
|
||||
if (source === undefined) throw new Error(`${name} has no workspace version ${sourceVersion}`)
|
||||
dshPackages++
|
||||
output.set(name, new Map(SYNTHETIC_DSH_VERSIONS.map(version => [
|
||||
version,
|
||||
cloneForVersion(source, version),
|
||||
])))
|
||||
}
|
||||
if (dshPackages === 0) throw new Error('registry contains no DSH packages')
|
||||
return output
|
||||
}
|
||||
|
||||
function packageNameAtPath(path: string, manifest: NpmLockPackage): string | undefined {
|
||||
if (manifest.name !== undefined) return manifest.name
|
||||
const marker = 'node_modules/'
|
||||
const markerIndex = path.lastIndexOf(marker)
|
||||
if (markerIndex < 0) return undefined
|
||||
const segments = path.slice(markerIndex + marker.length).split('/')
|
||||
if (segments[0]?.startsWith('@')) {
|
||||
return segments[1] === undefined ? undefined : `${segments[0]}/${segments[1]}`
|
||||
}
|
||||
return segments[0]
|
||||
}
|
||||
|
||||
function resolvePackagePath(
|
||||
packages: Readonly<Record<string, NpmLockPackage>>,
|
||||
sourcePath: string,
|
||||
dependency: string,
|
||||
): string | undefined {
|
||||
let directory = sourcePath
|
||||
while (directory !== '.') {
|
||||
const candidate = posix.join(directory, 'node_modules', dependency)
|
||||
if (packages[candidate] !== undefined) return candidate
|
||||
directory = posix.dirname(directory)
|
||||
}
|
||||
const rootCandidate = posix.join('node_modules', dependency)
|
||||
return packages[rootCandidate] === undefined ? undefined : rootCandidate
|
||||
}
|
||||
|
||||
function setDifference(left: ReadonlySet<string>, right: ReadonlySet<string>): string[] {
|
||||
return [...left].filter(value => !right.has(value)).sort()
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that npm isolates both DSH releases while sharing the Cordis runtime.
|
||||
* @param packageLock - Metadata-only package lock produced by npm.
|
||||
* @returns Counts for the verified DSH packages and dependency edges.
|
||||
*/
|
||||
export function assertDualDshInstallLayout(packageLock: NpmPackageLock): DshInstallLayoutSummary {
|
||||
const [nestedVersion, rootVersion] = SYNTHETIC_DSH_VERSIONS
|
||||
const errors: string[] = []
|
||||
const namesByVersion = new Map<string, Set<string>>([
|
||||
[nestedVersion, new Set()],
|
||||
[rootVersion, new Set()],
|
||||
])
|
||||
const installed = Object.entries(packageLock.packages)
|
||||
let checkedDshEdges = 0
|
||||
|
||||
for (const [path, manifest] of installed) {
|
||||
const name = packageNameAtPath(path, manifest)
|
||||
if (name === undefined || !isDshPackage(name)) continue
|
||||
const version = manifest.version
|
||||
if (version !== nestedVersion && version !== rootVersion) {
|
||||
errors.push(`${path}: expected DSH version ${nestedVersion} or ${rootVersion}, got ${String(version)}`)
|
||||
continue
|
||||
}
|
||||
namesByVersion.get(version)?.add(name)
|
||||
const expectedPath = version === rootVersion
|
||||
? `node_modules/${name}`
|
||||
: name === DSH_PACKAGE
|
||||
? NESTED_DSH_PATH
|
||||
: `${NESTED_DSH_PATH}/node_modules/${name}`
|
||||
if (path !== expectedPath) {
|
||||
errors.push(`${path}: expected ${name}@${version} at ${expectedPath}`)
|
||||
}
|
||||
|
||||
for (const field of DEPENDENCY_FIELDS) {
|
||||
for (const dependency of Object.keys(manifest[field] ?? {})) {
|
||||
if (!isDshPackage(dependency)) continue
|
||||
const targetPath = resolvePackagePath(packageLock.packages, path, dependency)
|
||||
const optionalPeer = field === 'peerDependencies'
|
||||
&& manifest.peerDependenciesMeta?.[dependency]?.optional === true
|
||||
if (targetPath === undefined) {
|
||||
if (field === 'optionalDependencies' || optionalPeer) continue
|
||||
errors.push(`${path}: ${field} ${dependency} does not resolve`)
|
||||
continue
|
||||
}
|
||||
checkedDshEdges++
|
||||
const targetVersion = packageLock.packages[targetPath]?.version
|
||||
if (targetVersion !== version) {
|
||||
errors.push(
|
||||
`${path}: ${field} ${dependency} resolves to ${targetPath}@${String(targetVersion)}, expected ${version}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nestedNames = namesByVersion.get(nestedVersion) ?? new Set<string>()
|
||||
const rootNames = namesByVersion.get(rootVersion) ?? new Set<string>()
|
||||
if (!nestedNames.has(DSH_PACKAGE)) errors.push(`${NESTED_DSH_PATH}: missing ${DSH_PACKAGE}@${nestedVersion}`)
|
||||
if (!rootNames.has(DSH_PACKAGE)) errors.push(`node_modules/${DSH_PACKAGE}: missing ${DSH_PACKAGE}@${rootVersion}`)
|
||||
const onlyNested = setDifference(nestedNames, rootNames)
|
||||
const onlyRoot = setDifference(rootNames, nestedNames)
|
||||
if (onlyNested.length > 0) errors.push(`only ${nestedVersion} contains: ${onlyNested.join(', ')}`)
|
||||
if (onlyRoot.length > 0) errors.push(`only ${rootVersion} contains: ${onlyRoot.join(', ')}`)
|
||||
|
||||
const cordisPaths = installed.flatMap(([path, manifest]) =>
|
||||
packageNameAtPath(path, manifest) === CORDIS_PACKAGE ? [path] : [])
|
||||
if (cordisPaths.length !== 1 || cordisPaths[0] !== `node_modules/${CORDIS_PACKAGE}`) {
|
||||
errors.push(`expected one shared ${CORDIS_PACKAGE} at node_modules/${CORDIS_PACKAGE}, got ${cordisPaths.join(', ')}`)
|
||||
}
|
||||
|
||||
if (errors.length > 0) throw new Error(`invalid npm install layout:\n${errors.map(error => ` - ${error}`).join('\n')}`)
|
||||
return { dshPackagesPerVersion: rootNames.size, checkedDshEdges }
|
||||
}
|
||||
|
||||
function workspaceVersion(root: string): string {
|
||||
const manifest = JSON.parse(readFileSync(resolve(root, 'apps/cli/package.json'), 'utf8')) as { version?: unknown }
|
||||
if (typeof manifest.version !== 'string') throw new Error('apps/cli/package.json has no string version')
|
||||
return manifest.version
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const index = buildDualDshRegistry(buildRegistryIndex(root), workspaceVersion(root))
|
||||
const [nestedVersion, rootVersion] = SYNTHETIC_DSH_VERSIONS
|
||||
const result = await resolveNpmPackageLock(index, {
|
||||
[DSH_PACKAGE]: rootVersion,
|
||||
[NESTED_DSH_ALIAS]: `npm:${DSH_PACKAGE}@${nestedVersion}`,
|
||||
}, TIMEOUT_MS)
|
||||
if (result.archiveRequests !== 0) throw new Error(`npm requested ${String(result.archiveRequests)} package archive(s)`)
|
||||
const summary = assertDualDshInstallLayout(result.packageLock)
|
||||
console.log(
|
||||
`verify-npm-install-layout: ${String(summary.dshPackagesPerVersion)} DSH package(s) per release and `
|
||||
+ `${String(summary.checkedDshEdges)} internal edge(s) verified in ${(result.durationMs / 1000).toFixed(2)} s; `
|
||||
+ `both releases share one Cordis installation; ${String(result.unknownPackages.length)} unavailable optional `
|
||||
+ 'package name(s) ignored by npm.',
|
||||
)
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
try {
|
||||
await main()
|
||||
} catch (error) {
|
||||
console.error(`verify-npm-install-layout: ${error instanceof Error ? error.message : String(error)}`)
|
||||
process.exitCode = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,528 @@
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
PACKAGE_DEPENDENCY_POLICY,
|
||||
type PackageDependencyPolicy,
|
||||
} from './package-dependency-policy.ts'
|
||||
import {
|
||||
collectHostDependencyExportPolicyViolations,
|
||||
collectPackageDependencyViolations,
|
||||
collectRuntimeSourceExportUses,
|
||||
discoverPackageDependencyScope,
|
||||
fixPackageDependencies,
|
||||
formatManagedRuntimeDependencies,
|
||||
formatPeerRequiredRuntimeDependencies,
|
||||
readPackageDependencyFacts,
|
||||
repairPackageDependencyManifest,
|
||||
type PackageDependencyFacts,
|
||||
type PackageDependencyManifest,
|
||||
type WorkspacePackageManifest,
|
||||
} from './verify-package-dependencies.ts'
|
||||
|
||||
const CORDIS = '@deepseek-ai/cordis'
|
||||
const roots: string[] = []
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
function pkg(
|
||||
name: string,
|
||||
manifestPath: string,
|
||||
manifest: Partial<PackageDependencyManifest> = {},
|
||||
): WorkspacePackageManifest {
|
||||
return {
|
||||
name,
|
||||
manifestPath,
|
||||
dir: dirname(manifestPath),
|
||||
manifest: { name, ...manifest },
|
||||
}
|
||||
}
|
||||
|
||||
function policy(fields: Partial<PackageDependencyPolicy> = {}): PackageDependencyPolicy {
|
||||
return {
|
||||
clientFaceInclude: [],
|
||||
clientFaceExclude: [],
|
||||
hostPackages: [],
|
||||
configurationOnlyDevDependencies: {},
|
||||
safeHostDependencyExports: {},
|
||||
peerRequiredHostExports: {},
|
||||
...fields,
|
||||
}
|
||||
}
|
||||
|
||||
function facts(manifest: PackageDependencyManifest): PackageDependencyFacts {
|
||||
return {
|
||||
manifestPath: 'packages/core/probe/package.json',
|
||||
role: 'configured-host',
|
||||
manifest,
|
||||
workspaceNames: new Set([
|
||||
CORDIS,
|
||||
'@deepseek-ai/dsh-runtime',
|
||||
'@deepseek-ai/dsh-types',
|
||||
'@deepseek-ai/dsh-stale',
|
||||
'@deepseek-ai/schemastery',
|
||||
]),
|
||||
allSourceUses: new Map([
|
||||
['@deepseek-ai/dsh-runtime', ['packages/core/probe/src/index.ts']],
|
||||
['@deepseek-ai/dsh-types', ['packages/core/probe/src/types.ts']],
|
||||
]),
|
||||
hostRuntimeSourceUses: new Map([
|
||||
['@deepseek-ai/dsh-runtime', ['packages/core/probe/src/index.ts']],
|
||||
]),
|
||||
hostRuntimeExportUses: [{
|
||||
packageName: '@deepseek-ai/dsh-runtime',
|
||||
specifier: '@deepseek-ai/dsh-runtime',
|
||||
exportName: 'runtimeValue',
|
||||
sourcePath: 'packages/core/probe/src/index.ts',
|
||||
line: 1,
|
||||
column: 10,
|
||||
sourceLine: "import { runtimeValue } from '@deepseek-ai/dsh-runtime'",
|
||||
}],
|
||||
peerRequiredHostDependencies: new Set(),
|
||||
configurationOnlyDevDependencies: new Set(),
|
||||
clientInject: new Set(),
|
||||
}
|
||||
}
|
||||
|
||||
describe('package dependency scope', () => {
|
||||
it('keeps the measured Host relay roster explicit', () => {
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.clientFaceExclude).toEqual([
|
||||
'@deepseek-ai/dsh-api-session-controller',
|
||||
'@deepseek-ai/dsh-api-workspace-controller',
|
||||
])
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.hostPackages).toEqual([
|
||||
'@deepseek-ai/dsh-llm',
|
||||
'@deepseek-ai/dsh-session',
|
||||
])
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.configurationOnlyDevDependencies).toEqual({
|
||||
'@deepseek-ai/dsh-client-locale': ['@deepseek-ai/dsh-api-remotes'],
|
||||
'@deepseek-ai/dsh-client-ui-conversation': [
|
||||
'@deepseek-ai/dsh-api-remotes',
|
||||
'@deepseek-ai/dsh-client-ui-workspace',
|
||||
],
|
||||
'@deepseek-ai/dsh-client-ui-model-selection': ['@deepseek-ai/dsh-client-ui-input-trigger'],
|
||||
'@deepseek-ai/dsh-client-ui-sidebar': ['@deepseek-ai/dsh-client-ui-workspace'],
|
||||
'@deepseek-ai/dsh-client-ui-subagent': ['@deepseek-ai/dsh-client-ui-input-trigger'],
|
||||
'@deepseek-ai/dsh-client-ui-theme': ['@deepseek-ai/dsh-api-remotes'],
|
||||
'@deepseek-ai/dsh-client-ui-tool': ['@deepseek-ai/dsh-api-remotes'],
|
||||
})
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.safeHostDependencyExports['@deepseek-ai/schemastery']).toEqual(['default'])
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.safeHostDependencyExports['@deepseek-ai/dsh-session/types']).toEqual([
|
||||
'SessionId',
|
||||
])
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.safeHostDependencyExports['@deepseek-ai/dsh-typert-protocol']).toEqual([
|
||||
'RemoteError', 'remoteErrorOf',
|
||||
])
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.peerRequiredHostExports['@deepseek-ai/dsh-scope']).toEqual([
|
||||
'carrierKeyOf', 'scopeOf', 'scopeTarget',
|
||||
])
|
||||
expect(PACKAGE_DEPENDENCY_POLICY.peerRequiredHostExports['@deepseek-ai/dsh-typert-protocol']).toEqual([
|
||||
'Remote', 'TypertRemoteService', 'remoteMethods',
|
||||
])
|
||||
})
|
||||
|
||||
it('discovers the Client directory, dsh.client declarations, and configured Host packages', () => {
|
||||
const packages = [
|
||||
pkg('@f/static', 'packages/client/static/package.json'),
|
||||
pkg('@f/dynamic-client', 'packages/client/dynamic/package.json', { dsh: { client: {} } }),
|
||||
pkg('@f/dual', 'packages/api/dual/package.json', { dsh: { client: {} } }),
|
||||
pkg('@f/export-only', 'packages/api/export-only/package.json', { exports: { './client': './lib/client.js' } }),
|
||||
pkg('@f/forced-client', 'packages/api/forced/package.json'),
|
||||
pkg('@f/excluded', 'packages/api/excluded/package.json', { dsh: { client: {} } }),
|
||||
pkg('@f/host', 'packages/core/host/package.json'),
|
||||
]
|
||||
|
||||
const found = discoverPackageDependencyScope(packages, policy({
|
||||
clientFaceInclude: ['@f/forced-client'],
|
||||
clientFaceExclude: ['@f/excluded'],
|
||||
hostPackages: ['@f/host'],
|
||||
}))
|
||||
|
||||
expect(found.violations).toEqual([])
|
||||
expect(found.selected.map(item => [item.name, item.role])).toEqual([
|
||||
['@f/dual', 'client-host'],
|
||||
['@f/forced-client', 'client-host'],
|
||||
['@f/dynamic-client', 'client-host'],
|
||||
['@f/static', 'client-only'],
|
||||
['@f/host', 'configured-host'],
|
||||
])
|
||||
})
|
||||
|
||||
it('rejects stale, redundant, overlapping, and unknown configuration', () => {
|
||||
const packages = [
|
||||
pkg('@f/client', 'packages/client/client/package.json'),
|
||||
pkg('@f/dual', 'packages/api/dual/package.json', { dsh: { client: {} } }),
|
||||
pkg('@f/host', 'packages/core/host/package.json'),
|
||||
]
|
||||
const found = discoverPackageDependencyScope(packages, policy({
|
||||
clientFaceInclude: ['@f/dual', '@f/missing', '@f/host'],
|
||||
clientFaceExclude: ['@f/client', '@f/host', '@f/missing'],
|
||||
hostPackages: ['@f/dual'],
|
||||
}))
|
||||
|
||||
expect(found.violations).toEqual(expect.arrayContaining([
|
||||
expect.stringContaining('clientFaceInclude redundantly names automatically discovered package @f/dual'),
|
||||
expect.stringContaining('@f/host appears in both clientFaceInclude and clientFaceExclude'),
|
||||
expect.stringContaining('clientFaceExclude cannot exempt packages/client package @f/client'),
|
||||
expect.stringContaining('clientFaceExclude names @f/host, which declares no dsh.client entry'),
|
||||
expect.stringContaining('hostPackages redundantly names Client-faced package @f/dual'),
|
||||
expect.stringContaining('unknown release package @f/missing'),
|
||||
]))
|
||||
})
|
||||
|
||||
it('rejects stale, duplicate, and unbounded safe Host export entries', () => {
|
||||
const consumer = pkg('@f/consumer', 'packages/core/consumer/package.json')
|
||||
const provider = pkg('@f/provider', 'packages/core/provider/package.json')
|
||||
const workspaceNames = new Set([CORDIS, consumer.name, provider.name])
|
||||
const consumerFacts: PackageDependencyFacts = {
|
||||
manifestPath: consumer.manifestPath,
|
||||
role: 'configured-host',
|
||||
manifest: consumer.manifest,
|
||||
workspaceNames,
|
||||
allSourceUses: new Map(),
|
||||
hostRuntimeSourceUses: new Map([[provider.name, ['packages/core/consumer/src/index.ts']]]),
|
||||
hostRuntimeExportUses: [{
|
||||
packageName: provider.name,
|
||||
specifier: `${provider.name}/api`,
|
||||
exportName: 'safeValue',
|
||||
sourcePath: 'packages/core/consumer/src/index.ts',
|
||||
line: 1,
|
||||
column: 10,
|
||||
sourceLine: "import { safeValue } from '@f/provider/api'",
|
||||
}],
|
||||
peerRequiredHostDependencies: new Set(),
|
||||
configurationOnlyDevDependencies: new Set(),
|
||||
clientInject: new Set(),
|
||||
}
|
||||
|
||||
expect(collectHostDependencyExportPolicyViolations(
|
||||
[consumerFacts],
|
||||
workspaceNames,
|
||||
{
|
||||
safeHostDependencyExports: {
|
||||
[`${provider.name}/api`]: ['safeValue', 'safeValue', '*', 'staleValue'],
|
||||
},
|
||||
peerRequiredHostExports: {
|
||||
[`${provider.name}/api`]: ['safeValue'],
|
||||
},
|
||||
},
|
||||
)).toEqual(expect.arrayContaining([
|
||||
expect.stringContaining('export safeValue more than once'),
|
||||
expect.stringContaining('cannot classify unbounded'),
|
||||
expect.stringContaining('unused @f/provider/api export staleValue'),
|
||||
expect.stringContaining('appears in both Host export classifications'),
|
||||
]))
|
||||
})
|
||||
})
|
||||
|
||||
describe('face-aware source classification', () => {
|
||||
it('fails when a managed Host package has no Host entry', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-package-missing-host-'))
|
||||
roots.push(root)
|
||||
const subject = pkg('@f/host', 'packages/g/host/package.json')
|
||||
|
||||
expect(() => readPackageDependencyFacts(root, subject, 'configured-host', new Set([subject.name])))
|
||||
.toThrow('packages/g/host/package.json: Host runtime entry packages/g/host/src/index.ts does not exist')
|
||||
})
|
||||
|
||||
it('counts Host values as dependencies and Client values as development inputs', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-package-faces-'))
|
||||
roots.push(root)
|
||||
const subject = pkg('@f/dual', 'packages/g/dual/package.json', {
|
||||
dsh: { client: { inject: ['@f/injected'] } },
|
||||
})
|
||||
const files = {
|
||||
'packages/g/dual/src/index.ts': [
|
||||
"import { value } from '@f/runtime'",
|
||||
"import type { Shared } from '@f/types'",
|
||||
"import type { Hidden } from './types.ts'",
|
||||
"export { nested } from './nested.ts'",
|
||||
].join('\n'),
|
||||
'packages/g/dual/src/nested.ts': "export { nested } from '@f/nested'",
|
||||
'packages/g/dual/src/types.ts': "import { hidden } from '@f/hidden'; export type Hidden = typeof hidden",
|
||||
'packages/g/dual/src/client/index.ts': "import { browser } from '@f/browser'",
|
||||
}
|
||||
for (const [path, source] of Object.entries(files)) {
|
||||
mkdirSync(dirname(join(root, path)), { recursive: true })
|
||||
writeFileSync(join(root, path), source)
|
||||
}
|
||||
const found = readPackageDependencyFacts(root, subject, 'client-host', new Set([
|
||||
CORDIS, '@f/runtime', '@f/types', '@f/nested', '@f/hidden', '@f/browser', '@f/injected',
|
||||
]), policy({
|
||||
configurationOnlyDevDependencies: { '@f/dual': ['@f/injected'] },
|
||||
}))
|
||||
|
||||
expect([...found.hostRuntimeSourceUses.keys()].sort()).toEqual(['@f/nested', '@f/runtime'])
|
||||
expect([...found.configurationOnlyDevDependencies]).toEqual(['@f/injected'])
|
||||
expect(found.hostRuntimeExportUses).toEqual([
|
||||
{
|
||||
packageName: '@f/nested',
|
||||
specifier: '@f/nested',
|
||||
exportName: 'nested',
|
||||
sourcePath: 'packages/g/dual/src/nested.ts',
|
||||
line: 1,
|
||||
column: 10,
|
||||
sourceLine: "export { nested } from '@f/nested'",
|
||||
},
|
||||
{
|
||||
packageName: '@f/runtime',
|
||||
specifier: '@f/runtime',
|
||||
exportName: 'value',
|
||||
sourcePath: 'packages/g/dual/src/index.ts',
|
||||
line: 1,
|
||||
column: 10,
|
||||
sourceLine: "import { value } from '@f/runtime'",
|
||||
},
|
||||
])
|
||||
expect([...found.allSourceUses.keys()].sort()).toEqual([
|
||||
'@f/browser', '@f/hidden', '@f/nested', '@f/runtime', '@f/types',
|
||||
])
|
||||
})
|
||||
|
||||
it('identifies exact runtime exports without treating type imports as values', () => {
|
||||
const source = [
|
||||
"import defaultValue, { value as local, type Kind } from '@f/root'",
|
||||
"import * as namespace from '@f/namespace'",
|
||||
"import '@f/effect'",
|
||||
"import type { TypeOnly } from '@f/types'",
|
||||
"export { source as renamed, type SourceType } from '@f/reexport'",
|
||||
"export * from '@f/star'",
|
||||
"void import('@f/dynamic')",
|
||||
"void require('@f/required')",
|
||||
'void defaultValue; void local; void namespace',
|
||||
].join('\n')
|
||||
const uses = collectRuntimeSourceExportUses('probe.ts', source)
|
||||
expect(uses.map(({ specifier, exportName }) => ({ specifier, exportName }))).toEqual([
|
||||
{ specifier: '@f/dynamic', exportName: '*' },
|
||||
{ specifier: '@f/effect', exportName: '(side effect)' },
|
||||
{ specifier: '@f/namespace', exportName: '*' },
|
||||
{ specifier: '@f/reexport', exportName: 'source' },
|
||||
{ specifier: '@f/required', exportName: '*' },
|
||||
{ specifier: '@f/root', exportName: 'default' },
|
||||
{ specifier: '@f/root', exportName: 'value' },
|
||||
{ specifier: '@f/star', exportName: '*' },
|
||||
])
|
||||
expect(uses.find(use => use.specifier === '@f/root' && use.exportName === 'value')).toMatchObject({
|
||||
line: 1,
|
||||
column: 24,
|
||||
sourceLine: "import defaultValue, { value as local, type Kind } from '@f/root'",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('dependency sections', () => {
|
||||
it('does not leak repository configuration into captured dependency facts', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-client-locale',
|
||||
dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-types': 'workspace:^' },
|
||||
peerDependencies: { [CORDIS]: 'workspace:^' },
|
||||
}
|
||||
const base = facts(manifest)
|
||||
const subject: PackageDependencyFacts = {
|
||||
...base,
|
||||
workspaceNames: new Set([...base.workspaceNames, '@deepseek-ai/dsh-api-remotes']),
|
||||
}
|
||||
|
||||
expect(collectPackageDependencyViolations({
|
||||
facts: [subject], packages: [], policyViolations: [], workspaceNames: subject.workspaceNames,
|
||||
})).toEqual([])
|
||||
})
|
||||
|
||||
it('requires non-workspace Host runtime imports in dependencies', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-types': 'workspace:^', external: '^1.0.0' },
|
||||
peerDependencies: { [CORDIS]: 'workspace:^' },
|
||||
}
|
||||
const subject: PackageDependencyFacts = {
|
||||
...facts(manifest),
|
||||
hostRuntimeSourceUses: new Map([
|
||||
['@deepseek-ai/dsh-runtime', ['packages/core/probe/src/index.ts']],
|
||||
['external', ['packages/core/probe/src/index.ts']],
|
||||
]),
|
||||
}
|
||||
const state = {
|
||||
facts: [subject], packages: [], policyViolations: [], workspaceNames: subject.workspaceNames,
|
||||
}
|
||||
|
||||
expect(collectPackageDependencyViolations(state)).toContain(
|
||||
'packages/core/probe/package.json: external (packages/core/probe/src/index.ts) '
|
||||
+ 'must be dependencies-only; found devDependencies',
|
||||
)
|
||||
repairPackageDependencyManifest(subject)
|
||||
expect(manifest.dependencies?.external).toBe('^1.0.0')
|
||||
expect(manifest.devDependencies?.external).toBeUndefined()
|
||||
|
||||
delete manifest.dependencies?.external
|
||||
expect(collectPackageDependencyViolations(state)).toContain(
|
||||
'packages/core/probe/package.json: external (packages/core/probe/src/index.ts) '
|
||||
+ 'must be dependencies-only; found no dependency section',
|
||||
)
|
||||
})
|
||||
|
||||
it('accepts Host dependencies, development-only inputs, and shared Cordis', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
dependencies: {
|
||||
'@deepseek-ai/dsh-runtime': 'workspace:^',
|
||||
'@deepseek-ai/schemastery': 'workspace:^',
|
||||
external: '^1.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
'@deepseek-ai/dsh-types': 'workspace:^',
|
||||
[CORDIS]: 'workspace:^',
|
||||
},
|
||||
peerDependencies: { [CORDIS]: 'workspace:^' },
|
||||
}
|
||||
expect(collectPackageDependencyViolations({
|
||||
facts: [facts(manifest)], packages: [], policyViolations: [], workspaceNames: facts(manifest).workspaceNames,
|
||||
})).toEqual([])
|
||||
})
|
||||
|
||||
it('lists managed Host runtime dependencies for fix review', () => {
|
||||
const subject = facts({ name: '@deepseek-ai/dsh-probe' })
|
||||
expect(formatManagedRuntimeDependencies({
|
||||
facts: [subject], packages: [], policyViolations: [], workspaceNames: subject.workspaceNames,
|
||||
})).toEqual([
|
||||
'verify-package-dependencies: 1 managed Host runtime edge(s) remain in dependencies across 1 package(s):',
|
||||
' @deepseek-ai/dsh-probe -> @deepseek-ai/dsh-runtime: @deepseek-ai/dsh-runtime#runtimeValue',
|
||||
])
|
||||
})
|
||||
|
||||
it('reports an unapproved Host runtime export without rewriting its dependency section', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-types': 'workspace:^' },
|
||||
peerDependencies: { [CORDIS]: 'workspace:^' },
|
||||
}
|
||||
const subject = facts(manifest)
|
||||
const safetyViolations = collectHostDependencyExportPolicyViolations(
|
||||
[subject],
|
||||
subject.workspaceNames,
|
||||
{ safeHostDependencyExports: {}, peerRequiredHostExports: {} },
|
||||
)
|
||||
const state = {
|
||||
facts: [subject], packages: [], policyViolations: safetyViolations, workspaceNames: subject.workspaceNames,
|
||||
}
|
||||
|
||||
expect(safetyViolations).toEqual([
|
||||
'packages/core/probe/src/index.ts:1:10: @deepseek-ai/dsh-runtime#runtimeValue is not classified as '
|
||||
+ 'safe or peer-required — import { runtimeValue } from \'@deepseek-ai/dsh-runtime\'',
|
||||
])
|
||||
expect(fixPackageDependencies('/unused', state)).toEqual([])
|
||||
expect(manifest.dependencies).toEqual({ '@deepseek-ai/dsh-runtime': 'workspace:^' })
|
||||
})
|
||||
|
||||
it('keeps an edge as a peer when one imported export requires shared identity', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
dependencies: { '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-types': 'workspace:^' },
|
||||
peerDependencies: { [CORDIS]: 'workspace:^' },
|
||||
}
|
||||
const subject: PackageDependencyFacts = {
|
||||
...facts(manifest),
|
||||
peerRequiredHostDependencies: new Set(['@deepseek-ai/dsh-runtime']),
|
||||
}
|
||||
expect(collectHostDependencyExportPolicyViolations(
|
||||
[subject],
|
||||
subject.workspaceNames,
|
||||
{
|
||||
safeHostDependencyExports: {},
|
||||
peerRequiredHostExports: {
|
||||
'@deepseek-ai/dsh-runtime': ['runtimeValue'],
|
||||
},
|
||||
},
|
||||
)).toEqual([])
|
||||
|
||||
repairPackageDependencyManifest(subject)
|
||||
expect(manifest.dependencies).toBeUndefined()
|
||||
expect(manifest.peerDependencies).toMatchObject({
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-runtime': 'workspace:^',
|
||||
})
|
||||
expect(manifest.devDependencies).toMatchObject({
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-runtime': 'workspace:^',
|
||||
})
|
||||
expect(formatPeerRequiredRuntimeDependencies({
|
||||
facts: [subject], packages: [], policyViolations: [], workspaceNames: subject.workspaceNames,
|
||||
})).toEqual([
|
||||
'verify-package-dependencies: 1 Host runtime edge(s) remain in peerDependencies because their exports require shared identity across 1 package(s):',
|
||||
' @deepseek-ai/dsh-probe -> @deepseek-ai/dsh-runtime: @deepseek-ai/dsh-runtime#runtimeValue',
|
||||
])
|
||||
})
|
||||
|
||||
it('reports wrong sections, workspace ranges, and stale peer metadata', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
dependencies: { '@deepseek-ai/dsh-types': 'workspace:*' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
peerDependencies: { [CORDIS]: 'workspace:*', '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
peerDependenciesMeta: { '@deepseek-ai/dsh-missing': { optional: true } },
|
||||
}
|
||||
const state = {
|
||||
facts: [facts(manifest)], packages: [], policyViolations: [], workspaceNames: facts(manifest).workspaceNames,
|
||||
}
|
||||
const violations = collectPackageDependencyViolations(state)
|
||||
expect(violations).toEqual(expect.arrayContaining([
|
||||
expect.stringContaining('@deepseek-ai/dsh-runtime'),
|
||||
expect.stringContaining('@deepseek-ai/dsh-types'),
|
||||
expect.stringContaining(`${CORDIS} must be matching peerDependencies + devDependencies`),
|
||||
expect.stringContaining('dependencies.@deepseek-ai/dsh-types must use workspace:^'),
|
||||
expect.stringContaining('peerDependenciesMeta.@deepseek-ai/dsh-missing has no matching'),
|
||||
]))
|
||||
})
|
||||
|
||||
it('repairs owned relationships without changing unrelated dependencies', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'dsh-package-dependencies-'))
|
||||
roots.push(root)
|
||||
const manifestPath = 'package.json'
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
dependencies: { '@deepseek-ai/schemastery': 'workspace:*', external: '^1.0.0' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
peerDependencies: {
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-runtime': 'workspace:^',
|
||||
'@deepseek-ai/dsh-stale': 'workspace:^',
|
||||
},
|
||||
peerDependenciesMeta: { '@deepseek-ai/dsh-stale': { optional: true } },
|
||||
}
|
||||
writeFileSync(join(root, manifestPath), `${JSON.stringify(manifest, null, 2)}\n`)
|
||||
const subject = { ...facts(manifest), manifestPath }
|
||||
const state = { facts: [subject], packages: [], policyViolations: [], workspaceNames: subject.workspaceNames }
|
||||
|
||||
expect(fixPackageDependencies(root, state)).toEqual([manifestPath])
|
||||
const fixed = JSON.parse(readFileSync(join(root, manifestPath), 'utf8')) as PackageDependencyManifest
|
||||
expect(fixed.dependencies).toEqual({
|
||||
'@deepseek-ai/schemastery': 'workspace:^',
|
||||
external: '^1.0.0',
|
||||
'@deepseek-ai/dsh-runtime': 'workspace:^',
|
||||
})
|
||||
expect(fixed.devDependencies).toEqual({
|
||||
[CORDIS]: 'workspace:^',
|
||||
'@deepseek-ai/dsh-types': 'workspace:^',
|
||||
'@deepseek-ai/dsh-stale': 'workspace:^',
|
||||
})
|
||||
expect(fixed.peerDependencies).toEqual({ [CORDIS]: 'workspace:^' })
|
||||
expect(fixed.peerDependenciesMeta).toBeUndefined()
|
||||
})
|
||||
|
||||
it('repairs an in-memory manifest for benchmark simulation', () => {
|
||||
const manifest: PackageDependencyManifest = {
|
||||
name: '@deepseek-ai/dsh-probe',
|
||||
peerDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
devDependencies: { [CORDIS]: 'workspace:^', '@deepseek-ai/dsh-runtime': 'workspace:^' },
|
||||
}
|
||||
repairPackageDependencyManifest(facts(manifest))
|
||||
expect(manifest.dependencies).toEqual({ '@deepseek-ai/dsh-runtime': 'workspace:^' })
|
||||
expect(manifest.peerDependencies).toEqual({ [CORDIS]: 'workspace:^' })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,734 @@
|
||||
/** Verify and repair npm dependency sections from published Client and Host faces. */
|
||||
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { existsSync, globSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { dirname, extname, join, normalize, relative, resolve, sep } from 'node:path'
|
||||
import ts from 'typescript'
|
||||
import { writeModuleGraph } from './gen-module-graph.ts'
|
||||
import {
|
||||
hasClientDeclaration,
|
||||
PACKAGE_DEPENDENCY_POLICY,
|
||||
type PackageDependencyPolicy,
|
||||
} from './package-dependency-policy.ts'
|
||||
import {
|
||||
collectRuntimeLocalSourceSpecifiers,
|
||||
collectSourcePackageUses,
|
||||
} from './verify-client-packages.ts'
|
||||
|
||||
const GATE = 'verify-package-dependencies'
|
||||
const CORDIS = '@deepseek-ai/cordis'
|
||||
const WORKSPACE_RANGE = 'workspace:^'
|
||||
const RELEASE_MANIFEST_GLOB = 'packages/!(experimental)/*/package.json'
|
||||
const WORKSPACE_MANIFEST_GLOBS = [
|
||||
'apps/*/package.json',
|
||||
'packages/*/*/package.json',
|
||||
'vendor/*/package.json',
|
||||
]
|
||||
|
||||
type DependencySection = 'dependencies' | 'devDependencies' | 'optionalDependencies' | 'peerDependencies'
|
||||
export type PackageDependencyRole = 'client-only' | 'client-host' | 'configured-host'
|
||||
|
||||
/** Manifest fields read and repaired by the package dependency policy. */
|
||||
export interface PackageDependencyManifest {
|
||||
name?: string
|
||||
version?: string
|
||||
exports?: unknown
|
||||
dependencies?: Record<string, string>
|
||||
devDependencies?: Record<string, string>
|
||||
optionalDependencies?: Record<string, string>
|
||||
peerDependencies?: Record<string, string>
|
||||
peerDependenciesMeta?: Record<string, unknown>
|
||||
dsh?: { client?: { inject?: string[] } }
|
||||
}
|
||||
|
||||
/** One workspace package and its source location. */
|
||||
export interface WorkspacePackageManifest {
|
||||
readonly dir: string
|
||||
readonly manifestPath: string
|
||||
readonly manifest: PackageDependencyManifest
|
||||
readonly name: string
|
||||
}
|
||||
|
||||
/** Source and manifest facts for one package covered by the policy. */
|
||||
export interface PackageDependencyFacts {
|
||||
readonly manifestPath: string
|
||||
readonly role: PackageDependencyRole
|
||||
readonly manifest: PackageDependencyManifest
|
||||
readonly workspaceNames: ReadonlySet<string>
|
||||
readonly allSourceUses: ReadonlyMap<string, readonly string[]>
|
||||
readonly hostRuntimeSourceUses: ReadonlyMap<string, readonly string[]>
|
||||
readonly hostRuntimeExportUses: readonly HostRuntimeExportUse[]
|
||||
readonly peerRequiredHostDependencies: ReadonlySet<string>
|
||||
readonly configurationOnlyDevDependencies: ReadonlySet<string>
|
||||
readonly clientInject: ReadonlySet<string>
|
||||
}
|
||||
|
||||
/** One runtime export reached from a package's Host source closure. */
|
||||
export interface HostRuntimeExportUse {
|
||||
readonly packageName: string
|
||||
readonly specifier: string
|
||||
readonly exportName: string
|
||||
readonly sourcePath: string
|
||||
readonly line: number
|
||||
readonly column: number
|
||||
readonly sourceLine: string
|
||||
}
|
||||
|
||||
/** Complete policy input read from the repository. */
|
||||
export interface PackageDependencyState {
|
||||
readonly facts: readonly PackageDependencyFacts[]
|
||||
readonly packages: readonly WorkspacePackageManifest[]
|
||||
readonly policyViolations: readonly string[]
|
||||
readonly workspaceNames: ReadonlySet<string>
|
||||
}
|
||||
|
||||
export interface ExpectedPackageDependency {
|
||||
readonly section: 'dependencies' | 'devDependencies' | 'peer-dev'
|
||||
readonly origins: readonly string[]
|
||||
}
|
||||
|
||||
function normalizePath(path: string): string {
|
||||
return path.split(sep).join('/')
|
||||
}
|
||||
|
||||
function packageNameOf(specifier: string): string | undefined {
|
||||
if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#') || specifier.includes(':')) {
|
||||
return undefined
|
||||
}
|
||||
const parts = specifier.split('/')
|
||||
return specifier.startsWith('@') ? parts.length >= 2 ? `${parts[0]}/${parts[1]}` : undefined : parts[0]
|
||||
}
|
||||
|
||||
/** Read package manifests used for scope discovery and workspace-name checks. */
|
||||
export function readWorkspacePackageManifests(root: string): {
|
||||
all: WorkspacePackageManifest[]
|
||||
release: WorkspacePackageManifest[]
|
||||
} {
|
||||
const read = (manifestPath: string): WorkspacePackageManifest => {
|
||||
const manifest = JSON.parse(readFileSync(resolve(root, manifestPath), 'utf8')) as PackageDependencyManifest
|
||||
if (typeof manifest.name !== 'string') throw new Error(`${manifestPath}: missing package name`)
|
||||
return {
|
||||
dir: dirname(manifestPath),
|
||||
manifestPath,
|
||||
manifest,
|
||||
name: manifest.name,
|
||||
}
|
||||
}
|
||||
const all = globSync(WORKSPACE_MANIFEST_GLOBS, { cwd: root }).map(normalizePath).sort().map(read)
|
||||
const releasePaths = new Set(globSync(RELEASE_MANIFEST_GLOB, { cwd: root }).map(normalizePath))
|
||||
return { all, release: all.filter(pkg => releasePaths.has(pkg.manifestPath)) }
|
||||
}
|
||||
|
||||
function duplicates(values: readonly string[]): string[] {
|
||||
const seen = new Set<string>()
|
||||
const duplicated = new Set<string>()
|
||||
for (const value of values) {
|
||||
if (seen.has(value)) duplicated.add(value)
|
||||
seen.add(value)
|
||||
}
|
||||
return [...duplicated].sort()
|
||||
}
|
||||
|
||||
/** Discover Client faces and configured Host packages, validating explicit overrides. */
|
||||
export function discoverPackageDependencyScope(
|
||||
packages: readonly WorkspacePackageManifest[],
|
||||
policy: PackageDependencyPolicy,
|
||||
): { selected: Array<WorkspacePackageManifest & { role: PackageDependencyRole }>; violations: string[] } {
|
||||
const violations: string[] = []
|
||||
const byName = new Map(packages.map(pkg => [pkg.name, pkg]))
|
||||
const include = new Set(policy.clientFaceInclude)
|
||||
const exclude = new Set(policy.clientFaceExclude)
|
||||
const host = new Set(policy.hostPackages)
|
||||
|
||||
for (const [field, values] of [
|
||||
['clientFaceInclude', policy.clientFaceInclude],
|
||||
['clientFaceExclude', policy.clientFaceExclude],
|
||||
['hostPackages', policy.hostPackages],
|
||||
] as const) {
|
||||
for (const name of duplicates(values)) violations.push(`${field} lists ${name} more than once`)
|
||||
for (const name of values) {
|
||||
if (!byName.has(name)) violations.push(`${field} names unknown release package ${name}`)
|
||||
}
|
||||
}
|
||||
for (const name of include) {
|
||||
if (exclude.has(name)) violations.push(`${name} appears in both clientFaceInclude and clientFaceExclude`)
|
||||
const pkg = byName.get(name)
|
||||
if (pkg !== undefined
|
||||
&& (pkg.manifestPath.startsWith('packages/client/') || hasClientDeclaration(pkg.manifest.dsh))) {
|
||||
violations.push(`clientFaceInclude redundantly names automatically discovered package ${name}`)
|
||||
}
|
||||
}
|
||||
for (const name of exclude) {
|
||||
const pkg = byName.get(name)
|
||||
if (pkg !== undefined && pkg.manifestPath.startsWith('packages/client/')) {
|
||||
violations.push(`clientFaceExclude cannot exempt packages/client package ${name}`)
|
||||
} else if (pkg !== undefined && !hasClientDeclaration(pkg.manifest.dsh)) {
|
||||
violations.push(`clientFaceExclude names ${name}, which declares no dsh.client entry`)
|
||||
}
|
||||
}
|
||||
|
||||
const selected: Array<WorkspacePackageManifest & { role: PackageDependencyRole }> = []
|
||||
for (const pkg of packages) {
|
||||
const clientDirectory = pkg.manifestPath.startsWith('packages/client/')
|
||||
const clientHost = (hasClientDeclaration(pkg.manifest.dsh) || include.has(pkg.name)) && !exclude.has(pkg.name)
|
||||
const clientOnly = clientDirectory && !clientHost
|
||||
const configuredHost = host.has(pkg.name)
|
||||
if (configuredHost && (clientHost || clientOnly)) {
|
||||
violations.push(`hostPackages redundantly names Client-faced package ${pkg.name}`)
|
||||
}
|
||||
const role = clientHost ? 'client-host' : clientOnly ? 'client-only' : configuredHost ? 'configured-host' : undefined
|
||||
if (role !== undefined) selected.push({ ...pkg, role })
|
||||
}
|
||||
return {
|
||||
selected: selected.sort((left, right) => left.manifestPath.localeCompare(right.manifestPath)),
|
||||
violations: [...new Set(violations)].sort(),
|
||||
}
|
||||
}
|
||||
|
||||
function addUse(target: Map<string, string[]>, name: string, path: string): void {
|
||||
const paths = target.get(name) ?? []
|
||||
if (!paths.includes(path)) paths.push(path)
|
||||
target.set(name, paths)
|
||||
}
|
||||
|
||||
const NAMESPACE_RUNTIME_EXPORT = '*'
|
||||
const SIDE_EFFECT_RUNTIME_EXPORT = '(side effect)'
|
||||
|
||||
interface RuntimeSourceExportUse {
|
||||
readonly specifier: string
|
||||
readonly exportName: string
|
||||
readonly line: number
|
||||
readonly column: number
|
||||
readonly sourceLine: string
|
||||
}
|
||||
|
||||
/** Collect exact runtime exports imported or re-exported by one source file. */
|
||||
export function collectRuntimeSourceExportUses(path: string, source: string): RuntimeSourceExportUse[] {
|
||||
const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true)
|
||||
const uses = new Map<string, RuntimeSourceExportUse>()
|
||||
const sourceLines = source.split(/\r?\n/u)
|
||||
const record = (specifier: string, exportName: string, locationNode: ts.Node): void => {
|
||||
const key = `${specifier}\0${exportName}`
|
||||
if (uses.has(key)) return
|
||||
const position = sourceFile.getLineAndCharacterOfPosition(locationNode.getStart(sourceFile))
|
||||
uses.set(key, {
|
||||
specifier,
|
||||
exportName,
|
||||
line: position.line + 1,
|
||||
column: position.character + 1,
|
||||
sourceLine: sourceLines[position.line]?.trim() ?? '',
|
||||
})
|
||||
}
|
||||
const add = (
|
||||
specifierNode: ts.Expression | undefined,
|
||||
exportName: string,
|
||||
locationNode: ts.Node = specifierNode ?? sourceFile,
|
||||
): void => {
|
||||
if (specifierNode === undefined || !ts.isStringLiteralLike(specifierNode)) return
|
||||
if (packageNameOf(specifierNode.text) === undefined) return
|
||||
record(specifierNode.text, exportName, locationNode)
|
||||
}
|
||||
const visit = (node: ts.Node): void => {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
const clause = node.importClause
|
||||
if (clause === undefined) {
|
||||
add(node.moduleSpecifier, SIDE_EFFECT_RUNTIME_EXPORT)
|
||||
} else if (clause.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
|
||||
if (clause.name !== undefined) add(node.moduleSpecifier, 'default', clause.name)
|
||||
const bindings = clause.namedBindings
|
||||
if (bindings !== undefined && ts.isNamespaceImport(bindings)) {
|
||||
add(node.moduleSpecifier, NAMESPACE_RUNTIME_EXPORT, bindings.name)
|
||||
} else if (bindings !== undefined && bindings.elements.length === 0) {
|
||||
add(node.moduleSpecifier, SIDE_EFFECT_RUNTIME_EXPORT)
|
||||
} else if (bindings !== undefined) {
|
||||
for (const element of bindings.elements) {
|
||||
const imported = element.propertyName ?? element.name
|
||||
if (!element.isTypeOnly) add(node.moduleSpecifier, imported.text, imported)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ts.isExportDeclaration(node) && !node.isTypeOnly) {
|
||||
const clause = node.exportClause
|
||||
if (clause === undefined || ts.isNamespaceExport(clause)) {
|
||||
add(node.moduleSpecifier, NAMESPACE_RUNTIME_EXPORT)
|
||||
} else if (clause.elements.length === 0) {
|
||||
add(node.moduleSpecifier, SIDE_EFFECT_RUNTIME_EXPORT)
|
||||
} else {
|
||||
for (const element of clause.elements) {
|
||||
const imported = element.propertyName ?? element.name
|
||||
if (!element.isTypeOnly) add(node.moduleSpecifier, imported.text, imported)
|
||||
}
|
||||
}
|
||||
} else if (ts.isImportEqualsDeclaration(node)
|
||||
&& !node.isTypeOnly
|
||||
&& ts.isExternalModuleReference(node.moduleReference)) {
|
||||
add(node.moduleReference.expression, NAMESPACE_RUNTIME_EXPORT, node.name)
|
||||
} else if (ts.isCallExpression(node)
|
||||
&& (node.expression.kind === ts.SyntaxKind.ImportKeyword
|
||||
|| ts.isIdentifier(node.expression) && node.expression.text === 'require')) {
|
||||
add(node.arguments[0], NAMESPACE_RUNTIME_EXPORT)
|
||||
} else if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node)) {
|
||||
record('react/jsx-runtime', NAMESPACE_RUNTIME_EXPORT, node)
|
||||
}
|
||||
ts.forEachChild(node, visit)
|
||||
}
|
||||
visit(sourceFile)
|
||||
return [...uses.values()].sort((left, right) =>
|
||||
left.specifier.localeCompare(right.specifier)
|
||||
|| left.exportName.localeCompare(right.exportName)
|
||||
|| left.line - right.line
|
||||
|| left.column - right.column)
|
||||
}
|
||||
|
||||
function resolveLocal(importer: string, specifier: string): string | undefined {
|
||||
const raw = resolve(dirname(importer), specifier)
|
||||
const candidates = extname(raw) === ''
|
||||
? [`${raw}.ts`, `${raw}.tsx`, `${raw}.mts`, `${raw}.cts`, join(raw, 'index.ts'), join(raw, 'index.tsx')]
|
||||
: [raw, raw.replace(/\.js$/, '.ts'), raw.replace(/\.jsx$/, '.tsx'), raw.replace(/\.mjs$/, '.mts'), raw.replace(/\.cjs$/, '.cts')]
|
||||
return candidates.find(candidate => existsSync(candidate))
|
||||
}
|
||||
|
||||
function readHostRuntimeUses(root: string, pkg: WorkspacePackageManifest): {
|
||||
packageUses: Map<string, string[]>
|
||||
exportUses: HostRuntimeExportUse[]
|
||||
} {
|
||||
const packageUses = new Map<string, string[]>()
|
||||
const exportUses = new Map<string, HostRuntimeExportUse>()
|
||||
const seen = new Set<string>()
|
||||
const visit = (path: string): void => {
|
||||
const normalized = normalize(path)
|
||||
if (seen.has(normalized)) return
|
||||
seen.add(normalized)
|
||||
const source = readFileSync(normalized, 'utf8')
|
||||
const displayPath = normalizePath(relative(root, normalized))
|
||||
for (const use of collectRuntimeSourceExportUses(normalized, source)) {
|
||||
const name = packageNameOf(use.specifier)
|
||||
if (name === undefined) continue
|
||||
addUse(packageUses, name, displayPath)
|
||||
const fact = { packageName: name, ...use, sourcePath: displayPath }
|
||||
exportUses.set(`${use.specifier}\0${use.exportName}\0${displayPath}\0${String(use.line)}\0${String(use.column)}`, fact)
|
||||
}
|
||||
for (const specifier of collectRuntimeLocalSourceSpecifiers(normalized, source)) {
|
||||
const target = resolveLocal(normalized, specifier)
|
||||
if (target !== undefined) visit(target)
|
||||
}
|
||||
}
|
||||
const entry = resolve(root, pkg.dir, 'src/index.ts')
|
||||
if (!existsSync(entry)) {
|
||||
throw new Error(`${pkg.manifestPath}: Host runtime entry ${normalizePath(relative(root, entry))} does not exist`)
|
||||
}
|
||||
visit(entry)
|
||||
return {
|
||||
packageUses,
|
||||
exportUses: [...exportUses.values()].sort((left, right) =>
|
||||
left.packageName.localeCompare(right.packageName)
|
||||
|| left.specifier.localeCompare(right.specifier)
|
||||
|| left.exportName.localeCompare(right.exportName)
|
||||
|| left.sourcePath.localeCompare(right.sourcePath)
|
||||
|| left.line - right.line
|
||||
|| left.column - right.column),
|
||||
}
|
||||
}
|
||||
|
||||
function readAllSourceUses(root: string, pkg: WorkspacePackageManifest): Map<string, string[]> {
|
||||
const uses = new Map<string, string[]>()
|
||||
for (const sourcePath of globSync('src/**/*.{ts,tsx,mts,cts}', { cwd: resolve(root, pkg.dir) }).sort()) {
|
||||
const source = readFileSync(resolve(root, pkg.dir, sourcePath), 'utf8')
|
||||
const displayPath = `${pkg.dir}/${normalizePath(sourcePath)}`
|
||||
for (const name of collectSourcePackageUses(sourcePath, source)) addUse(uses, name, displayPath)
|
||||
}
|
||||
return uses
|
||||
}
|
||||
|
||||
/** Read source usage for one already-classified package. */
|
||||
export function readPackageDependencyFacts(
|
||||
root: string,
|
||||
pkg: WorkspacePackageManifest,
|
||||
role: PackageDependencyRole,
|
||||
workspaceNames: ReadonlySet<string>,
|
||||
policy: PackageDependencyPolicy = PACKAGE_DEPENDENCY_POLICY,
|
||||
): PackageDependencyFacts {
|
||||
const inject = pkg.manifest.dsh?.client?.inject ?? []
|
||||
const hostRuntime = role === 'client-only'
|
||||
? { packageUses: new Map<string, string[]>(), exportUses: [] }
|
||||
: readHostRuntimeUses(root, pkg)
|
||||
return {
|
||||
manifestPath: pkg.manifestPath,
|
||||
role,
|
||||
manifest: pkg.manifest,
|
||||
workspaceNames,
|
||||
allSourceUses: readAllSourceUses(root, pkg),
|
||||
hostRuntimeSourceUses: hostRuntime.packageUses,
|
||||
hostRuntimeExportUses: hostRuntime.exportUses,
|
||||
peerRequiredHostDependencies: new Set(hostRuntime.exportUses
|
||||
.filter(use => policy.peerRequiredHostExports[use.specifier]?.includes(use.exportName) === true)
|
||||
.map(use => use.packageName)),
|
||||
configurationOnlyDevDependencies: new Set(
|
||||
policy.configurationOnlyDevDependencies[pkg.manifest.name ?? ''] ?? [],
|
||||
),
|
||||
clientInject: new Set(inject.map(packageNameOf).filter(name => name !== undefined)),
|
||||
}
|
||||
}
|
||||
|
||||
/** Validate reviewed Host export classifications against current source facts. */
|
||||
export function collectHostDependencyExportPolicyViolations(
|
||||
facts: readonly PackageDependencyFacts[],
|
||||
workspaceNames: ReadonlySet<string>,
|
||||
policy: Pick<PackageDependencyPolicy, 'peerRequiredHostExports' | 'safeHostDependencyExports'>,
|
||||
): string[] {
|
||||
const violations: string[] = []
|
||||
const allRuntimeUses = facts.flatMap(fact => fact.hostRuntimeExportUses)
|
||||
const classifications = [
|
||||
['safeHostDependencyExports', policy.safeHostDependencyExports],
|
||||
['peerRequiredHostExports', policy.peerRequiredHostExports],
|
||||
] as const
|
||||
for (const [field, entries] of classifications) {
|
||||
for (const [specifier, exportNames] of Object.entries(entries)) {
|
||||
const provider = packageNameOf(specifier)
|
||||
if (provider === undefined || !workspaceNames.has(provider)) {
|
||||
violations.push(`${field} specifier ${specifier} is not a workspace package`)
|
||||
}
|
||||
if (exportNames.length === 0) {
|
||||
violations.push(`${field} lists no exports for ${specifier}`)
|
||||
}
|
||||
for (const exportName of duplicates(exportNames)) {
|
||||
violations.push(`${field} lists ${specifier} export ${exportName} more than once`)
|
||||
}
|
||||
for (const exportName of exportNames) {
|
||||
if (exportName === '' || exportName === NAMESPACE_RUNTIME_EXPORT || exportName === SIDE_EFFECT_RUNTIME_EXPORT) {
|
||||
violations.push(`${field} cannot classify unbounded ${specifier} export ${exportName}`)
|
||||
continue
|
||||
}
|
||||
if (!allRuntimeUses.some(use => use.specifier === specifier && use.exportName === exportName)) {
|
||||
violations.push(`${field} lists unused ${specifier} export ${exportName}`)
|
||||
}
|
||||
if (field === 'safeHostDependencyExports'
|
||||
&& policy.peerRequiredHostExports[specifier]?.includes(exportName) === true) {
|
||||
violations.push(`${specifier} export ${exportName} appears in both Host export classifications`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const fact of facts) {
|
||||
for (const use of fact.hostRuntimeExportUses) {
|
||||
if (use.packageName === fact.manifest.name || use.packageName === CORDIS) continue
|
||||
if (!workspaceNames.has(use.packageName)) continue
|
||||
if (policy.safeHostDependencyExports[use.specifier]?.includes(use.exportName) === true) continue
|
||||
if (policy.peerRequiredHostExports[use.specifier]?.includes(use.exportName) === true) continue
|
||||
violations.push(
|
||||
`${use.sourcePath}:${String(use.line)}:${String(use.column)}: `
|
||||
+ `${use.specifier}#${use.exportName} is not classified as safe or peer-required — ${use.sourceLine}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
return violations.sort()
|
||||
}
|
||||
|
||||
/** Read every package covered by the current dependency policy. */
|
||||
export function readPackageDependencyState(
|
||||
root: string,
|
||||
policy: PackageDependencyPolicy = PACKAGE_DEPENDENCY_POLICY,
|
||||
): PackageDependencyState {
|
||||
const packages = readWorkspacePackageManifests(root)
|
||||
const workspaceNames = new Set(packages.all.map(pkg => pkg.name))
|
||||
const discovered = discoverPackageDependencyScope(packages.release, policy)
|
||||
const facts = discovered.selected.map(pkg =>
|
||||
readPackageDependencyFacts(root, pkg, pkg.role, workspaceNames, policy))
|
||||
const selectedNames = new Set(facts.map(fact => fact.manifest.name))
|
||||
return {
|
||||
facts,
|
||||
packages: packages.release,
|
||||
policyViolations: [
|
||||
...discovered.violations,
|
||||
...collectHostDependencyExportPolicyViolations(facts, workspaceNames, policy),
|
||||
...Object.keys(policy.configurationOnlyDevDependencies)
|
||||
.filter(name => !selectedNames.has(name))
|
||||
.map(name => `configurationOnlyDevDependencies names unmanaged package ${name}`),
|
||||
].sort(),
|
||||
workspaceNames,
|
||||
}
|
||||
}
|
||||
|
||||
/** Derive the required npm section for each relationship owned by the policy. */
|
||||
export function expectedPackageDependencies(
|
||||
facts: PackageDependencyFacts,
|
||||
): ReadonlyMap<string, ExpectedPackageDependency> {
|
||||
const expected = new Map<string, { section: ExpectedPackageDependency['section']; origins: Set<string> }>()
|
||||
const add = (name: string, sectionName: ExpectedPackageDependency['section'], origin: string): void => {
|
||||
if (name === facts.manifest.name || name === CORDIS) return
|
||||
const current = expected.get(name)
|
||||
const section = current?.section === 'peer-dev' || sectionName === 'peer-dev'
|
||||
? 'peer-dev'
|
||||
: current?.section === 'dependencies' || sectionName === 'dependencies'
|
||||
? 'dependencies'
|
||||
: 'devDependencies'
|
||||
expected.set(name, { section, origins: new Set([...(current?.origins ?? []), origin]) })
|
||||
}
|
||||
|
||||
expected.set(CORDIS, { section: 'peer-dev', origins: new Set(['shared Cordis runtime']) })
|
||||
for (const [name, paths] of facts.allSourceUses) {
|
||||
if (!facts.workspaceNames.has(name)) continue
|
||||
for (const path of paths) add(name, 'devDependencies', path)
|
||||
}
|
||||
for (const name of facts.clientInject) {
|
||||
if (facts.workspaceNames.has(name)) add(name, 'devDependencies', 'dsh.client.inject')
|
||||
}
|
||||
for (const name of facts.configurationOnlyDevDependencies) {
|
||||
if (facts.workspaceNames.has(name)) add(name, 'devDependencies', 'configured development-only relationship')
|
||||
}
|
||||
for (const name of Object.keys(facts.manifest.peerDependencies ?? {})) {
|
||||
if (name !== CORDIS) add(name, 'devDependencies', 'existing non-Cordis peer')
|
||||
}
|
||||
for (const [name, paths] of facts.hostRuntimeSourceUses) {
|
||||
const expectedSection = facts.workspaceNames.has(name) && facts.peerRequiredHostDependencies.has(name)
|
||||
? 'peer-dev'
|
||||
: 'dependencies'
|
||||
for (const path of paths) add(name, expectedSection, path)
|
||||
}
|
||||
return new Map([...expected].map(([name, rule]) => [name, {
|
||||
section: rule.section,
|
||||
origins: [...rule.origins].sort(),
|
||||
}]))
|
||||
}
|
||||
|
||||
interface ManagedRuntimeEdge {
|
||||
readonly consumer: string
|
||||
readonly dependency: string
|
||||
readonly exports: readonly string[]
|
||||
}
|
||||
|
||||
function managedRuntimeEdges(
|
||||
state: PackageDependencyState,
|
||||
expectedSection: 'dependencies' | 'peer-dev',
|
||||
): ManagedRuntimeEdge[] {
|
||||
return state.facts.flatMap(facts => [...expectedPackageDependencies(facts)]
|
||||
.filter(([name, rule]) => name !== CORDIS && rule.section === expectedSection)
|
||||
.map(([dependency]) => ({
|
||||
consumer: facts.manifest.name ?? facts.manifestPath,
|
||||
dependency,
|
||||
exports: [...new Set(facts.hostRuntimeExportUses
|
||||
.filter(use => use.packageName === dependency)
|
||||
.map(use => `${use.specifier}#${use.exportName}`))].sort(),
|
||||
})))
|
||||
.sort((left, right) =>
|
||||
left.consumer.localeCompare(right.consumer) || left.dependency.localeCompare(right.dependency))
|
||||
}
|
||||
|
||||
/** Format Host runtime edges whose reviewed exports permit ordinary dependencies. */
|
||||
export function formatManagedRuntimeDependencies(state: PackageDependencyState): string[] {
|
||||
const rows = managedRuntimeEdges(state, 'dependencies')
|
||||
const packages = new Set(rows.map(row => row.consumer)).size
|
||||
return [
|
||||
`${GATE}: ${String(rows.length)} managed Host runtime edge(s) remain in dependencies across ${String(packages)} package(s):`,
|
||||
...rows.map(row => ` ${row.consumer} -> ${row.dependency}: ${row.exports.join(', ')}`),
|
||||
]
|
||||
}
|
||||
|
||||
/** Format Host runtime edges retained as peers by their imported export classification. */
|
||||
export function formatPeerRequiredRuntimeDependencies(state: PackageDependencyState): string[] {
|
||||
const rows = managedRuntimeEdges(state, 'peer-dev')
|
||||
const packages = new Set(rows.map(row => row.consumer)).size
|
||||
return [
|
||||
`${GATE}: ${String(rows.length)} Host runtime edge(s) remain in peerDependencies because their exports require shared identity across ${String(packages)} package(s):`,
|
||||
...rows.map(row => ` ${row.consumer} -> ${row.dependency}: ${row.exports.join(', ')}`),
|
||||
]
|
||||
}
|
||||
|
||||
function section(manifest: PackageDependencyManifest, name: DependencySection): Record<string, string> {
|
||||
return manifest[name] ?? {}
|
||||
}
|
||||
|
||||
function mutableSection(manifest: PackageDependencyManifest, name: DependencySection): Record<string, string> {
|
||||
manifest[name] ??= {}
|
||||
return manifest[name]
|
||||
}
|
||||
|
||||
function declaredSections(manifest: PackageDependencyManifest, name: string): DependencySection[] {
|
||||
return (['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const)
|
||||
.filter(sectionName => section(manifest, sectionName)[name] !== undefined)
|
||||
}
|
||||
|
||||
function describeSections(sections: readonly DependencySection[]): string {
|
||||
return sections.length === 0 ? 'no dependency section' : sections.join(' + ')
|
||||
}
|
||||
|
||||
/** Return all manifest and policy violations in stable order. */
|
||||
export function collectPackageDependencyViolations(state: PackageDependencyState): string[] {
|
||||
const violations = [...state.policyViolations]
|
||||
if (violations.length > 0) return [...new Set(violations)].sort()
|
||||
for (const facts of state.facts) {
|
||||
for (const [name, rule] of expectedPackageDependencies(facts)) {
|
||||
const actual = declaredSections(facts.manifest, name)
|
||||
if (rule.section === 'peer-dev') {
|
||||
if (actual.length === 2
|
||||
&& actual.includes('peerDependencies')
|
||||
&& actual.includes('devDependencies')
|
||||
&& section(facts.manifest, 'peerDependencies')[name] === WORKSPACE_RANGE
|
||||
&& section(facts.manifest, 'devDependencies')[name] === WORKSPACE_RANGE
|
||||
&& facts.manifest.peerDependenciesMeta?.[name] === undefined) continue
|
||||
violations.push(
|
||||
`${facts.manifestPath}: ${name} must be matching peerDependencies + devDependencies at ${WORKSPACE_RANGE}; found ${describeSections(actual)}`,
|
||||
)
|
||||
continue
|
||||
}
|
||||
const expectedSection = rule.section
|
||||
const range = section(facts.manifest, expectedSection)[name]
|
||||
if (actual.length === 1
|
||||
&& actual[0] === expectedSection
|
||||
&& (!facts.workspaceNames.has(name) || range === WORKSPACE_RANGE)) continue
|
||||
violations.push(
|
||||
`${facts.manifestPath}: ${name} (${rule.origins.join(', ')}) must be ${expectedSection}-only`
|
||||
+ (facts.workspaceNames.has(name) ? ` at ${WORKSPACE_RANGE}` : '')
|
||||
+ `; found ${describeSections(actual)}`,
|
||||
)
|
||||
}
|
||||
for (const sectionName of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const) {
|
||||
for (const [name, range] of Object.entries(section(facts.manifest, sectionName))) {
|
||||
if (!facts.workspaceNames.has(name) || range === WORKSPACE_RANGE) continue
|
||||
violations.push(`${facts.manifestPath}: ${sectionName}.${name} must use ${WORKSPACE_RANGE}, found ${range}`)
|
||||
}
|
||||
}
|
||||
for (const name of Object.keys(facts.manifest.peerDependenciesMeta ?? {})) {
|
||||
if (facts.manifest.peerDependencies?.[name] === undefined) {
|
||||
violations.push(`${facts.manifestPath}: peerDependenciesMeta.${name} has no matching peerDependencies entry`)
|
||||
}
|
||||
}
|
||||
}
|
||||
return [...new Set(violations)].sort()
|
||||
}
|
||||
|
||||
function deleteDependency(
|
||||
manifest: PackageDependencyManifest,
|
||||
sectionName: DependencySection,
|
||||
name: string,
|
||||
): void {
|
||||
const dependencies = manifest[sectionName]
|
||||
if (dependencies?.[name] === undefined) return
|
||||
const retained = Object.fromEntries(Object.entries(dependencies).filter(([key]) => key !== name))
|
||||
if (Object.keys(retained).length > 0) {
|
||||
manifest[sectionName] = retained
|
||||
return
|
||||
}
|
||||
switch (sectionName) {
|
||||
case 'dependencies': delete manifest.dependencies; break
|
||||
case 'devDependencies': delete manifest.devDependencies; break
|
||||
case 'optionalDependencies': delete manifest.optionalDependencies; break
|
||||
case 'peerDependencies': delete manifest.peerDependencies; break
|
||||
}
|
||||
}
|
||||
|
||||
function deletePeerMeta(manifest: PackageDependencyManifest, name: string): void {
|
||||
if (manifest.peerDependenciesMeta?.[name] === undefined) return
|
||||
const retained = Object.fromEntries(Object.entries(manifest.peerDependenciesMeta)
|
||||
.filter(([key]) => key !== name))
|
||||
if (Object.keys(retained).length > 0) manifest.peerDependenciesMeta = retained
|
||||
else delete manifest.peerDependenciesMeta
|
||||
}
|
||||
|
||||
function preferredRange(
|
||||
facts: PackageDependencyFacts,
|
||||
name: string,
|
||||
target: ExpectedPackageDependency['section'],
|
||||
): string | undefined {
|
||||
if (facts.workspaceNames.has(name)) return WORKSPACE_RANGE
|
||||
const order: readonly DependencySection[] = target === 'dependencies'
|
||||
? ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']
|
||||
: ['devDependencies', 'peerDependencies', 'dependencies', 'optionalDependencies']
|
||||
return order.map(sectionName => section(facts.manifest, sectionName)[name]).find(value => value !== undefined)
|
||||
}
|
||||
|
||||
/** Apply the dependency policy to one in-memory manifest. */
|
||||
export function repairPackageDependencyManifest(facts: PackageDependencyFacts): void {
|
||||
for (const [name, rule] of expectedPackageDependencies(facts)) {
|
||||
if (rule.section === 'peer-dev') {
|
||||
for (const sectionName of ['dependencies', 'optionalDependencies'] as const) {
|
||||
deleteDependency(facts.manifest, sectionName, name)
|
||||
}
|
||||
mutableSection(facts.manifest, 'peerDependencies')[name] = WORKSPACE_RANGE
|
||||
mutableSection(facts.manifest, 'devDependencies')[name] = WORKSPACE_RANGE
|
||||
deletePeerMeta(facts.manifest, name)
|
||||
continue
|
||||
}
|
||||
const range = preferredRange(facts, name, rule.section)
|
||||
if (range === undefined) continue
|
||||
for (const sectionName of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const) {
|
||||
if (sectionName !== rule.section) deleteDependency(facts.manifest, sectionName, name)
|
||||
}
|
||||
mutableSection(facts.manifest, rule.section)[name] = range
|
||||
deletePeerMeta(facts.manifest, name)
|
||||
}
|
||||
for (const name of Object.keys(facts.manifest.peerDependenciesMeta ?? {})) {
|
||||
if (facts.manifest.peerDependencies?.[name] === undefined) deletePeerMeta(facts.manifest, name)
|
||||
}
|
||||
for (const sectionName of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const) {
|
||||
for (const name of Object.keys(section(facts.manifest, sectionName))) {
|
||||
if (facts.workspaceNames.has(name)) mutableSection(facts.manifest, sectionName)[name] = WORKSPACE_RANGE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Repair every covered manifest and return repository-relative changed paths. */
|
||||
export function fixPackageDependencies(root: string, state: PackageDependencyState): string[] {
|
||||
if (state.policyViolations.length > 0) return []
|
||||
const changed: string[] = []
|
||||
for (const facts of state.facts) {
|
||||
const before = `${JSON.stringify(facts.manifest, null, 2)}\n`
|
||||
repairPackageDependencyManifest(facts)
|
||||
const after = `${JSON.stringify(facts.manifest, null, 2)}\n`
|
||||
if (after === before) continue
|
||||
writeFileSync(resolve(root, facts.manifestPath), after)
|
||||
changed.push(facts.manifestPath)
|
||||
}
|
||||
return changed.sort()
|
||||
}
|
||||
|
||||
function refreshPnpmLockfile(root: string): void {
|
||||
const result = spawnSync(
|
||||
'pnpm',
|
||||
['install', '--lockfile-only', '--ignore-scripts', '--no-frozen-lockfile'],
|
||||
{ cwd: root, shell: process.platform === 'win32', stdio: 'inherit' },
|
||||
)
|
||||
if (result.error !== undefined) throw new Error(`could not refresh pnpm-lock.yaml: ${result.error.message}`)
|
||||
if (result.status !== 0) throw new Error(`pnpm lockfile refresh exited with status ${String(result.status)}`)
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
let state = readPackageDependencyState(root)
|
||||
const fix = process.argv.includes('--fix')
|
||||
if (fix) {
|
||||
if (state.policyViolations.length > 0) {
|
||||
console.error(`${GATE}: --fix skipped because dependency policy review failed.`)
|
||||
} else {
|
||||
const changed = fixPackageDependencies(root, state)
|
||||
console.log(`${GATE}: fixed ${String(changed.length)} manifest(s).`)
|
||||
refreshPnpmLockfile(root)
|
||||
const graphChanges = writeModuleGraph(root)
|
||||
console.log(
|
||||
`${GATE}: refreshed pnpm-lock.yaml and wrote ${String(graphChanges.length)} module-graph artifact(s).`,
|
||||
)
|
||||
state = readPackageDependencyState(root)
|
||||
}
|
||||
}
|
||||
const violations = collectPackageDependencyViolations(state)
|
||||
if (violations.length > 0) {
|
||||
console.error(`${GATE}: ${String(violations.length)} violation(s):`)
|
||||
for (const violation of violations) console.error(` ${violation}`)
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
const roles = Object.groupBy(state.facts, fact => fact.role)
|
||||
console.log(
|
||||
`${GATE}: ${String(state.facts.length)} package(s) match the published dependency policy`
|
||||
+ ` (${String(roles['client-only']?.length ?? 0)} Client-only,`
|
||||
+ ` ${String(roles['client-host']?.length ?? 0)} Client/Host,`
|
||||
+ ` ${String(roles['configured-host']?.length ?? 0)} configured Host).`,
|
||||
)
|
||||
if (fix) {
|
||||
for (const line of formatManagedRuntimeDependencies(state)) console.log(line)
|
||||
for (const line of formatPeerRequiredRuntimeDependencies(state)) console.log(line)
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) main()
|
||||
Reference in New Issue
Block a user