@hanamesh/dsh-app-host 0.2.0-rc.2 → 0.6.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE +4 -7
  2. package/README.md +140 -13
  3. package/consistency.json +41 -6
  4. package/dist/catalog/fixtures/consumer.json +35 -0
  5. package/dist/catalog/fixtures/provider.json +107 -0
  6. package/dist/catalog/suite.d.ts +4 -0
  7. package/dist/catalog/suite.js +50 -0
  8. package/dist/client-ui.d.ts +21 -3
  9. package/dist/client-ui.js +961 -94
  10. package/dist/client.js +2 -2
  11. package/dist/control-origin.js +9 -0
  12. package/dist/descriptor.js +6 -0
  13. package/dist/dsh-compat.js +6 -0
  14. package/dist/dsh.d.ts +21 -4
  15. package/dist/dsh.js +149 -58
  16. package/dist/gateway.js +140 -11
  17. package/dist/git-process.js +64 -0
  18. package/dist/git-worker.js +50 -0
  19. package/dist/index.d.ts +9 -7
  20. package/dist/install-target/fixtures/catalog.json +58 -0
  21. package/dist/install-target/fixtures/consumer-cases.json +148 -0
  22. package/dist/install-target/fixtures/install-failure-cases.json +58 -0
  23. package/dist/install-target/fixtures/provider-cases.json +618 -0
  24. package/dist/install-target/fixtures/reference-consumer.js +37 -0
  25. package/dist/install-target/fixtures/source-profile.js +123 -0
  26. package/dist/install-target/harness.js +43 -0
  27. package/dist/install-target/run.js +28 -0
  28. package/dist/install-target/suite.d.ts +19 -0
  29. package/dist/install-target/suite.js +328 -0
  30. package/dist/installation-status.d.ts +21 -0
  31. package/dist/installation-status.js +2 -0
  32. package/dist/library/catalog.js +163 -19
  33. package/dist/library/client-identity.js +31 -0
  34. package/dist/library/desktop-cli.js +7 -0
  35. package/dist/library/domain.js +3 -1
  36. package/dist/library/handoff.js +246 -0
  37. package/dist/library/install.js +138 -32
  38. package/dist/library/installation-cli.js +48 -0
  39. package/dist/library/installation-command-worker.js +27 -0
  40. package/dist/library/installation-status-http.js +26 -0
  41. package/dist/library/installation-status.js +91 -0
  42. package/dist/library/installation-worker.js +44 -0
  43. package/dist/library/locate.js +70 -9
  44. package/dist/library/node-binding.js +11 -0
  45. package/dist/library/recovery.js +66 -0
  46. package/dist/library/routes.js +90 -14
  47. package/dist/library/service.js +123 -27
  48. package/dist/library/suite.js +130 -0
  49. package/dist/manager.js +24 -8
  50. package/dist/node-runtime/domain.js +6 -0
  51. package/dist/node-runtime/releases.json +59 -0
  52. package/dist/node-runtime/service.js +101 -0
  53. package/dist/owned-probe-diagnostic.js +53 -0
  54. package/dist/router/receipts.js +8 -11
  55. package/dist/router/routes.js +7 -7
  56. package/dist/routes.js +9 -8
  57. package/dist/runtime.js +11 -1
  58. package/dist/usage-evidence.js +18 -86
  59. package/dist/workspace-origin.js +17 -0
  60. package/docs/APP_PACKAGE.md +4 -0
  61. package/docs/CONTRACT.md +75 -11
  62. package/docs/DSH_COMPATIBILITY.md +94 -0
  63. package/docs/DSH_INTEGRATION.md +41 -0
  64. package/docs/INSTALLATION_STATUS.md +96 -0
  65. package/docs/INSTALL_TARGET.md +130 -0
  66. package/docs/LIBRARY.md +44 -3
  67. package/docs/LICENSES.json +189 -61
  68. package/docs/PROVENANCE.json +53 -12
  69. package/docs/SECURITY.md +31 -0
  70. package/node_modules/@hanamesh/lib-provision/LICENSE +15 -0
  71. package/node_modules/@hanamesh/lib-provision/README.md +134 -0
  72. package/node_modules/@hanamesh/lib-provision/THIRD_PARTY_NOTICES.md +17 -0
  73. package/node_modules/@hanamesh/lib-provision/bin/hanamesh-provision.js +13 -0
  74. package/node_modules/@hanamesh/lib-provision/consistency.json +20 -0
  75. package/node_modules/@hanamesh/lib-provision/contract/CHANGELOG.md +5 -0
  76. package/node_modules/@hanamesh/lib-provision/contract/conformance.mjs +80 -0
  77. package/node_modules/@hanamesh/lib-provision/contract/fixtures/consumer.json +9 -0
  78. package/node_modules/@hanamesh/lib-provision/contract/fixtures/provider.json +11 -0
  79. package/node_modules/@hanamesh/lib-provision/contract/lib-provision.schema.json +47 -0
  80. package/node_modules/@hanamesh/lib-provision/package.json +50 -0
  81. package/package.json +81 -33
  82. package/schemas/catalog-provider-page.schema.json +884 -7
  83. package/schemas/catalog-source.schema.json +9 -7
  84. package/schemas/install-target.schema.json +298 -0
  85. package/dist/provision/LICENSE +0 -6
  86. package/dist/provision/THIRD_PARTY_NOTICES.md +0 -13
  87. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/archive.d.ts +0 -0
  88. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/archive.js +0 -0
  89. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/check.d.ts +0 -0
  90. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/check.js +0 -0
  91. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/checkpoints.d.ts +0 -0
  92. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/checkpoints.js +0 -0
  93. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/cli.d.ts +0 -0
  94. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/cli.js +0 -0
  95. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/download.d.ts +0 -0
  96. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/download.js +0 -0
  97. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/errors.d.ts +0 -0
  98. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/errors.js +0 -0
  99. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/extract.d.ts +0 -0
  100. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/extract.js +0 -0
  101. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/fsutil.d.ts +0 -0
  102. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/fsutil.js +0 -0
  103. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/index.d.ts +0 -0
  104. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/index.js +0 -0
  105. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/ledger.d.ts +0 -0
  106. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/ledger.js +0 -0
  107. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/manifest.d.ts +0 -0
  108. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/manifest.js +0 -0
  109. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/paths.d.ts +0 -0
  110. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/paths.js +0 -0
  111. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/platform.d.ts +0 -0
  112. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/platform.js +0 -0
  113. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/provision.d.ts +0 -0
  114. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/provision.js +0 -0
  115. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/tar.d.ts +0 -0
  116. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/tar.js +0 -0
  117. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/types.d.ts +0 -0
  118. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/types.js +0 -0
  119. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/zip.d.ts +0 -0
  120. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/zip.js +0 -0
package/LICENSE CHANGED
@@ -1,12 +1,9 @@
1
1
  License scope for @hanamesh/dsh-app-host
2
2
 
3
- The MIT terms below cover this package's AppHost code and documentation,
4
- excluding dist/provision/**. That directory contains the inlined
5
- @hanamesh/lib-provision@0.1.0-rc.1 component. All dist/provision/** files are
6
- outside and excluded from this MIT license; see dist/provision/LICENSE for that
7
- component's separate notice. Installed dependencies and host peers keep their
8
- own licenses; their names, versions, sources, and purposes are recorded in
9
- docs/LICENSES.json.
3
+ The MIT terms below cover this package's AppHost code and documentation.
4
+ Installed dependencies and host peers keep their own licenses; the external
5
+ @hanamesh/lib-provision package is bundled with its original LICENSE and is not relicensed here. Their names,
6
+ versions, sources, and purposes are recorded in docs/LICENSES.json.
10
7
 
11
8
  MIT License
12
9
 
package/README.md CHANGED
@@ -1,6 +1,55 @@
1
+ 0.6.14 候选:严格读取标准分发目录的精确 npm 三目标与 agentPlugins,保留历史固定 GitHub DTO;目录事实仅展示,不决定兼容或升级。R1-COMBO-01 原始 26 条目响应已纳入回归。
2
+
3
+ > I51 R1 返修(待复审):供应商指引跟随宿主中英菜单,默认正文只写用途和结果;实现解释、交接固定规则及具名设置默认值保留在技术详情。交接的保存操作与套件来源选择前置,自有字段按单列排列;设置值、默认值、权限、读写协议均不变。
4
+
5
+ 0.6.13 候选只消费新 npm 三包身份;插件 id、服务与存储不变。新旧 Core/Usage/Brand 均受保护,Recommender 不属于套件。0.6.12 原件保持原行为。
6
+ >
7
+ > 已知限制 / Known limitations:官方 DSH rc.2 设置页在 390 CSS px 下仍保留固定侧栏,插件内容可用宽度受宿主挤压;本插件不改变客户端或全局 CSS,不能保证该宿主窄屏下标题、原生下拉选项及输入值完整可见。完整设置操作建议使用宽窗口。At 390 CSS px, the official DSH rc.2 settings sidebar leaves limited room for plugin content; titles, native select options and input values may remain constrained. Use a wider window for full settings operations. AppHost only controls its own content and does not modify the client or global CSS. 此限制按编排本次裁定披露,不报告整页390通过。Brand M01既有错误可见性限制仍开;静态profile peers check红流不改写为通过。
8
+
9
+ > I51 第二批候选:供应商来源和状态随宿主中英显示,原始 id/source/state 收在折叠记录;390供应商与路由逐项排列。未改读取、授权、密钥处理或宿主设置侧栏;宿主390列宽限制继续单列。
10
+
11
+ > R1 返修候选:AppHost 页面通过宿主公开 locale 服务随中英切换,错误主面说明下一步、原始原因保留在技术详情。只收紧插件自有布局;官方设置侧栏的390限制单列。不改变 profile peer 策略;旧 ui-slots 声明纠正为公开 renderer provider。
12
+
13
+ # 0.6.10 · B17 已审合拢
14
+
15
+ C 复审 Docs `2d95591d` 已关闭 `b13e60a` 两项P3;本版合入普通插件内的 Core 套件安装包来源选择、持久设置和复读失效保护,并通过 lib-provision 公开 ledger 修正默认 runtime 账本读取。保留0.6.9的独立Node准备、完全退出后重开指引、宿主公开主题token和F02严格拒绝旧目录;不改客户端。原生适用证据属于各固定候选,合拢后的源码/正常包另验,不冒完整安装、mac x64/Windows或owner验收。PKG/PRE/静态种子仍开。
16
+
17
+ > B17:「套件安装包来源」默认现有 registry,也可明确消费 Core 当前公开本机来源;目录清单独立。预览、确认、执行前及异步声明后复读,来源变化终止旧确认,不回退。只在正常插件加载后生效,不承接初装/首 profile。见[公开合约](docs/CONTRACT.md#b17-套件安装包来源2026-10-21-候选)。
18
+
19
+ > 0.6.9历史:该版不含B17,曾披露默认runtime ledger相对路径缺失;本版已合入已审公开provider修复。Node ready仍不代表完整应用运行验收。
20
+
21
+
22
+ > 2026-10-21 · Managed Node candidate: plugin Settings → 安装环境 → review and confirm one-source SHA-verified preparation → later operations automatically use standalone Node without restarting DSH. macOS arm64/x64 implementation only; Windows unsupported. Editable named settings and evidence boundaries: [contract](docs/CONTRACT.md#plugin-managed-standalone-node-2026-10-21-candidate). No silent acquisition, Electron guardian or client change.
23
+ > 2026-10-21候选:所有客户端均按「完全退出后重新打开」指引处理需重启状态;移除旧壳专用重启深链及parent消息,不改客户端、不自动重启。下方rc.28/rc.32重启桥是已被本候选取代的历史记录,市场席位其它行为不变。
24
+
25
+ > 0.6.7 四渠道只读状态桥:允许的网站本人点击后,使用能力广告指向的严格 POST 读取当前 Core 声明和显式配置的官方 CLI 清单;缺供给、失败与未覆盖作用域均具名 unknown,不跨 runtime / CLI / 桌面 App 推断已装。协议、必填设置、支持版本与取消规则见 [Installation status](docs/INSTALLATION_STATUS.md)。
26
+
27
+ CLI-8:未配置来源的新用户默认请求 HanaMesh 视图(`https://market.hanamesh.com/catalog-source.json?view=hanamesh`)。已保存的旧 URL、自定义来源或手动清空列表均保持原样;显式 `sources: []` 仍不播种。
28
+
29
+ > 0.6.6 套件定稿:兼容声明与升级规则唯一归 Core,App-host 只消费可选 protocol `1` 的公开 `getSuiteDeclaration()`。本地单卡显示官方、不计分、Core 与每个组件的实际版本;未知完整性与未执行的升级检查明确区分。agent 套件 0.1.0 是渠道分发版本,不作为 DSH 三组件版本。网站单卡、四渠道平铺面板与 agent 本机状态由网站及渠道提供方提供;App-host 的回环探测仅证明本监听对应的 DSH / HanaMesh 客户端。详见 [套件边界](docs/LIBRARY.md)。
30
+
31
+ > 2026-10-15 · 0.6.2 compatibility candidate: public host peers admit official DSH `0.2.0-rc.2` and `0.2.1-alpha.2` with Cordis `4.0.4` / `4.0.5-alpha.1` and Schemastery `3.18.4` / `3.18.5-alpha.1`; development inputs stay exact. The rc.2 plugin manager has no public `saveExact` option. A proven packaged macOS Desktop uses its unchanged shipped `runtime/cli/bin/dsh` launcher for exact installs and reports `restart-required`; alpha.2 keeps the public live manager path. If neither a verified exact-save manager nor the supported public CLI is available, discovery reports `ready:false` and a concrete reason before installation mutates the profile. Existing browsing and application-view APIs remain available. See [the public API audit and validation limits](docs/DSH_COMPATIBILITY.md). Source checks and fixture results do not establish native or owner acceptance.
32
+
33
+ 0.6.5 历史交付:Git 依赖安装先清除继承的凭据 helper,再只使用 gh;安装与测试入口监测到 osxkeychain 即失败。套件能力沿用 0.6.4:套件只显示一张官方卡,读回实际组件版本;兼容升级展示三个固定组件的版本变化并需本人确认,升级后完全退出并重开。原有DSH 本地 `install-target` 与网站交接监听共用允许网站名单,未获准网站不能读客户端能力;`library.handoff.pollMs` 保存后在真实存储重启中保留,旧记录缺字段仍用默认值。
34
+
35
+ > 2026-10-15 · 0.6.1(核查修正):①探测只回答「允许交接的网站」,别的网站拿不到客户端、就绪、缺什么;②交接出错不再被吞:过期分成「客户端没来取 / 确认框打不开 / 弹出后没回复」,确认框打不开报 `HANDOFF_OPEN_FAILED` 带原因,上报失败、读取失败在应用库里提示并写日志;免重启装完读回 profile 失败会照实提示;③轮询间隔成为设置 `library.handoff.pollMs`(默认 1500 毫秒);去掉端口数、网站数、过期上下限、预检缓存、读包标识超时这些写死的限值,剩下的固定规则在设置页逐条列出并说明原因;④品牌插件 `hanamesh-brand` 进保护名单,不可从市场卸载;⑤测试临时目录全部在进程退出时删除(失败也删),有守卫测试。
36
+ > 2026-10-15 · 0.6.0(第 2 段 Session E):①网站交接——应用库在 127.0.0.1 上另起交接监听(默认端口 39317/39318/39319),网站探测、交接、轮询状态,客户端窗口弹出原有确认,用户确认才安装(C-MARKET 2026-10-15 追加);②宿主有公开 `pluginManager` 时插件安装/卸载改由它完成,装完即加载、无需重启(结果 `applied`);③探测返回真实客户端 `dsh`/`hanamesh` 和「还不能安装」的具体原因;④设置页新增「网站安装交接」,端口、允许的网站、过期时间都可见可改。
37
+
38
+ > D-230 / 0.5.9 candidate: each acquired AppHost route, optional-service listener, observer, resolver, domain and host now registers its release immediately. Failed activation drains the acquired resources and preserves the original error; cleanup failures produce only a named APPHOST_CLEANUP_FAILED diagnostic. Normal unload uses the same once-only releases. Ordinary-app admission, original presentation/success facts, native isolation and final-package U2 remain separate gates.
39
+
40
+ > D-221 / 0.5.8 candidate: runtime readiness, HTTP/resources/WS and hourly Router receipts no longer synthesize Usage open/use. No verified public presentation/business-success source is connected; USAGE_FACT_UNAVAILABLE preserves unknown state. Router diagnostics remain available. Real source facts, native isolation and final-package U2 are still pending. Historical rc.27/rc.30 hourly reporting descriptions below are superseded by this correction.
41
+
42
+ > D-214 / 0.5.7 implementation candidate: the owned verification build connects the normal client Loader/apply/sidebar/market to the existing contract page and retains complete public success/rejection JSON. Release builds default off; installation still requires confirmation. The separate owned native driver uses the fixed upstream public launcher and records actual process argv/version. Package, real Desktop and ordinary application U2 evidence remain separate.
43
+
44
+ > D-202 / 0.5.6 implementation candidate: fixed upstream `d743267388641bc76f17c45ce8b4c231aed1d32c`, official DSH `0.2.1-alpha.2`, Cordis `4.0.5-alpha.1`, Schemastery `3.18.5-alpha.1`, React `18.3.1`. This candidate retains current catalog/market/verification behavior and adds proven Desktop layout discovery, the public reserved-profile CLI, and separate exact localhost control/data origins. `@hanamesh/lib-provision@0.2.1` is bundled from its approved unchanged Git source with its original LICENSE. This is not a release, native U2 pass or owner ACCEPTED. Current evidence is in the card run directory, separate from historical packages and native observations.
45
+
1
46
  # HanaMesh app-host · 0.2.0-rc.2 本地候选
2
47
 
3
- > NPM-APPHOST-01(2026-10-05):本地候选 `0.2.0-rc.2` 对齐官方 `@deepseek-ai/dsh@0.2.0-rc.2`、Cordis `4.0.4`、Schemastery `3.18.4` 与 storage-domain `0.2.0-rc.2`。`@hanamesh/lib-provision@0.1.0-rc.1` 仅以已核 SHA-256 的 vendor tgz 在构建期内联,公共 registry E404,因此不声明为运行时 peer。owner D-2026-10-05-02 已确认该自有代码可分发;内联代码仍为 `UNLICENSED`,不推断新增 MIT 授权。包级许可分区见 [`LICENSE`](LICENSE) 与 [`docs/LICENSES.json`](docs/LICENSES.json)。本地官方 DSH 装配不等于公开 npm 安装门或产品验收;当前卡证据见 BlueMap `NPM-APPHOST-01/REPORT.md`。
48
+ > J1S3-AH-03 / D-180:新增 C-MARKET 的匿名回环探测与严格 HanaMesh 目录视图消费,安装受理/终态/精确读回分开呈现,事件丢失不自动重装;开发表单及合约验证面板默认隐藏,仅测试包装 `verification:true` 启用。沿既有 DSH 扩展点,不改变应用启动/进程/租约所有权。源码与包验证不等同真实 Desktop 或 owner 验收,协议与测试入口见 `docs/INSTALL_TARGET.md`。
49
+
50
+ > 历史 METADATA-DEVKIT-VENDOR-APPHOST-01(2026-10-06,现已由下方0.4.0正常源供给替代):既有开发工具 `@hanamesh/devkit` 更新为精确 optional peer `0.1.0-rc.2` 与同版 file vendor,SHA256 `ae815e589c3e5a573e407da5c982bb0fc8df15b57683ebbfaccd828d9dd588e0`。devkit 不进入运行时依赖或随包代码;canonical 分发授权原文记录于 `docs/LICENSES.json`,不新增 MIT 或再许可。AppHost 根许可分区和内联 provision rc3 保持不变。
51
+
52
+ > NPM-APPHOST-01(2026-10-05):本地候选 `0.2.0-rc.10` 对齐官方 `@deepseek-ai/dsh@0.2.0-rc.2`、Cordis `4.0.4`、Schemastery `3.18.4` 与 storage-domain `0.2.0-rc.2`。`@hanamesh/lib-provision@0.1.0-rc.3` 仅以已核 SHA-256 的 vendor tgz 在构建期内联,公共 registry E404,因此不声明为运行时 peer。owner D-2026-10-05-02 已确认该自有代码可分发;内联代码的自有分发授权原文随 canonical rc3 包复制,不推断新增 MIT 或再许可授权。包级许可分区见 [`LICENSE`](LICENSE) 与 [`docs/LICENSES.json`](docs/LICENSES.json)。本地官方 DSH 装配不等于公开 npm 安装门或产品验收。
4
53
 
5
54
  > rc.41(2026-10-01,P01-U05-RI 修复):真实原生市场重装 Vibe 时,受管 Python runtime 卸载后留有32个运行时生成的 `__pycache__/*.pyc`,后续原子提升因目标目录无所有权清单而拒绝(`E_PROMOTE`)。AppHost 在 lib-provision 精确移除受管文件后仅清理由该 runtime 生成的 Python 字节码及空目录;未知残留继续保留并报告 `RUNTIME_RESIDUE`,不以 force 覆盖。两项回归、模块 check/types 通过;仍需固定消费者组合和独立原生产品复验。
6
55
 
@@ -29,7 +78,7 @@
29
78
 
30
79
  > rc.27(2026-09-21,用户定,STATUS `P2-USE-EVENTS`):**应用的使用证据由 app-host 上报。** 此前 app-host 从不调用 usage 插件的 record 座位,应用既没有 `open` 也没有 `use` 事件。现在:`ctx.inject(['hanameshUsage'])` 可选取得座位(鸭子类型 `record()`,三插件仍互不 import;缺席/不兼容/抛错/`rejected` 只 debug 日志,永不阻止启动或转发);`open` = 实例到达 `ready` 一次(`open:<appId>:<instanceId>`);`use` = 该实例网关真正转发了已授权请求且应用回应非 401/403,每应用每 UTC 小时一次(`use:<appId>:<YYYYMMDDHH>`,时间取桶内第一个请求);引导票据、网关拒绝、宿主就绪探针不计。`hanaRef` = 应用 npm 包名:描述符新增可选 `packageName`(向后兼容),缺省由启动时的已安装扫描 `host.bindPackageName()` 绑定,两者都没有则该应用不产生证据。`sourcePlugin = '@hanamesh/dsh-app-host'`。新面:`host.packageName/bindPackageName/onActivity`、`FixedGateway({onForward})`、`createUsageEvidence()`、`list().apps[].packageName`。契约见 `docs/CONTRACT.md`「应用使用证据」;AH-U01–U07 测试(U07 为真实 Cordis 根,座位先于/后于本插件提供两种顺序),M11/M12 变异。
31
80
 
32
- > rc.26(2026-09-21,O3 stage-4 官方 DSH 发行路径 PRD §A.8):**纯 DSH CLI profile(只 `dsh plugin add hanamesh-core` + 应用包,无桌面壳 overlay)下的应用库可用。** ① `library.sources` **未配置**时默认 `[{manifestUrl:'https://market.hanamesh.com/catalog-source.json',enabled:true}]`(首启仍只在存储为空时播种;显式 `sources: []` 表示不要来源,保持为空——schema 用 `union([array, undefined])` 区分「未设」与「空数组」,旧版 schemastery 把未设强制成 `[]` 的行为不再影响);② `library.profileDir` 缺省时从本包**自身真实安装位置**推断:`import.meta.url` 向上找到名为 `@hanamesh/dsh-app-host` 的包根并 `realpath`,再向上找第一个 `node_modules/@hanamesh/dsh-app-host` 解析到该真实根、且 `package.json` 的 `dependencies` / `dsh.profile.bundles` 提到 hanamesh 的祖先目录——pnpm `.pnpm` 存储路径永不被返回,只返回链接它的 profile;`profileName` = `basename(profileDir)`;`dshBin` = `process.argv[1]` **仅当**它以 `/@deepseek-ai/dsh/lib/bin.js` 结尾(启动本进程的 DSH CLI),否则再尝试从 profile 解析(失败不再抛错,只是安装不可用);`nodeBinary` = `process.execPath` **仅当** `process.versions.electron` 未定义(K5:Electron 宿主仍须显式配置,否则 `NODE_RUNTIME_REQUIRED` fail-closed)。显式配置永远优先(桌面壳 overlay 全部显式,行为不变);推断结果以一行结构化日志 `hanamesh-app-host library: inferred {...}` 打出。效果:CLI 安装且已注册的 Vibe 在库里显示为 `registered` → 卡片「打开」而非「安装」;安装/卸载/补齐 runtime 在纯 DSH 上可用(走 `node bin.js plugin --profile <name> add/remove`,与桌面桥完全相同)。AH-L07–L10 测试(含真实 Cordis 根经 Config schema 的 L07 plugin 用例),M10 变异。
81
+ > rc.26(2026-09-21,O3 stage-4 官方 DSH 发行路径 PRD §A.8):**纯 DSH CLI profile(只 `dsh plugin add hanamesh-core` + 应用包,无桌面壳 overlay)下的应用库可用。** ① `library.sources` **未配置**时默认 `[{manifestUrl:'https://market.hanamesh.com/catalog-source.json?view=hanamesh',enabled:true}]`(首启仍只在存储为空时播种;显式 `sources: []` 表示不要来源,保持为空——schema 用 `union([array, undefined])` 区分「未设」与「空数组」,旧版 schemastery 把未设强制成 `[]` 的行为不再影响);② `library.profileDir` 缺省时从本包**自身真实安装位置**推断:`import.meta.url` 向上找到名为 `@hanamesh/dsh-app-host` 的包根并 `realpath`,再向上找第一个 `node_modules/@hanamesh/dsh-app-host` 解析到该真实根、且 `package.json` 的 `dependencies` / `dsh.profile.bundles` 提到 hanamesh 的祖先目录——pnpm `.pnpm` 存储路径永不被返回,只返回链接它的 profile;`profileName` = `basename(profileDir)`;`dshBin` = `process.argv[1]` **仅当**它以 `/@deepseek-ai/dsh/lib/bin.js` 结尾(启动本进程的 DSH CLI),否则再尝试从 profile 解析(失败不再抛错,只是安装不可用);`nodeBinary` = `process.execPath` **仅当** `process.versions.electron` 未定义(K5:Electron 宿主仍须显式配置,否则 `NODE_RUNTIME_REQUIRED` fail-closed)。显式配置永远优先(桌面壳 overlay 全部显式,行为不变);推断结果以一行结构化日志 `hanamesh-app-host library: inferred {...}` 打出。效果:CLI 安装且已注册的 Vibe 在库里显示为 `registered` → 卡片「打开」而非「安装」;安装/卸载/补齐 runtime 在纯 DSH 上可用(走 `node bin.js plugin --profile <name> add/remove`,与桌面桥完全相同)。AH-L07–L10 测试(含真实 Cordis 根经 Config schema 的 L07 plugin 用例),M10 变异。
33
82
  > rc.25(2026-09-21,STATUS `APP-RUNTIME-LOCK`):桌面壳整棵进程树被强杀(DSH + guardian 一起死)后,应用数据根下的 `.runtime.lock` 不再永久卡住下一次「打开」。锁记录现在带 owner pid + 进程启动时间令牌、guardian 创建的子进程(launcher / app 的 pid + 启动令牌 + 可执行文件)和端口;再次 acquire 时:owner 活着 → 仍 `DATA_ROOT_BUSY`,`details.pid` 给出活着的 pid;owner 死了(pid 不存在,或同 pid 但启动时间不同 = pid 复用)→ 逐个核对记录的子进程:已消失或被别的进程复用 pid 的忽略,**只有 pid + 启动令牌 + 可执行文件三者都对得上的孤儿**才被 SIGTERM→SIGKILL 后接管锁;活着但证明不了是我们的 → 仍 `DATA_ROOT_BUSY`,`details.pid`/`details.ownerPid` 指出该进程。只用 Node 内建(macOS/Linux 用 `ps -o lstart=` / `/proc`,Windows 退化为只判 pid 存活、永不接管活进程)。AH-L01–L06 测试(L05/L06 真 SIGKILL guardian + 宿主后再开),M09 变异。
34
83
  > rc.24(2026-09-21):模型随路由——路由表加「模型」列(所路由供应商的模型列表 / 文本框;「应用默认」= 清单默认值),`POST /hanamesh/router/model`;自动路由行选模型即成为同供应商的显式 grant。
35
84
  > rc.23(2026-09-21):Router 不再替应用选模型——自动路由时 `{{model|默认}}` 落到应用声明的默认值,不再取供应商模型列表第一项(用户在 Vibe 里被塞了 `gpt-5.3-codex-spark` 的根因);无 `providers` 的派生槽位不自动路由、plan 标 `derived`、路由表不显示。
@@ -47,7 +96,7 @@
47
96
 
48
97
  > 收录不代表审核或推荐。新客户端 seed 对 Core、Usage、AppHost 各安装并启用一次;同一 profile 不得再手工插入第二条 `hanamesh-app-host` loader entry。
49
98
 
50
- > rc.4 增加 `credentialEnv` / `credentialResolver`;rc.5 增加文件投射根与格式;rc.6 增加文件生命周期策略;rc.7 允许停止实例在下次打开时采用新定义;rc.8 增加 `credentialEnv[].sets` 声明。逐项证据见 `docs/acceptance/`。`ACCEPTED` 仍只有用户能给。
99
+ > rc.4 增加 `credentialEnv` / `credentialResolver`;rc.5 增加文件投射根与格式;rc.6 增加文件生命周期策略;rc.7 允许停止实例在下次打开时采用新定义;rc.8 增加 `credentialEnv[].sets` 声明。逐项证据见 `docs/acceptance/`。
51
100
 
52
101
  本仓完成可独立运行的应用实例管理、持久视图租约、受控网关和工作台 SDK。原型源码所在私有仓当时访问返回 404,因此这是新的实现候选,不是原型提取;原型许可证和 commit 尚未核实(原型现在可读,见 `<umbrella>/research/dsh-greenfield-2026-09-09/workspace/packages/hanamesh-app-host/`,契约差异未逐项对照)。
53
102
 
@@ -61,24 +110,35 @@
61
110
  - **K5:** Electron 宿主必须显式给绝对且可执行的 `nodeBinary`;guardian/launcher 使用同一 Node,只继承 `DSH_HOME/HOME/LANG/TMPDIR/PATH` 白名单。未配置时 fail-closed 为 `NODE_RUNTIME_REQUIRED`。
62
111
  - **Router:** 合并授权、撤销、文件投射 ledger 与 `sets`,来源为 DSH credentials/LLM 目录和 coding-oauth gateway;不搬 key 探测、录入或 OAuth 端口。
63
112
  - **市场(原应用库):** 自带侧栏入口与覆盖页;目录源同一时刻只启用一项;插件与应用同一入口、同一 `dsh plugin add/remove` 路径;已装列表含插件;区分已注册、待重启、可升级与缺 runtime。
64
- - **锁定 runtime 供给:** build 脚本直接读取 `vendor/hanamesh-lib-provision-0.1.0-rc.1.tgz`,校验 SHA-256 后内联到 `dist/provision/`。包清单没有该私有包的 dependency、peer 或 devDependency;来源与许可边界见 `docs/PROVENANCE.json`。
113
+ - **Runtime 供给(0.5.0):** `@hanamesh/lib-provision` 从其私有 Git 源 tag 范围正常安装,DSH 入口调用公开 `provision`、`remove`、`ledger`。构建只复制本源 `src/`,不提取 vendor 或内联其他包;来源与许可边界见 `docs/PROVENANCE.json`。
65
114
 
66
115
  ## 运行
67
116
 
68
- NPM-APPHOST-01 的本地开发环境是 **macOS arm64 / Node 24.13.1 / npm 11.8.0 / 官方 DSH 0.2.0-rc.2**。干净安装使用锁文件,运行依赖为 `zod 4.5.4`;私有 `@hanamesh/lib-provision` 不在运行时依赖或 peer 中,其代码已获自有代码分发确认并按独立许可分区内联。
117
+ 当前候选使用 Node 24.13.1、pnpm 10.33.0、TypeScript 5.8.3 与官方 DSH 0.2.1-alpha.2。先为本次运行显式设置隔离 HOME、DSH_HOME、TMPDIR、npm cache 和 pnpm store,再执行:
69
118
 
70
119
  ```bash
71
- npm ci
72
- npm run build
73
- npm test
74
- npm run test:mutation
75
- npm run test:types
76
- npm run demo -- --smoke
120
+ CI=true pnpm install --frozen-lockfile
121
+ pnpm run build
122
+ CI=true pnpm test
123
+ pnpm run test:contract
124
+ pnpm run test:mutation
125
+ pnpm run test:types
126
+ # 原生驱动契约(需要已安装并构建的上游 DSH dsh-v0.2.1-alpha.2 检出,不在 pnpm test 内)
127
+ AH_DSH_UPSTREAM=/absolute/upstream-checkout pnpm run test:native-driver
128
+ pnpm run check:consistency
129
+ pnpm run check:toolchain
130
+ pnpm run preflight
131
+ pnpm pack --pack-destination /absolute/card-run/artifacts
132
+ pnpm run verify:pack /absolute/card-run/artifacts/hanamesh-dsh-app-host-0.5.6.tgz
77
133
  ```
78
134
 
79
- `npm run demo` 启动一个受控示例应用,并让两个视图共用同一实例;终端打印应用 URL,Ctrl+C 清理自有进程和临时示例目录。它不是 DSH、工作台或两个上游应用的演示。
135
+ `@hanamesh/devkit` 仅为开发依赖,按声明的 Git 范围解析到锁定 e6ccf710 的 0.2.3,不进入 tarball 或运行时。43 个变异保留各自业务断言,`HANAMESH_APPHOST_RUN_DIR` 将证据写入本卡隔离子目录。lib-provision 仍是固定 575d63fb 的 0.2.1 原源包,正常 pack 随包分发并保留原 LICENSE;生产者使用 pnpm 要求的 hoisted 布局,不更改消费者的 exotic、peer 或脚本政策。
80
136
 
81
- `typescript 5.8.3` 已固定在开发依赖中。rc.3 tarball 可用 `npm install --offline --ignore-scripts --legacy-peer-deps /绝对路径/hanamesh-dsh-app-host-0.1.0-rc.3.tgz` 安装到独立测试工程;真实 DSH 验收须用独立 `DSH_HOME`,不要装到个人 profile。
137
+ `verify:pack` 在独立目录先验证缺少宿主 peers 时准确报 `ERR_PNPM_PEER_DEP_ISSUES`,不强制 offline 或把缓存故障当缺 peer。随后显式提供九个直接 peers,加上官方 0.2.1-alpha.2 的 storage/scope 传递 peers,严格安装、冻结锁重装并核锁摘要,再消费公开 JS/TS。完整测试另在默认 pnpm11 的全新 HOME/store 下消费真实 tarball,保留正常 scripts/exotic/peer 政策。公开 browser 入口的解析/语法验证不代替原生 Loader 激活。
138
+
139
+ `pnpm run preflight:dsh [实际宿主项目绝对路径]` 只读检查实际 DSH/Cordis/storage-domain/schemastery 的精确 pins,并报告解析路径;不传路径时检查本模块开发目录,缺 DSH 本体会准确退出 2,不自动安装或伪称真实宿主。原生取证必须使用固定上游和独立 default Desktop profile,正常公开 CLI 安装同一最终 tarball,完成全部安全与 UI 门。
140
+
141
+ `devkit.config.mjs` 与 `scripts/*-cases/policy/probes` 保留本模块专用策略与断言。`pnpm run demo` 仅为受控本地示例,不是普通应用产品供给、真实 Desktop 或 owner 验收。
82
142
 
83
143
  ## 验收结果在哪里
84
144
 
@@ -102,3 +162,70 @@ rc.3 修复只在本地隔离分支 `codex/app-host-acc-fix`;没有创建远
102
162
  rc.1 原交付包的 ZIP 含本地 Git bundle 和提交信息。`scripts/publish-github.sh --create-private` 是**尚未执行**的历史发布辅助;执行前须重新核对目标仓与授权。
103
163
 
104
164
  rc.1 原始输入当时标注 `UNLICENSED`,不是 MIT/Apache 授权声明;没有擅自给用户代码选择开源许可证。[`docs/PROVENANCE.json`](docs/PROVENANCE.json) 保留 rc.1 原始输入与当时环境记录;rc.3 的包摘要与复验证据见源码仓 `docs/acceptance/wave01-rc3-artifact.json`。
165
+
166
+ ## METADATA-APPHOST-PROVISION-01(2026-10-06)
167
+
168
+ AppHost `0.2.0-rc.5` 内联 canonical `@hanamesh/lib-provision@0.1.0-rc.3`,源码提交 `e8707089409ffd3483fc4c964d6032c370dae634`,vendor SHA-256 `b7d149dcbf51c30fd0226fb170afdf268501057b0c7149903c02c17abe93b2c7`。原 build 验证归档摘要并提取 `lib/`、`LICENSE` 与 `THIRD_PARTY_NOTICES.md`;两个分发记录保留上游原文。根 `SEE LICENSE IN LICENSE` / AppHost MIT 分区保持,`dist/provision/**` 自有分发记录不改为 MIT。业务源码与公开 API 不变,无新增依赖或运行时功能;devkit 仍精确 rc1。只交工程新包,未发布 npm 或安装物,产品界面与干净机未运行。
169
+
170
+ ## 市场接收安装目标(P06)
171
+
172
+ AppHost rc7 提供 `market.openInstallTarget({itemId?,packageName?})` 及同名公开客户端出口。市场查询自己的当前目录、显示四字段确认;只在用户明确确认后走原鉴权安装路由,重复输入共享安装状态。市场顶部「安装目标」小界面调用同一入口;fixture 来源醒目标注。输入/调用方式、回执及 HTTP 语义见 [INSTALL_TARGET.md](docs/INSTALL_TARGET.md)。本轮源码/包自测不代统一客户端安装、真实首步或 owner 验收。
173
+
174
+ 安装目标合约(rc8,`hanamesh.install-target` v1,只加不改):schema `schemas/install-target.schema.json`(出口 `./install-target/schema.json`),提供方/消费方 fixture 与一致性套件随包(`./install-target/suite`、`./install-target/fixtures/*`)。调用方可选声明 `contractVersion: '1'`;不声明保持 rc7 语义,其他值明确拒绝 `CONTRACT_VERSION_UNSUPPORTED`。见 [INSTALL_TARGET.md](docs/INSTALL_TARGET.md#合约版本与一致性套件)。
175
+
176
+ 运行 `pnpm run test:contract` 会先 build,再串行执行 `tests/install-target-contract.test.mjs` 与 `tests/catalog-major-compat.test.mjs`,验证安装目标 v1 和目录 major 1 的提供方/消费方契约及拒绝语义。J1S2-AH-01 提议将基线 conformance 命令设为 `pnpm run test:contract`;基线采纳由 segflow 上层处理。本入口是本模块契约自测,真实 DSH / 客户端产品验收另行记录。崩溃一致性声明仍由 `pnpm run check:consistency` 检查。
177
+
178
+ rc9 installation-target contract: the library accepts exact 127.0.0.1/localhost aliases at the same configured port; Origin must match the request Host. Cross-alias/foreign Origin, unknown Host/port, iframe, CSRF, authentication and version refusals remain explicit. See [INSTALL_TARGET](docs/INSTALL_TARGET.md).
179
+
180
+ ## 0.4.0 · Devkit normal Git supply / 0.5.0 external provision supply
181
+
182
+ Development installs use Node 24.13.1, pnpm 10.33.0 and the frozen `pnpm-lock.yaml`, with pnpm package-manager self-management disabled. The exact Devkit 0.2.3 / lib-provision 0.2.1 published package archives now live under `vendor/`, retaining the previous source commits and original LICENSE notices. `vendor/supply.json` records source pins and SHA256; the lock also pins archive integrity. Source installs need no private Git access or credentials. `@hanamesh/devkit` remains development-only (0.5.1 removed its unused public optional peer). The package identity is Devkit, never the shared root alias; only its published package surface is archived here. Run `pnpm run check:devkit-supply` for the public provider contract, installed archive bytes/SRI, version range and CLI checks. The provider 0.2.3 Git-only `checkConsumer` does not cover file transport and is explicitly reported as not applicable. The four mature tool engines and runtime payload are unchanged. No runtime Devkit dependency or bundled tool code is added.
183
+
184
+ Historical source-Git route (superseded by the fixed archives above for current installs): the upstream Git subdirectory route supports pnpm 10.33.0; npm 11.8.0 cannot install that development dependency. AppHost 0.4.x source Git consumption therefore uses pnpm, with its normal dependency build approval for this package's existing build/prepack lifecycle. A normal npm tarball runtime install remains supported and ignores development dependencies. The previously verified AppHost 0.3.0 source/tag and `^0.3.0` npm route remain byte-identical and outside the 0.4.0 range. Future 0.x minor ranges remain distinct. The independent 0.4.0 release retains the mature inlined lib-provision payload. AppHost 0.5.0 installs lib-provision from `git+https://github.com/yzsnstotz/hanamesh-lib-provision.git#semver:^0.2.1` and removes it from `dist/` and `vendor/`. The lib source candidate has no public Devkit peer or Git installation lifecycle script, so it needs no provision build allowlist; only the existing koffi lifecycle remains approved. A fresh strict two-source installation verifies this boundary. The old 0.2.0 strict peer failure remains in the task evidence; no peer override or disabled strictness is used. Run `pnpm run check:provision-supply` for the source's installed public conformance when affected; unchanged runtime/API/CLI/type checks are reused by byte evidence.
185
+
186
+ ## 0.5.1 · origin/main dependency closure
187
+
188
+ Removed the unused public Devkit peer; all Devkit imports belong to development scripts. Its normal pnpm Git subdirectory range and the external lib-provision runtime dependency are unchanged. No runtime API, schema, fixture, protocol or business code changes. Normal npm tarball runtime consumption remains applicable; npm source Git cannot resolve the Devkit subdirectory route.
189
+
190
+ 开发安装与检查使用固定工具链和模块自有的 Git 守卫(不修改用户的 Git 配置):
191
+
192
+ ```sh
193
+ fnm exec --using=24.13.1 node scripts/safe-git.mjs pnpm install --frozen-lockfile
194
+ fnm exec --using=24.13.1 node scripts/safe-git.mjs npm run check
195
+ fnm exec --using=24.13.1 node scripts/safe-git.mjs npm run verify:pack -- /absolute/path/package.tgz
196
+ ```
197
+
198
+ 守卫为子进程设置 `GIT_CONFIG_NOSYSTEM=1`、关闭终端提示,并用空 helper 清空继承项后设置 `!gh auth git-credential`。隔离 HOME 时,私有 Git 依赖需要该环境可用的 gh 登录;不复制个人凭据。pnpm 自动切换版本关闭。Git Trace2 只写权限受限的临时文件,发现禁用 helper 时失败并结束自有进程组;正常、失败、SIGINT/SIGTERM 后删除 trace,不把原始内容写入报告。测试使用假的 gh/钥匙串 helper,不访问真实钥匙串。
199
+
200
+ 应用库公开 CLI 安装也使用同一守卫。进程内插件管理器不能传入独立环境和监测边界,因此包变更统一走受控公开 CLI,并显示需重启;CLI 不可用时在安装前显示缺失条件。原生准备、旧 wave01 复演等脚本也必须从 `scripts/safe-git.mjs` 启动;原有隔离目录与浏览器 `--use-mock-keychain --password-store=basic` 要求继续适用。
201
+
202
+ 页面的 `env -u …` 首次安装/补齐命令仅供 macOS / Linux 的 POSIX 终端使用;Windows 安全复制命令尚未提供,不将其计为 Windows 产品验收通过。运行时守卫的 Windows npm/pnpm JS 入口和进程树清理仅作源码处理,仍待 Windows 实测。
203
+
204
+ ### Public CI
205
+
206
+ The `app-host-core` workflow downloads the public commit archive anonymously,
207
+ uses fixed Node 24.13.1 / pnpm 10.33.0 with self-management off, verifies vendor
208
+ archive hashes, and installs with the frozen pnpm lock. It checks both provider
209
+ public contracts, runs the full module check (including the fake-keychain guard
210
+ regressions), then packs and verifies a fresh strict consumer. All package
211
+ commands use the existing monitored Git boundary. No repository/environment
212
+ secret, checkout credential, private dependency fetch, paid runner, deployment or
213
+ publishing action is configured. Isolated HOME/DSH/agent/cache/store/temp paths
214
+ are cleaned even after failure. Local full checks remain the delivery authority;
215
+ Actions runs on the standard public/free `macos-15` arm64 runner because the existing native preparation fixture requires that platform. The preinstalled Chrome runs with an isolated profile, mock keychain and basic password store. It is an additional macOS check, not native-client or owner acceptance; this does not establish Linux support.
216
+
217
+ ## 发布检查:平台依赖闭包(不可关闭)
218
+
219
+ `DSH_PNPM_PLATFORM_CLOSURE` 是正确性不变量,Mac/Windows/Linux 同样适用:DSH 自带 pnpm 11.7.0 处理不适用平台 optional 子包时可能安装完不退出,导致 DSH 持续等待。正常 tarball、bundled 包及完整锁定依赖闭包发现 os/cpu/libc 字段或平台子包 optionalDependencies 即拒绝,报具体包名/路径;缺闭包证据也拒绝。不能以开关、超时、重试、omit-optional 或静默兜底绕过;应改用单包内含多平台文件的中立依赖。
220
+
221
+ 运行 `npm run release:check` 正常打包并检查;发布仅用 `npm run release:publish`,发布已检查的同一 tarball。直接目录 npm publish 会被 prepublishOnly 明确拒绝。开发工具 `@hanamesh/release-platform-gate` 仅 devDependency,先按接线请求复制经 SHA 固定的正常工具包并更新冻结锁;CI 必须接入这个发布门。详细输出包含不可关闭的原因、正常包/锁 SHA 和扫描路径;absent optional peer 按 npm 定义列明,不等同 optionalDependencies。
222
+
223
+ 共享门已升级到 R2 PASS 的 0.1.9,原正常工具 tar SHA256 为 `c72010c96a5f22e36d65f6c1fd850e583dead7e843644eba1657b4416d9cbd0d`;最终 main 来源见 `vendor/release-platform-gate.json`。本仓接线仍须 R1 独审,不等于 npm 发布放行,本次不发布。
224
+
225
+ `verify:pack` 原有 tarball 参数保持;正常消费者验证之后通过共享公开 checkRelease 核对同一个归档,CI沿该入口必经硬门,不另打一个包代替原包。接线没有复制扫描实现。
226
+
227
+ 有限依赖形态合同为正常开发工具包中的 `DEPENDENCY_SHAPES.md`(dependency-shapes-v1):支持 registry/git/file/link/tarball/workspace/bundled/vendor 的明确子集,不能当作 npm/pnpm 的无限全集。合同外一律 `UNSUPPORTED_DEPENDENCY_SHAPE`,逐项公开 `package/path/shape/why/action/contract`;缓存、bundle、环境变量或额外 CLI 开关都不能绕过准入。已知缺证据、冻结漂移、完整性和平台违规仍各自具名拒绝,不能以“任意失败”代替正确理由。
228
+
229
+ 发布说明:DSH 内置 pnpm 11.7.0 处理不适用平台 optional 子包时可能安装后不退出,使 DSH 一直等安装结束;因此本门是正确性不变量(`disableable:false`),没有关闭开关。所有 OS/CPU/libc 都必须具备平台中立的完整安装依赖闭包,不能用本机已装、omit-optional、ignore-scripts、超时、重试、放宽断言或改客户端代替。每次 PASS/FAIL 的 JSON/receipt 都包含触发背景和不能关闭的 reason;release:check 正常 pack,release:publish 只发布同一已检查且再核 SHA 的 tar。源码目录发布由 prepublishOnly 拒绝,CI 的 verify:pack/preflight 必经该门;无可失败 job 或旁路入口。
230
+
231
+ 固定提供方 main 提交 `13ec0db3bc6aa6b6235f2105d3f0a6b998855ff5`,与 R2 审过的 0.1.9 正常包6载荷逐字一致;来源/归档摘要见 `vendor/release-platform-gate.json`。
package/consistency.json CHANGED
@@ -40,14 +40,27 @@
40
40
  },
41
41
  {
42
42
  "id": "receipt-hour",
43
- "name": "回执行的计数与已上报标记一起发布",
43
+ "name": "独立Router诊断行整体发布",
44
44
  "facts": [
45
45
  "receipt-row:count",
46
46
  "receipt-row:reported"
47
47
  ],
48
48
  "medium": "single-snapshot:hanamesh_router_receipts",
49
- "why": "T6:同一 (app, 路由, 小时) 行的 count/injections/firstAt 与 reported 标记在一次去抖后的 global.set 里整体发布;不存在第二张回执表。强杀最多丢最后一个去抖窗口内的计数,永不出现 reported 却没有行。",
49
+ "why": "同一(app,路由,小时)诊断行的count/injections/firstAt和遗留reported兼容位在一次去抖global.set整体发布;强杀可丢最后窗口计数,不新增表。不自动发业务Usage或设置reported,遗留位不证明Usage确认。",
50
50
  "test": "tests/usage-evidence.test.mjs:AH-U09"
51
+ },
52
+ {
53
+ "id": "suite-source-selection",
54
+ "name": "套件来源与目录交接配置整体发布",
55
+ "facts": [
56
+ "library:suiteSource",
57
+ "library:sources",
58
+ "library:handoff",
59
+ "library:revision"
60
+ ],
61
+ "medium": "single-snapshot:hanamesh_library",
62
+ "why": "设置写入串行读取最新完整镜像;持久成功后才发布内存,失败保持旧选择,不覆盖并发目录或交接字段。",
63
+ "test": "tests/suite-source.test.mjs:B17 concurrent saves"
51
64
  }
52
65
  ],
53
66
  "boundaries": [
@@ -75,13 +88,13 @@
75
88
  },
76
89
  {
77
90
  "id": "receipt-report",
78
- "name": "usage 席位收到小时 use 事件 → 账本标记 reported",
91
+ "name": "转发观察 → 独立Router诊断镜像",
79
92
  "sides": [
80
- "usage-seat:use-event",
93
+ "router-diagnostics:runtime-observation",
81
94
  "single-snapshot:hanamesh_router_receipts"
82
95
  ],
83
- "safeDirection": "usage-seat:use-event",
84
- "why": "先让席位 recorded/duplicate,再标 reported;允许席位已有而账本未标(下次重报得 duplicate),不允许账本已标而席位从未收到。rejected/withheld/席位缺席都不标。",
96
+ "safeDirection": "router-diagnostics:runtime-observation",
97
+ "why": "先有受控转发观察再累计诊断;允许丢未持久化窗口,不制造业务成功。ready/跨小时/恢复/停止/flush不调用record、不自动标reported,未知事实明确诊断;此边界不声称Usage投递或提交。",
85
98
  "test": "tests/usage-evidence.test.mjs:AH-U04"
86
99
  },
87
100
  {
@@ -94,6 +107,28 @@
94
107
  "safeDirection": "dshmarket-absence-decided",
95
108
  "why": "rc.32:壳的「扩展管理」面板只认一个 market 席位(cordis 的 provide 对同名第二次注册直接抛错)。先读席位(reflect.get(\"market\",false))并问一次 /hanamesh/library/installedPlugins,确认 dshmarket 既没占座也没装,才 provide。宁可席位空着、只留侧栏「市场」入口加一条提示,也不抢座把对方的 provide 打挂;库路由答不上来时 fail open(席位本身不承载持久事实)。",
96
109
  "test": "tests/market-seat.test.mjs:AH-MS01/AH-MS02/AH-MS03"
110
+ },
111
+ {
112
+ "id": "node-ready-binding",
113
+ "name": "已核验文件与账本 → 启用独立 Node 指针",
114
+ "sides": [
115
+ "provision:verified-owned-tree-and-ledger",
116
+ "single-snapshot:hanamesh_node_runtime"
117
+ ],
118
+ "safeDirection": "provision:verified-owned-tree-and-ledger",
119
+ "why": "确认后单源 SHA 下载,文件与精确平台版本检查通过后再发布 active;强杀可留下未绑定的受管文件,不能先宣称 ready。重开只离线复核,绝不自动下载。",
120
+ "test": "tests/managed-node.test.mjs:MN08 X03 real SIGKILL"
121
+ },
122
+ {
123
+ "id": "suite-source-confirmation",
124
+ "name": "复读公开来源与精确声明 → 官方CLI执行",
125
+ "sides": [
126
+ "current-source-and-core-declaration",
127
+ "official-exact-suite-cli"
128
+ ],
129
+ "safeDirection": "current-source-and-core-declaration",
130
+ "why": "预览、确认、执行前和异步声明返回时复读;URL/selection/服务身份或精确tuple/物理baseline变化终止旧确认。Core无generation/watch,不虚构观察能力。",
131
+ "test": "tests/suite-source.test.mjs:B17 execution re-reads"
97
132
  }
98
133
  ],
99
134
  "scope": "REAL_PROCESS + LOCAL_ATOMIC_FILE;不是 DSH 加载、真实浏览器、整机断电或 macOS 验收。",
@@ -0,0 +1,35 @@
1
+ {
2
+ "evidence": "SOURCE",
3
+ "accepted": [
4
+ [
5
+ "1.0.0",
6
+ "1.0.0"
7
+ ],
8
+ [
9
+ "1.1.0",
10
+ "1.2.0"
11
+ ],
12
+ [
13
+ "1.2.0-rc.1+build.001",
14
+ "1.3.1"
15
+ ]
16
+ ],
17
+ "refused": [
18
+ [
19
+ "2.0.0",
20
+ "1.0.0"
21
+ ],
22
+ [
23
+ "1.0.0",
24
+ "2.0.0"
25
+ ],
26
+ [
27
+ "1.01.0",
28
+ "1.0.0"
29
+ ]
30
+ ],
31
+ "additions": {
32
+ "notice": "SOURCE optional notice",
33
+ "updatedAt": "2026-10-09T00:00:00Z"
34
+ }
35
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "evidence": "SOURCE",
3
+ "manifest": {
4
+ "manifestVersion": "1.0.0",
5
+ "providerId": "com.hanamesh.market",
6
+ "name": "SOURCE catalog",
7
+ "attribution": {
8
+ "name": "SOURCE",
9
+ "url": "https://hanamesh.com"
10
+ },
11
+ "transport": {
12
+ "kind": "https-json",
13
+ "endpoint": "https://catalog.hanamesh.com/v1/plugins",
14
+ "method": "GET"
15
+ },
16
+ "query": {
17
+ "supported": [
18
+ "q",
19
+ "cursor",
20
+ "limit"
21
+ ],
22
+ "defaultLimit": 50,
23
+ "maxLimit": 50,
24
+ "sorts": []
25
+ }
26
+ },
27
+ "page": {
28
+ "schemaVersion": "1.0.0",
29
+ "revision": "fixture-2026-09-19",
30
+ "items": [
31
+ {
32
+ "id": "com.hanamesh.vibe-trading",
33
+ "name": "@hanamesh/app-vibe-trading",
34
+ "displayName": "Vibe Trading",
35
+ "summary": "HanaMesh Vibe \u4ea4\u6613\u5e94\u7528\u3002",
36
+ "latestVersion": "0.1.0",
37
+ "categories": [
38
+ "hanamesh-app",
39
+ "finance"
40
+ ],
41
+ "package": {
42
+ "registry": "npm",
43
+ "name": "@hanamesh/app-vibe-trading"
44
+ },
45
+ "publisher": {
46
+ "name": "HanaMesh"
47
+ }
48
+ },
49
+ {
50
+ "id": "com.example.repository-only",
51
+ "name": "repository-only",
52
+ "displayName": "Repository only",
53
+ "summary": "\u53ea\u6709\u6e90\u7801\u4ed3\u5e93\uff0c\u4e0d\u80fd\u7531\u5e94\u7528\u5e93\u5b89\u88c5\u3002",
54
+ "categories": [
55
+ "hanamesh-app"
56
+ ],
57
+ "repository": {
58
+ "url": "https://example.com/repository"
59
+ },
60
+ "publisher": {
61
+ "name": "Example"
62
+ }
63
+ },
64
+ {
65
+ "id": "com.hanamesh.utility-plugin",
66
+ "name": "@hanamesh/utility-plugin",
67
+ "displayName": "Utility plugin",
68
+ "summary": "\u666e\u901a DSH \u63d2\u4ef6\uff0c\u4e0d\u662f HanaMesh \u5e94\u7528\u3002",
69
+ "latestVersion": "1.0.0",
70
+ "categories": [
71
+ "utility"
72
+ ],
73
+ "package": {
74
+ "registry": "npm",
75
+ "name": "@hanamesh/utility-plugin"
76
+ },
77
+ "publisher": {
78
+ "name": "HanaMesh"
79
+ }
80
+ }
81
+ ],
82
+ "page": {
83
+ "total": 3
84
+ }
85
+ },
86
+ "accepted": [
87
+ "1.0.0",
88
+ "1.1.0",
89
+ "1.23.4",
90
+ "1.2.0-rc.1+build.001"
91
+ ],
92
+ "refused": [
93
+ "0.9.0",
94
+ "2.0.0",
95
+ "1",
96
+ "01.0.0",
97
+ "1.01.0",
98
+ "1.0.01",
99
+ "1.0.0-01",
100
+ "1.0.0-",
101
+ "1.0.0+",
102
+ "v1.0.0",
103
+ 1,
104
+ null,
105
+ "1.0.0\n"
106
+ ]
107
+ }
@@ -0,0 +1,4 @@
1
+ export interface CatalogSuiteReport {suite:'catalog-provider'|'catalog-consumer';evidence:'SOURCE';contract:'catalog-major-1';total:number;pass:number;fail:number;results:Array<{id:string;outcome:'pass'|'fail';detail?:string}>;}
2
+ export function runCatalogProviderSuite():Promise<CatalogSuiteReport>;
3
+ /** Defaults to the actual AppHost catalog loader, with explicitly SOURCE transport fixture responses. */
4
+ export function runCatalogConsumerSuite():Promise<CatalogSuiteReport>;
@@ -0,0 +1,50 @@
1
+ /** SOURCE catalog version conformance: real validators and real catalog loader; transport responses are labelled fixtures. */
2
+ import {readFile} from 'node:fs/promises';
3
+ import {validateCatalogManifest,validateProviderPage,loadCatalog} from '../library/catalog.js';
4
+ const read=async path=>JSON.parse(await readFile(new URL(path,import.meta.url),'utf8'));
5
+ const equal=(a,b)=>{if(JSON.stringify(a)!==JSON.stringify(b))throw new Error('Catalog readback differs from fixture');};
6
+ const refuses=async(run,code)=>{try{await run();}catch(error){if(!code||error.code===code)return;throw error;}throw new Error('Expected catalog refusal');};
7
+ async function runner(suite,cases){
8
+ const results=[];
9
+ for(const [id,run] of cases)try{await run();results.push({id,outcome:'pass'});}catch(error){results.push({id,outcome:'fail',detail:error.message});}
10
+ return{suite,evidence:'SOURCE',contract:'catalog-major-1',total:results.length,pass:results.filter(x=>x.outcome==='pass').length,fail:results.filter(x=>x.outcome==='fail').length,results};
11
+ }
12
+ export async function runCatalogProviderSuite(){
13
+ const fixture=await read('./fixtures/provider.json');
14
+ const manifestSchema=await read('../../schemas/catalog-source.schema.json'),pageSchema=await read('../../schemas/catalog-provider-page.schema.json');
15
+ const cases=[];
16
+ for(const version of fixture.accepted)cases.push(['accepted/'+version,()=>{
17
+ const manifest={...fixture.manifest,manifestVersion:version},page={...fixture.page,schemaVersion:version};
18
+ equal(validateCatalogManifest(manifest),manifest);equal(validateProviderPage(page),page);
19
+ if(!new RegExp(manifestSchema.properties.manifestVersion.pattern,'u').test(version)||!new RegExp(pageSchema.properties.schemaVersion.pattern,'u').test(version))throw new Error('Shipped schema rejects compatible version');
20
+ }]);
21
+ for(const version of fixture.refused)cases.push(['refused/'+JSON.stringify(version),async()=>{
22
+ await refuses(()=>validateCatalogManifest({...fixture.manifest,manifestVersion:version}),'INVALID_CATALOG_MANIFEST');
23
+ await refuses(()=>validateProviderPage({...fixture.page,schemaVersion:version}),'INVALID_CATALOG_PAGE');
24
+ for(const property of [manifestSchema.properties.manifestVersion,pageSchema.properties.schemaVersion])if(typeof version==='string'&&new RegExp(property.pattern,'u').test(version))throw new Error('Shipped schema accepts refused version');
25
+ }]);
26
+ cases.push(['shape-required-method',()=>refuses(()=>validateCatalogManifest({...fixture.manifest,manifestVersion:'1.1.0',transport:{...fixture.manifest.transport,method:'POST'}}),'INVALID_CATALOG_MANIFEST')]);
27
+ cases.push(['shape-invalid-item',()=>refuses(()=>validateProviderPage({...fixture.page,schemaVersion:'1.1.0',items:[{...fixture.page.items[0],updatedAt:'yesterday'}]}),'INVALID_CATALOG_PAGE')]);
28
+ cases.push(['shape-unknown-field',()=>refuses(()=>validateProviderPage({...fixture.page,schemaVersion:'1.1.0',unexpected:true}),'INVALID_CATALOG_PAGE')]);
29
+ return runner('catalog-provider',cases);
30
+ }
31
+ export async function runCatalogConsumerSuite(consume=loadCatalog){
32
+ const fixture=await read('./fixtures/provider.json'),consumer=await read('./fixtures/consumer.json');const cases=[];
33
+ const input=(manifestVersion,schemaVersion)=>{
34
+ const manifest={...fixture.manifest,manifestVersion,attribution:{...fixture.manifest.attribution,notice:consumer.additions.notice}};
35
+ const page={...fixture.page,schemaVersion,items:fixture.page.items.map(item=>({...item,updatedAt:consumer.additions.updatedAt}))};
36
+ const requests=[],responses=[manifest,page];
37
+ return{page,requests,options:{sources:[{manifestUrl:new URL('/catalog-source.json',manifest.transport.endpoint).href}],fetchImpl:async(url,init)=>{requests.push({url:String(url),init});return new Response(JSON.stringify(responses.shift()),{headers:{'content-type':'application/json'}});}}};
38
+ };
39
+ for(const pair of consumer.accepted)cases.push(['accepted/'+pair.join('/'),async()=>{
40
+ const probe=input(...pair),result=await consume(probe.options);equal(result.items,probe.page.items);equal(result.schemaVersion,probe.page.schemaVersion);
41
+ if(probe.requests.length!==2||probe.requests.some(x=>x.init.redirect!=='manual'||x.init.headers['accept-encoding']!=='identity'))throw new Error('Catalog transport trust controls changed');
42
+ }]);
43
+ for(const pair of consumer.refused)cases.push(['refused/'+pair.join('/'),()=>refuses(()=>consume(input(...pair).options))]);
44
+ cases.push(['trust-foreign-endpoint',async()=>{
45
+ const manifest={...fixture.manifest,manifestVersion:'1.1.0',transport:{...fixture.manifest.transport,endpoint:'https://foreign.example/v1/plugins'}};let calls=0;
46
+ await refuses(()=>consume({sources:[{manifestUrl:'https://catalog.hanamesh.com/catalog-source.json'}],fetchImpl:async()=>{calls++;return new Response(JSON.stringify(manifest),{headers:{'content-type':'application/json'}});}}),'INVALID_CATALOG_MANIFEST');
47
+ equal(calls,1);
48
+ }]);
49
+ return runner('catalog-consumer',cases);
50
+ }
@@ -1,19 +1,37 @@
1
1
  export const name:'hanamesh-app-host-client';
2
2
  export const inject:readonly ['slots','locale'];
3
- export function apply(ctx:unknown):void;
3
+ /** Trusted producer configuration; normal Loader activation defaults to false. */
4
+ export function apply(ctx:unknown,options?:{verification?:boolean}):void;
4
5
  export function ProvidersSection():unknown;
5
6
  /** Settings section「市场目录源」(rc.28 name; the export keeps its rc.11 identifier). */
6
7
  export function LibrarySourcesSection():unknown;
8
+ export function HandoffSettingsSection():unknown;
9
+ /** Plugin-local named settings and explicitly confirmed standalone Node preparation. */
10
+ export function NodeRuntimeSection():unknown;
7
11
  /** Sidebar entry「市场」; hidden while the `market` seat owner renders the market itself. */
8
12
  export function LibraryAction():unknown;
9
13
  /** The HanaMesh market page (applications + plugins; install / upgrade / uninstall / restart notice).
10
14
  * `embedded` renders it inline for the Extension Management tab instead of as the shell overlay. */
11
- export function LibraryOverlay(props?:{embedded?:boolean,preferredSubsectionId?:string}):unknown;
15
+ export function LibraryOverlay(props?:{embedded?:boolean,preferredSubsectionId?:string,verification?:boolean}):unknown;
12
16
  /** rc.32: the「只能其一」notice shown at the top of the market page when dshmarket holds the seat. */
13
17
  export function MarketConflictNotice():unknown;
18
+ /** Identifiers only; metadata and confirmation are owned by the client's market. */
19
+ /** rc.8: `contractVersion` optionally declares the install-target contract the caller speaks; absent means v1, any other value is refused with CONTRACT_VERSION_UNSUPPORTED. */
20
+ export interface InstallTarget {itemId?:string;packageName?:string;contractVersion?:'1';}
21
+ export interface InstallTargetReceipt {status:'confirmation-required'|'installing'|'already-installed'|'superseded';itemId?:string;packageName?:string;}
22
+ /** Show/resolve a target without installing. Resolves once confirmation is ready; rejects with a visible market error. */
23
+ export function openInstallTarget(input:InstallTarget):Promise<InstallTargetReceipt>;
14
24
  /** rc.32: the client-side `market` service object read by the shell's Extension Management panel. */
15
- export function createMarketSeat():{render(options?:{preferredSubsectionId?:string}):unknown,setSettingsVisible(visible:boolean):void};
25
+ export function createMarketSeat(options?:{verification?:boolean}):{render(options?:{preferredSubsectionId?:string,verification?:boolean}):unknown,setSettingsVisible(visible:boolean):void,openInstallTarget(input:InstallTarget):Promise<InstallTargetReceipt>};
16
26
  export const MARKET_SEAT:'market';
17
27
  export const MARKET_CONFLICT_TEXT:string;
18
28
  /** Test/inspection view of the module-level market state; not part of the DSH contract. */
19
29
  export function marketState():{conflict:string,entryVisible:boolean};
30
+
31
+ /** Normal navigation on the authenticated workspace URL; app-host consumes this fragment. */
32
+ export const INSTALL_TARGET_HASH:'#hanamesh-install?';
33
+ /** Install-target contract version this market implements; see schemas/install-target.schema.json. */
34
+ export const INSTALL_TARGET_CONTRACT_VERSION:'1';
35
+
36
+ /** AppHost-owned registry selection, independent of catalog manifest sources. */
37
+ export function SuiteSourceSettingsSection():unknown;