@hanamesh/dsh-app-host 0.6.20 → 0.6.22
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.
- package/README.md +8 -4
- package/dist/client-ui.d.ts +4 -1
- package/dist/client-ui.js +27 -31
- package/dist/dsh.d.ts +1 -1
- package/dist/dsh.js +4 -6
- package/dist/install-target/fixtures/catalog.json +99 -8
- package/dist/install-target/fixtures/install-failure-cases.json +385 -35
- package/dist/install-target/fixtures/reference-consumer.js +1 -1
- package/dist/install-target/suite.d.ts +2 -1
- package/dist/install-target/suite.js +28 -8
- package/dist/library/catalog.js +24 -7
- package/dist/library/diagnostics.js +0 -1
- package/dist/library/github-target.js +42 -0
- package/dist/library/handoff.js +5 -2
- package/dist/library/install.js +27 -64
- package/dist/library/locate.js +4 -13
- package/dist/library/recovery.js +5 -3
- package/dist/library/routes.js +1 -0
- package/dist/library/service.js +35 -19
- package/dist/library/suite.js +9 -10
- package/docs/APP_PACKAGE.md +1 -1
- package/docs/CONTRACT.md +6 -6
- package/docs/DSH_COMPATIBILITY.md +1 -1
- package/docs/INSTALL_TARGET.md +22 -6
- package/docs/LIBRARY.md +4 -15
- package/docs/LICENSES.json +6 -6
- package/docs/SECURITY.md +2 -0
- package/node_modules/@hanamesh/lib-provision/bin/hanamesh-provision.js +0 -0
- package/package.json +27 -24
- package/schemas/catalog-provider-page.schema.json +97 -10
- package/schemas/install-target.schema.json +252 -38
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
0.6.
|
|
1
|
+
0.6.21 候选:普通市场和网站交接消费 Indexer 的固定 GitHub SHA/子目录/包名/构建名单。客户端沿原确认页展示来源、完整 commit 与本机构建提示;确认回传同一目标,目录更新不得换 SHA。执行仍走受控官方 DSH CLI / pnpm,读回精确来源与启用项后报告需完全退出重开;没有改上游或另写安装器。详见 [安装目标](docs/INSTALL_TARGET.md)。初轮已完成隔离 DSH、网站及真实 DTO 验收;本轮 R25 另修未匹配固定目标时的拒绝与退休目录版本字段,仍待复审,不宣称已发布。
|
|
2
|
+
|
|
3
|
+
0.6.22 候选:普通插件只执行目录固定目标;缺 installMethods 即拒绝。套件安装命令只消费 Core,删除普通包名的元数据查询和规则加载。
|
|
2
4
|
|
|
3
5
|
0.6.15 候选:市场保留官方 CLI 的 stdout/stderr 真实失败原因并脱敏,在卡片与安装确认的技术详情中显示。正文显示 pnpm 真实错误类别;宿主发布时间检查失败时列出受影响包与实际 cutoff;HanaMesh 总包安装/升级使用精确发布版本,发布后即可验收;不修改 profile、pnpm 供应链策略或安装执行路径。
|
|
4
6
|
|
|
@@ -80,7 +82,7 @@ CLI-8:未配置来源的新用户默认请求 HanaMesh 视图(`https://marke
|
|
|
80
82
|
|
|
81
83
|
> 分支 `t6-usage-receipts`(2026-09-22,设计定案 §3「协议层」,T6,**未发版**,由派发 session 合入下一 rc):**Router 使用回执。** app-host 自己的 storage domain `hanamesh_router_receipts` 按小时记 `{appId, providerId, model, hour, count}`(Router 每次注入记路由与 `injections`,网关每次转发 `count+1`;不记内容、不记值),`GET /hanamesh/router/receipts[?appId=]` 可查本地账。usage 席位上报的 `use` 事件改为在 **UTC 小时结束或应用最后一个活实例停止时**发出(`occurredAt` 仍是该小时首个转发请求;同 key 一小时一条不变),并附 `targetRef=appId` 与该小时的 `receipt {providerId, model, count}`;无席位只记本地账不报错;宿主死机前未报的小时在下次启动由账本补报(席位按 key 去重)。需要 usage `0.2.0-rc.7`(席位接受三个可选键;更早版本会 `rejected INVALID_RECORD_INPUT`,只 debug 日志)。
|
|
82
84
|
|
|
83
|
-
> rc.28(2026-09-22,设计定案 §4「HanaMesh 市场」,T4):**「应用库」升级为 HanaMesh 市场——插件与应用同一入口、同一安装路径。** 侧栏入口与页面标题改为「市场」/「HanaMesh 市场」,设置段「应用库来源」改名「市场目录源」。目录默认列出**全部**类别(客户端显式 `category=`),筛选 = 全部 / 应用(`hanamesh-app`)/ 插件(客户端视图:非应用的 npm 条目)/ 目录页里出现过的每个类别;搜索、「更多」保留。每条目带 `kind`(`application` / `plugin` / `listing`)、`installed`(已装行)与 `upgradeAvailable
|
|
85
|
+
> rc.28(2026-09-22,设计定案 §4「HanaMesh 市场」,T4):**「应用库」升级为 HanaMesh 市场——插件与应用同一入口、同一安装路径。** 侧栏入口与页面标题改为「市场」/「HanaMesh 市场」,设置段「应用库来源」改名「市场目录源」。目录默认列出**全部**类别(客户端显式 `category=`),筛选 = 全部 / 应用(`hanamesh-app`)/ 插件(客户端视图:非应用的 npm 条目)/ 目录页里出现过的每个类别;搜索、「更多」保留。每条目带 `kind`(`application` / `plugin` / `listing`)、`installed`(已装行)与 `upgradeAvailable`(审核 npm `installTarget.version` 严格新于已装版本)。卡片状态:未装「安装」/ 已装(应用「打开」「卸载」,插件「卸载」)/ 可升级「升级」(同一 `dsh plugin add --save-exact` 路径)/ 需重启。**已装列表含插件**:扫 profile `package.json` 的 `dependencies`(减去应用包),`bundle`(声明 `dsh.bundle`)与 `active`(在 `dsh.profile.bundles`);「需重启」由本插件启动时的依赖快照推出:启动后新增 → `installed-not-loaded`,启动后移除 → `uninstalled-not-unloaded`。任一操作完成或列表含上述状态时页面顶部出现「需重启 DSH」:在桌面壳内(DSH 页在壳 iframe 里)给出 `hanamesh://restart` 深链按钮,官方 DSH 直开浏览器时只提示「请手动重启 DSH」。新路由:`GET /hanamesh/library/installedPlugins` → `{plugins,apps,restartRequired}`;`POST /hanamesh/library/plugins/install {packageName}`(须在启用目录里能搜到该包;应用包走应用路径)与 `POST /hanamesh/library/plugins/uninstall {packageName}`(应用包转应用卸载:runtime + 运行中检查)→ 202 + 事件流;`POST /hanamesh/library/install` 现接受 `{itemId, packageName?}`(`packageName` 用于目录精确查找,插件条目也可装)。旧路由全部保留。**修 `LIB-PROVISION-INPUT`**:`provision` / `uninstall` / `plugins/*` 缺字段或字段非法 → 400 `INVALID_INPUT`,操作不启动(此前 TypeError → 事件 `LIBRARY_OPERATION_FAILED`)。受保护包 `hanamesh-core` / `hanamesh-usage` / `@hanamesh/dsh-app-host`(含旧写法)永不经市场装卸(`PACKAGE_DENIED`;rc.27 前阻止名单写的是从未存在过的 `@hanamesh/dsh-core`)。不做 T5(`provide('market')`、dshmarket 互斥、recommender 接线)。AH-M01–M08 测试,M13/M14 变异;真实门见 `docs/acceptance/t4-market-20260922/`。
|
|
84
86
|
|
|
85
87
|
> 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 变异。
|
|
86
88
|
|
|
@@ -96,7 +98,7 @@ CLI-8:未配置来源的新用户默认请求 HanaMesh 视图(`https://marke
|
|
|
96
98
|
>
|
|
97
99
|
> rc.19(2026-09-21):网关不再只认 cookie——嵌入式 webview(HanaMesh 桌面 Tauri/WKWebView、开了跟踪防护的 WebView2)里应用 iframe 相对壳的顶层 origin 是第三方,`SameSite=Strict` 的引导 cookie 被丢弃,303 之后每个请求都 403(响应带 `frame-ancestors 'none'`)→ 用户看到空白 iframe(2026-09-21 桌面 rc.4 + Vibe 实测)。rc.19 在 cookie 缺席时改用 Fetch Metadata:`sec-fetch-site: same-origin`(应用自身子资源/XHR)、或 `same-site` + `iframe` + 父 origin referer(引导后的框架导航)、或应用 origin 的 WebSocket 握手,且必须已有一张为仍在有效期 lease 消费过的引导票;cross-site / `none`(地址栏)一律拒绝。H15 三条测试;浏览器直开仍走 cookie。
|
|
98
100
|
>
|
|
99
|
-
> rc.18(2026-09-20):应用库卡片跟踪安装/补齐运行时/卸载操作——按钮进入「…中…」,订阅 `/hanamesh/library/events` 直到 `-done`/`-failed`,失败时在卡片上显示错误码与可读原因(如 `
|
|
101
|
+
> rc.18(2026-09-20):应用库卡片跟踪安装/补齐运行时/卸载操作——按钮进入「…中…」,订阅 `/hanamesh/library/events` 直到 `-done`/`-failed`,失败时在卡片上显示错误码与可读原因(如 `NOT_INSTALLABLE`:目录没有审核过的固定目标),并提供「重试安装」。用户 2026-09-20 实测:点安装无任何反应。宿主逻辑不变。
|
|
100
102
|
|
|
101
103
|
**交付状态:rc.3 用户 ACCEPTED 2026-09-13;rc.4–rc.12 为增量 🧪;rc.13 只补上架前提(MIT 许可证、`repository` 字段、DSH peer 精确钉 `0.1.5-alpha.1`);rc.14 删除客户端里对 `hanameshCore` 的死读取(浏览器侧 cordis 上下文不含宿主服务,该读取恒为 null,且把「未安装 HanaMesh Core」误显给已装用户)——本包对 Core 现在零引用,Core 状态只在 Core 自己的设置段;仍待用户验收。**
|
|
102
104
|
|
|
@@ -238,4 +240,6 @@ Actions runs on the standard public/free `macos-15` arm64 runner because the exi
|
|
|
238
240
|
|
|
239
241
|
## Core 公开套件声明的测试依赖
|
|
240
242
|
|
|
241
|
-
源码测试通过 `@hanamesh/core/suite` 读取 Core 单源公开命令。`@hanamesh/core` 是仓库声明的 devDependency,按 npm 版本范围 `^0.3.
|
|
243
|
+
源码测试通过 `@hanamesh/core/suite` 读取 Core 单源公开命令。`@hanamesh/core` 是仓库声明的 devDependency,按 npm 版本范围 `^0.3.30` 从公开 npm 安装,冻结 pnpm 锁记录实际版本与 SRI;许可证记录见 `docs/LICENSES.json`。Core 不成为运行时依赖或 bundled 包。
|
|
244
|
+
|
|
245
|
+
套件升级的执行定义来自可信 Cordis Core 声明 `upgrade.installation:{name,version,command,args}`;AppHost将实际profile与可选registry交给Core,使用返回的完整argv,不自行加flag、解析命令前缀或补默认npm源。缺定义时具名拒绝,参数纳入确认快照。该数据接口避免AppHost在Core新版本发布前依赖未发布SDK。
|
package/dist/client-ui.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ export function LibraryOverlay(props?:{embedded?:boolean,preferredSubsectionId?:
|
|
|
17
17
|
export function MarketConflictNotice():unknown;
|
|
18
18
|
/** Identifiers only; metadata and confirmation are owned by the client's market. */
|
|
19
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
|
|
20
|
+
export type PackageInstallTarget =
|
|
21
|
+
| {source:'npm';name:string;version:string;allowBuild:string[]}
|
|
22
|
+
| {source:'github';repo:string;ref:string;path:string|null;packageName:string;allowBuild:string[]};
|
|
23
|
+
export interface InstallTarget {itemId?:string;packageName?:string;contractVersion?:'1';installTarget?:PackageInstallTarget;}
|
|
21
24
|
export interface InstallTargetReceipt {status:'confirmation-required'|'installing'|'already-installed'|'superseded';itemId?:string;packageName?:string;}
|
|
22
25
|
/** Show/resolve a target without installing. Resolves once confirmation is ready; rejects with a visible market error. */
|
|
23
26
|
export function openInstallTarget(input:InstallTarget):Promise<InstallTargetReceipt>;
|
package/dist/client-ui.js
CHANGED
|
@@ -129,15 +129,11 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
129
129
|
"copy121": "固定规则(不能关)",
|
|
130
130
|
"copy122": "为什么:",
|
|
131
131
|
"copy123": "安装命令返回成功,但 profile 读回的版本与固定版本不一致",
|
|
132
|
-
"copy124": "无法查询 DSH 配置的 registry;检查 DSH 源设置与网络,展开技术详情后手动重试",
|
|
133
|
-
"registryLookupTimeout": "registry 查询超过 30 秒;检查 DSH 源设置与网络后手动重试",
|
|
134
|
-
"registryConfigUnavailable": "DSH 未提供可读的源配置;检查客户端插件管理器,展开技术详情",
|
|
135
132
|
"copy125": "DSH 安装命令失败,请展开技术详情查看原始原因",
|
|
136
|
-
"installAgeRejected": "
|
|
133
|
+
"installAgeRejected": "宿主的依赖发布时间检查未通过。请核对安装目标包含精确版本并保留技术详情;若仍失败,请在 DSH 设置中检查并升级 DSH。",
|
|
137
134
|
"installAffectedPackages": "受影响包:",
|
|
138
135
|
"copy126": "当前宿主未提供安装参数(profile / node 路径)",
|
|
139
136
|
"copy127": "目录里已没有这一项,刷新后重试",
|
|
140
|
-
"copy128": "registry 上的最新版是预发布版(rc),客户端未允许安装预发布版",
|
|
141
137
|
"copy129": "运行时归档下载失败,检查网络或来源",
|
|
142
138
|
"copy130": "10 分钟内没有结果,可稍后重试",
|
|
143
139
|
"copy131": "HanaMesh 套件自身不能从市场安装或卸载",
|
|
@@ -198,7 +194,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
198
194
|
"copy185": "检查兼容升级",
|
|
199
195
|
"copy186": "重试安装",
|
|
200
196
|
"copy187": "升级",
|
|
201
|
-
"copy188": "升级到 ",
|
|
202
197
|
"copy189": "补齐运行时",
|
|
203
198
|
"copy190": "卸载",
|
|
204
199
|
"copy191": "已卸载,重启 DSH 后生效",
|
|
@@ -224,8 +219,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
224
219
|
"copy211": "查看安装目标",
|
|
225
220
|
"copy212": "市场安装确认",
|
|
226
221
|
"copy213": "插件名",
|
|
227
|
-
"copy214": "版本",
|
|
228
|
-
"copy215": "目录未提供版本",
|
|
229
222
|
"copy216": "测试目录(fixture)",
|
|
230
223
|
"copy217": "当前市场目录",
|
|
231
224
|
"copy218": "确认后升级 HanaMesh 总包及其锁定组件;需要完全退出并重新打开客户端。",
|
|
@@ -281,7 +274,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
281
274
|
"copy268": "交接状态只给发起它的那个网站看",
|
|
282
275
|
"copy269": "一个网站不能读另一个网站的交接",
|
|
283
276
|
"copy270": "交接请求体不超过 4096 字节",
|
|
284
|
-
"copy271": "
|
|
277
|
+
"copy271": "交接只包含目录身份、合约版本及已审核的结构化安装目标;正文上限为 4096 字节,不接受来源命令",
|
|
285
278
|
"copy272": "端口在 1024–65535 之间、互不重复,至少一个",
|
|
286
279
|
"copy273": "1024 以下要管理员权限;没有端口就没有地方让网站找到",
|
|
287
280
|
"copy274": "网站必须写成来源(协议 + 域名 [+ 端口]),http 只允许 127.0.0.1 / localhost",
|
|
@@ -437,15 +430,11 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
437
430
|
"copy121": "Required rules",
|
|
438
431
|
"copy122": "Reason: ",
|
|
439
432
|
"copy123": "Installation command succeeded, but the version read from the profile differs from the confirmed version",
|
|
440
|
-
"copy124": "Cannot query the registry configured in DSH. Check DSH source settings and network, expand technical details, then retry manually",
|
|
441
|
-
"registryLookupTimeout": "Registry lookup exceeded 30 seconds. Check DSH source settings and network, then retry manually",
|
|
442
|
-
"registryConfigUnavailable": "DSH did not expose readable registry configuration. Check the client plugin manager and expand technical details",
|
|
443
433
|
"copy125": "DSH installation failed. Expand Technical details for the original cause",
|
|
444
|
-
"installAgeRejected": "The host rejected a dependency
|
|
434
|
+
"installAgeRejected": "The host rejected a dependency release-age check. Verify the exact installation target and retain Technical details. If it still fails, check and upgrade DSH in Settings.",
|
|
445
435
|
"installAffectedPackages": "Affected packages: ",
|
|
446
436
|
"copy126": "This host has not provided installation parameters (profile / Node path)",
|
|
447
437
|
"copy127": "This item is no longer in the catalog. Refresh before trying again",
|
|
448
|
-
"copy128": "The latest registry version is a prerelease, which this client has not allowed",
|
|
449
438
|
"copy129": "Runtime archive download failed. Check the network or source",
|
|
450
439
|
"copy130": "No result within 10 minutes. Check the installed state before trying again",
|
|
451
440
|
"copy131": "The HanaMesh suite cannot be installed or uninstalled through the market",
|
|
@@ -506,7 +495,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
506
495
|
"copy185": "Check compatible upgrade",
|
|
507
496
|
"copy186": "Retry installation",
|
|
508
497
|
"copy187": "Upgrade",
|
|
509
|
-
"copy188": "Upgrade to ",
|
|
510
498
|
"copy189": "Prepare runtime",
|
|
511
499
|
"copy190": "Uninstall",
|
|
512
500
|
"copy191": "Uninstalled; restart DSH to apply",
|
|
@@ -532,8 +520,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
532
520
|
"copy211": "Review installation target",
|
|
533
521
|
"copy212": "Confirm market installation",
|
|
534
522
|
"copy213": "Plugin name",
|
|
535
|
-
"copy214": "Version",
|
|
536
|
-
"copy215": "No version provided by catalog",
|
|
537
523
|
"copy216": "Test catalog (fixture)",
|
|
538
524
|
"copy217": "Current market catalog",
|
|
539
525
|
"copy218": "Confirmation upgrades the HanaMesh bundle and its locked components. Fully quit and reopen the client afterwards.",
|
|
@@ -589,7 +575,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
589
575
|
"copy268": "Handoff status is visible only to the website that created it.",
|
|
590
576
|
"copy269": "One website cannot read another website’s handoffs.",
|
|
591
577
|
"copy270": "Handoff request body must not exceed 4096 bytes.",
|
|
592
|
-
"copy271": "A
|
|
578
|
+
"copy271": "A handoff contains only catalog identity, contract version and the reviewed package target. The body limit is 4096 bytes; source commands are not accepted.",
|
|
593
579
|
"copy272": "Provide at least one distinct port between 1024 and 65535.",
|
|
594
580
|
"copy273": "Lower ports need administrator permissions. Without a port the website cannot find this client.",
|
|
595
581
|
"copy274": "Websites must be origins (scheme + domain [+ port]). HTTP is allowed only for 127.0.0.1 / localhost.",
|
|
@@ -621,6 +607,8 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
621
607
|
"copy301": "Supports macOS 13.5+ (Apple Silicon / Intel). Windows installation, guardian and cancellation verification are not connected; this flow does not support Windows."
|
|
622
608
|
}
|
|
623
609
|
};
|
|
610
|
+
Object.assign(COPY.zh,{githubRepository:'来源仓库',githubCommit:'固定 commit',githubPath:'仓库子目录',githubBuild:'会在本机执行构建脚本',githubBuildPolicy:'确认后将按名单允许构建;pnpm 会把许可保存到当前 profile。',githubNoBuild:'未授予构建脚本许可'});
|
|
611
|
+
Object.assign(COPY.en,{githubRepository:'Source repository',githubCommit:'Pinned commit',githubPath:'Repository subdirectory',githubBuild:'Build scripts will run on this computer',githubBuildPolicy:'Confirmation permits the listed builds; pnpm saves these permissions in the current profile.',githubNoBuild:'No build scripts are approved'});
|
|
624
612
|
const COPY_KEYS=new Map(Object.entries(COPY.zh).map(([key,text])=>[text,key]));
|
|
625
613
|
let localeService=null;
|
|
626
614
|
function t(text){if(typeof text==='function')return text();const key=COPY_KEYS.get(text);if(!key)return text;return localeService?localeService.bind('hanamesh.apphost')(key):COPY.zh[key];}
|
|
@@ -666,6 +654,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
666
654
|
let targetSelection=null,targetSequence=0,pendingOperations={};
|
|
667
655
|
const targetListeners=new Set(),pendingListeners=new Set();
|
|
668
656
|
const INSTALL_TARGET_HASH='#hanamesh-install?',INSTALL_TARGET_CONTRACT_VERSION='1';
|
|
657
|
+
const targetQuery=input=>new URLSearchParams({...input,...(input.installTarget?{installTarget:JSON.stringify(input.installTarget)}:{})});
|
|
669
658
|
const CORE_SUITE_FAILURES={CORE_SUITE_DECLARATION_MISSING:t('Core 未提供套件声明'),CORE_SUITE_DECLARATION_INVALID:t('Core 套件声明无法用于精确安装。')};
|
|
670
659
|
const suiteTargetFailure=target=>target.previewFailed?t('兼容升级检查未通过,尚未执行安装:')+(t(CORE_SUITE_FAILURES[target.error])??target.error??t('检测不到结果')):t(CORE_SUITE_FAILURES[target.error])??(target.details?.stage==='suite-upgrade'?t('套件升级未完成:')+(target.error??t('检测不到结果'))+t('。请核对当前版本;完全退出后可使用 HanaMesh 设置中的补齐命令修复并重新打开。'):t('套件升级未完成或结果尚未确认:')+(target.error??t('检测不到结果'))+t('。请核对已装版本;不会自动重试。'));
|
|
671
660
|
const setTarget=value=>{targetSelection=value;for(const listener of targetListeners)listener(value);};
|
|
@@ -677,11 +666,12 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
677
666
|
if(!input||typeof input!=='object'||Array.isArray(input))throw new Error('INVALID_INPUT');
|
|
678
667
|
// rc.8: optional contract declaration; absent keeps v1 semantics, an unsupported version is refused before any request.
|
|
679
668
|
if(input.contractVersion!==undefined&&input.contractVersion!==INSTALL_TARGET_CONTRACT_VERSION)throw new Error('CONTRACT_VERSION_UNSUPPORTED');
|
|
680
|
-
if(Object.keys(input).some(key=>!['itemId','packageName','contractVersion'].includes(key))||(!input.itemId&&!input.packageName)||
|
|
669
|
+
if(Object.keys(input).some(key=>!['itemId','packageName','contractVersion','installTarget'].includes(key))||(!input.itemId&&!input.packageName)||
|
|
670
|
+
(input.installTarget!==undefined&&(!input.itemId||!input.installTarget||typeof input.installTarget!=='object'||Array.isArray(input.installTarget)))||
|
|
681
671
|
(input.itemId!==undefined&&(typeof input.itemId!=='string'||!input.itemId.length||input.itemId.length>160||/[\u0000-\u001f\u007f]/.test(input.itemId)))||
|
|
682
672
|
(input.packageName!==undefined&&(typeof input.packageName!=='string'||input.packageName.length>214||!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(input.packageName))))throw new Error('INVALID_INPUT');
|
|
683
673
|
setTarget({status:'resolving',input:{...input}});
|
|
684
|
-
const query=
|
|
674
|
+
const query=targetQuery(input),resolved=await request('/hanamesh/library/target?'+query);
|
|
685
675
|
if(sequence!==targetSequence)return{status:'superseded'};
|
|
686
676
|
const item=resolved.item,op=pendingOperations[item.id];
|
|
687
677
|
const status=op?.busy?'installing':['registered','installed','installed-not-loaded'].includes(item.installed?.state)&&!item.upgradeAvailable?'already-installed':'confirmation-required';
|
|
@@ -707,7 +697,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
707
697
|
if(handoffIssue?.poll)setHandoffIssue(null);
|
|
708
698
|
for(const row of value.handoffs??[]){
|
|
709
699
|
if(row.state!=='pending'||handled.has(row.handoffId))continue;handled.add(row.handoffId);
|
|
710
|
-
const input={...(row.itemId?{itemId:row.itemId}:{}),...(row.packageName&&row.itemId!=='hanamesh:suite-upgrade'?{packageName:row.packageName}:{}),contractVersion:INSTALL_TARGET_CONTRACT_VERSION};
|
|
700
|
+
const input={...(row.itemId?{itemId:row.itemId}:{}),...(row.packageName&&row.itemId!=='hanamesh:suite-upgrade'?{packageName:row.packageName}:{}),...(row.installTarget?{installTarget:row.installTarget}:{}),contractVersion:INSTALL_TARGET_CONTRACT_VERSION};
|
|
711
701
|
let opened=false;
|
|
712
702
|
try{await openInstallTarget(input,{handoffId:row.handoffId});opened=true;}
|
|
713
703
|
catch(error){noteHandoffIssue(t('确认框打不开'),error);await reportHandoff(row.handoffId,'failed',{code:errorCode(error)});}
|
|
@@ -720,7 +710,9 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
720
710
|
const hash=globalThis.location?.hash;if(!hash?.startsWith(INSTALL_TARGET_HASH))return;
|
|
721
711
|
const params=new URLSearchParams(hash.slice(INSTALL_TARGET_HASH.length));
|
|
722
712
|
if(new Set(params.keys()).size!==[...params.keys()].length){targetSequence++;if(entryVisible)setLibraryVisible(true);setTarget({status:'failed',error:'INVALID_INPUT'});return;}
|
|
723
|
-
|
|
713
|
+
const input=Object.fromEntries(params);
|
|
714
|
+
if(input.installTarget!==undefined){try{input.installTarget=JSON.parse(input.installTarget);}catch{setTarget({status:'failed',error:'INVALID_INPUT'});return;}}
|
|
715
|
+
void openInstallTarget(input).catch(()=>{});
|
|
724
716
|
}
|
|
725
717
|
// rc.32 market seat. The shell's Extension Management panel (dsh-tauri-panel-extension) reads the client-side
|
|
726
718
|
// cordis service `market` via `ctx.reflect.get('market')` and shows a 「市场」 tab when it is there; it calls
|
|
@@ -841,12 +833,12 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
841
833
|
defaults&&names?h('div',null,h('h3',null,t('设置名称与默认值')),h('dl',null,...['enabled','ports','allowedOrigins','ttlMs','pollMs'].flatMap(key=>[h('dt',{key:key+'-name'},names[key]),h('dd',{key:key+'-value'},Array.isArray(defaults[key])?defaults[key].join(', '):typeof defaults[key]==='boolean'?(defaults[key]?t('开'):t('关')):String(defaults[key]))]))):null,
|
|
842
834
|
value?.rules?h('div',null,h('h3',null,t('固定规则(不能关)')),h('ul',null,...value.rules.map(row=>h('li',{key:row.rule},t(row.rule),h('br',null),h('small',null,t('为什么:')+t(row.why)))))):null));
|
|
843
835
|
}
|
|
844
|
-
const FAILURE_REASONS={...CORE_SUITE_FAILURES,INSTALL_READBACK_MISMATCH:t('安装命令返回成功,但 profile 读回的版本与固定版本不一致'),
|
|
836
|
+
const FAILURE_REASONS={...CORE_SUITE_FAILURES,INSTALL_READBACK_MISMATCH:t('安装命令返回成功,但 profile 读回的版本与固定版本不一致'),DSH_PLUGIN_FAILED:t('DSH 安装命令失败,请展开技术详情查看原始原因'),LIBRARY_INSTALL_UNAVAILABLE:t('当前宿主未提供安装参数(profile / node 路径)'),CATALOG_ITEM_MISSING:t('目录里已没有这一项,刷新后重试'),RUNTIME_ARCHIVE_UNAVAILABLE:t('运行时归档下载失败,检查网络或来源'),OPERATION_TIMEOUT:t('10 分钟内没有结果,可稍后重试'),PACKAGE_DENIED:t('HanaMesh 套件自身不能从市场安装或卸载'),INSTANCE_IN_USE:t('先关闭该应用的所有视图再卸载')};
|
|
845
837
|
const failureReason=(code,details)=>{
|
|
846
838
|
const diagnostic=code==='DSH_PLUGIN_FAILED'?details?.diagnostic??'':'',pnpmCode=diagnostic.match(/\bERR_PNPM_[A-Z0-9_]+\b/)?.[0];
|
|
847
839
|
if(pnpmCode==='ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION'){
|
|
848
840
|
const packages=[...new Set([...diagnostic.matchAll(/((?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\s+was published\b/g)].map(match=>match[1]))];
|
|
849
|
-
return pnpmCode+' · '+t('
|
|
841
|
+
return pnpmCode+' · '+t('宿主的依赖发布时间检查未通过。请核对安装目标包含精确版本并保留技术详情;若仍失败,请在 DSH 设置中检查并升级 DSH。')+(packages.length?' '+t('受影响包:')+packages.join(', '):'');
|
|
850
842
|
}
|
|
851
843
|
return(pnpmCode?pnpmCode+' · ':'')+(t(FAILURE_REASONS[code])??t('详细原因见宿主日志'));
|
|
852
844
|
};
|
|
@@ -990,14 +982,15 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
990
982
|
const selected=targetSelection;if(selected?.status!=='confirmation-required'||pendingOperations[selected.item.id]?.busy)return;
|
|
991
983
|
setTarget({...selected,status:'installing'});
|
|
992
984
|
const suite=selected.item.kind==='suite-upgrade';
|
|
993
|
-
const
|
|
985
|
+
const reviewed={itemId:selected.item.id,packageName:selected.item.package.name,...(selected.item.installTarget?{installTarget:selected.item.installTarget}:{})};
|
|
986
|
+
const outcome=await operate(suite?'/hanamesh/library/suite/upgrade':'/hanamesh/library/install',suite?{planId:selected.item.suiteUpgrade.planId}:reviewed,selected.item.id,suite?t('升级套件'):t('安装'),true);
|
|
994
987
|
if(outcome){
|
|
995
988
|
if(!outcome.ok){if(targetSelection?.item?.id===selected.item.id)setTarget({...targetSelection,status:outcome.unknown?'result-unavailable':suite?'suite-upgrade-failed':'failed',error:outcome.code,details:outcome.details});return;}
|
|
996
989
|
if(suite){
|
|
997
990
|
try{const snapshot=await request('/hanamesh/library/installedPlugins');if(!outcome.result.components.every(c=>snapshot.plugins.some(p=>p.packageName===c.name&&p.version===c.to&&p.active)))throw new Error('INSTALL_READBACK_MISMATCH');setPending(p=>({...p,[selected.item.id]:{label:t("升级套件"),text:()=>(t('套件升级已读回,请完全退出并重新打开客户端。'))}}));setChanged(true);setTarget({...selected,status:'installed'});}
|
|
998
991
|
catch(error){setPending(p=>({...p,[selected.item.id]:{label:t("升级套件"),text:()=>(t('套件版本读回失败,请检查三个组件。')),failed:true}}));setTarget({...selected,status:'readback-failed',error:String(error.message??error)});}return;
|
|
999
992
|
}
|
|
1000
|
-
try{const fresh=await request('/hanamesh/library/target?'+
|
|
993
|
+
try{const fresh=await request('/hanamesh/library/target?'+targetQuery(reviewed));
|
|
1001
994
|
const row=fresh.item?.installed;
|
|
1002
995
|
if(row?.packageName!==selected.item.package.name||!['registered','installed','installed-not-loaded'].includes(row.state)||(outcome.result?.version&&row.version!==outcome.result.version))throw new Error('INSTALL_READBACK_MISMATCH');
|
|
1003
996
|
const live=outcome.result?.status==='applied';setPending(p=>({...p,[selected.item.id]:{label:t("安装"),text:()=>(live?t('安装完成,已加载,可以直接使用(已按精确版本读回)')+baselineText(outcome.result):t('安装完成,已按精确版本读回'))}}));if(!live)setChanged(true);
|
|
@@ -1048,20 +1041,21 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1048
1041
|
const restartRequired=changed||Boolean(snapshot?.restartRequired);
|
|
1049
1042
|
const filters=[...BASE_FILTERS,...seenCategories.filter(c=>c!=='hanamesh-app').map(c=>[c,c])];
|
|
1050
1043
|
const openButton=row=>h('button',{type:'button',disabled:Boolean(openingAppId),onClick:()=>void open(row)},openingAppId===row.appId?t('打开中…'):t('打开'));
|
|
1051
|
-
const card=item=>{const row=item.installed,op=pending[item.id],busy=op?.busy;const installBody={itemId:item.id,...(item.package?.name?{packageName:item.package.name}:{})};
|
|
1044
|
+
const card=item=>{const row=item.installed,op=pending[item.id],busy=op?.busy;const installBody={itemId:item.id,...(item.package?.name?{packageName:item.package.name}:{}),...(item.installTarget?{installTarget:item.installTarget}:{})};
|
|
1045
|
+
const reviewOrInstall=label=>item.installTarget?openInstallTarget(installBody).catch(()=>{}):operate('/hanamesh/library/install',installBody,item.id,label);
|
|
1052
1046
|
let action=h('span',null,t('仅收录,不可安装')),state=null;
|
|
1053
1047
|
if(row)state=h('span',{className:'hm-market-state','data-hanamesh-state':row.state},(t(STATE_TEXT[row.state]??row.state))+(row.version?' '+row.version:''));
|
|
1054
1048
|
if(item.kind==='suite')return h('article',{key:item.id,'data-hanamesh-library-item':item.id,'data-hanamesh-kind':'suite'},h('h3',null,t('HanaMesh 套件')),h('p',null,item.summary),h('p',null,item.suite?.status==='installed'?t('已安装 · HanaMesh ')+item.suite.version:item.suite?.status==='incomplete'?t('套件不完整,请查看组件状态'):t('套件状态未知,请查看 Core 声明与阻断原因')),item.suite?.completeness?h('p',null,t('Core 完整性:')+item.suite.completeness):null,...(item.suite?.components??[]).map(c=>h('p',{key:c.name},c.requiredRange?c.label+t(' · 要求 ')+c.requiredRange+t(' · 实际 ')+(c.actualVersion??t('检测不到'))+' · '+c.status:c.label+' · '+(c.version??t('检测不到'))+(c.active?'':t(' · 未启用')))),...(item.suite?.blocked??[]).map((row,i)=>h('p',{key:'blocked-'+i,role:'status'},row.code+(row.moduleName?' · '+row.moduleName:'')+(row.bundleVersion?' · HanaMesh '+row.bundleVersion:''))),item.suiteUpgradeUnavailable?h('p',{role:'status'},item.suiteUpgradeUnavailable):null,h('button',{type:'button',disabled:Boolean(item.suiteUpgradeUnavailable),onClick:()=>void openInstallTarget({itemId:'hanamesh:suite-upgrade'}).catch(()=>{})},t('检查兼容升级')));
|
|
1055
1049
|
if(busy)action=h('button',{type:'button',disabled:true},t(op.text));
|
|
1056
|
-
else if(item.kind!=='listing'&&!row)action=h('button',{type:'button',onClick:()=>void
|
|
1057
|
-
else if(row&&item.upgradeAvailable)action=h('span',{className:'hm-market-actions'},h('button',{type:'button',onClick:()=>void
|
|
1050
|
+
else if(item.kind!=='listing'&&!row)action=h('button',{type:'button',onClick:()=>void reviewOrInstall(t('安装'))},op?.failed?t('重试安装'):t('安装'));
|
|
1051
|
+
else if(row&&item.upgradeAvailable)action=h('span',{className:'hm-market-actions'},h('button',{type:'button',onClick:()=>void reviewOrInstall(t('升级'))},item.installTarget?.source==='github'?t('查看安装目标'):t('升级')),row.state==='registered'?openButton(row):null);
|
|
1058
1052
|
else if(row?.state==='runtime-missing')action=h('button',{type:'button',onClick:()=>void operate('/hanamesh/library/provision',{appId:row.appId,packageName:row.packageName,runtimeItem:row.runtimeItem},item.id,t('补齐运行时'))},t('补齐运行时'));
|
|
1059
1053
|
else if(row?.state==='registered')action=h('span',{className:'hm-market-actions'},openButton(row),h('button',{type:'button',onClick:()=>void operate('/hanamesh/library/uninstall',{appId:row.appId,packageName:row.packageName,runtimeItem:row.runtimeItem},item.id,t('卸载'))},t('卸载')));
|
|
1060
1054
|
else if(row?.state==='installed')action=PROTECTED.has(row.packageName)?h('span',null,t('HanaMesh 套件')):h('button',{type:'button',onClick:()=>void operate('/hanamesh/library/plugins/uninstall',{packageName:row.packageName},item.id,t('卸载'))},t('卸载'));
|
|
1061
1055
|
else if(row?.state==='uninstalled-not-unloaded')action=h('span',null,t('已卸载,重启 DSH 后生效'));
|
|
1062
1056
|
else if(row)action=h('span',null,t('已安装,重启 DSH 后生效'));
|
|
1063
1057
|
return h('article',{key:item.id,'data-hanamesh-library-item':item.id,'data-hanamesh-kind':item.kind},h('h3',null,item.displayName),h('p',null,item.summary),
|
|
1064
|
-
h('small',null,t(KIND_TEXT[item.kind])+' · '+(item.publisher?.name??t('未知发布者'))+
|
|
1058
|
+
h('small',null,t(KIND_TEXT[item.kind])+' · '+(item.publisher?.name??t('未知发布者'))+((item.categories??[]).length?' · '+item.categories.join('、'):'')),
|
|
1065
1059
|
state,action,op&&!busy?operationNotice(op):null);};
|
|
1066
1060
|
const catalogSection=receipt?h('div',{className:'hm-app-frame'},h('div',null,h('strong',null,receipt.instance.appId),h('button',{type:'button',disabled:closing,onClick:()=>void close()},closing?t('关闭中…'):t('关闭视图'))),h('iframe',{ref:frame,src:receipt.uiUrl,title:receipt.instance.appId,sandbox:'allow-forms allow-modals allow-popups allow-same-origin allow-scripts'})):
|
|
1067
1061
|
h('div',{className:'hm-library-grid',key:'catalog'},...items.map(card));
|
|
@@ -1082,7 +1076,9 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1082
1076
|
h('input',{'aria-label':t('目录条目 ID'),value:targetItemId,placeholder:t('itemId(可选)'),onChange:event=>setTargetItemId(event.target.value)}),
|
|
1083
1077
|
h('input',{'aria-label':t('包名'),value:targetPackageName,placeholder:t('packageName(可选)'),onChange:event=>setTargetPackageName(event.target.value)}),h('button',{type:'submit'},t('查看安装目标')))):null,
|
|
1084
1078
|
target?h('div',{role:target.status==='confirmation-required'?'dialog':'status','aria-label':t('市场安装确认')},
|
|
1085
|
-
target.item?h('dl',null,h('dt',null,t('插件名')),h('dd',null,target.item.displayName),h('dt',null,t('包名')),h('dd',null,target.item.package.name),h('dt',null,t('
|
|
1079
|
+
target.item?h('dl',null,h('dt',null,t('插件名')),h('dd',null,target.item.displayName),h('dt',null,t('包名')),h('dd',null,target.item.package.name),h('dt',null,t('来源')),h('dd',null,target.source?.kind==='fixture'?t('测试目录(fixture)'):target.source?.manifestUrl??t('当前市场目录'))):null,
|
|
1080
|
+
target.item?.installTarget?.source==='github'?h('dl',{'data-github-confirmation':true},h('dt',null,t('来源仓库')),h('dd',null,'https://github.com/'+target.item.installTarget.repo),h('dt',null,t('固定 commit')),h('dd',null,target.item.installTarget.ref),...(target.item.installTarget.path?[h('dt',null,t('仓库子目录')),h('dd',null,target.item.installTarget.path)]:[])):null,
|
|
1081
|
+
target.item?.installTarget?(target.item.installTarget.allowBuild.length?h('div',{role:'alert','data-build-warning':true},h('strong',null,t('会在本机执行构建脚本')),h('p',null,target.item.installTarget.allowBuild.join(', ')),h('p',null,t('确认后将按名单允许构建;pnpm 会把许可保存到当前 profile。'))):h('p',null,t('未授予构建脚本许可'))):null,
|
|
1086
1082
|
target.item?.suiteUpgrade?h('ul',null,...target.item.suiteUpgrade.components.map(c=>h('li',{key:c.name},c.label+':'+c.from+' → '+c.to)),h('li',null,t('确认后升级 HanaMesh 总包及其锁定组件;需要完全退出并重新打开客户端。'))):null,
|
|
1087
1083
|
target.item?.suiteUpgrade?.registry?h('p',null,'Registry:'+target.item.suiteUpgrade.registry):null,
|
|
1088
1084
|
...(target.item?.suiteUpgrade?.blocked??target.details?.blocked??[]).map((row,i)=>h('p',{key:'suite-blocked-'+i,role:'status'},row.code+(row.moduleName?' · '+row.moduleName:'')+(row.bundleVersion?' · HanaMesh '+row.bundleVersion:''))),
|
package/dist/dsh.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface DshPluginConfig {
|
|
|
13
13
|
/** `sources` undefined → the HanaMesh catalog source; explicit `[]` → none. `profileDir`/`profileName`/`dshBin` (and
|
|
14
14
|
* `nodeBinary`) are inferred from the proven Desktop layout or plain DSH when undefined — see docs/CONTRACT.md 「应用库配置」; explicit values win. */
|
|
15
15
|
/** rc.28: the same keys serve the HanaMesh market (plugins + applications; routes `/hanamesh/library*`, see docs/CONTRACT.md「市场」). */
|
|
16
|
-
library?:{fixture?:string;sources?:Array<{manifestUrl:string;enabled?:boolean}>;profileDir?:string;profileName?:string;dshBin?:string;registry?:string;
|
|
16
|
+
library?:{fixture?:string;sources?:Array<{manifestUrl:string;enabled?:boolean}>;profileDir?:string;profileName?:string;dshBin?:string;registry?:string;eventRetention?:number;installationReaders?:Partial<Record<'claude'|'codex',InstallationReaderConfig>>};
|
|
17
17
|
applications?: AppDefinition[]; leaseTtlMs?: number; sweepIntervalMs?: number;
|
|
18
18
|
}
|
|
19
19
|
/** Adapt an open `ctx.storageDomain` handle (single layout, global snapshot) to the store binding. */
|
package/dist/dsh.js
CHANGED
|
@@ -73,7 +73,7 @@ export const Config = z.object({
|
|
|
73
73
|
sources:z.union([z.array(z.any()),z.const(undefined)]),
|
|
74
74
|
/** Locations are inferred from the verified Desktop argv/profile or plain DSH (see library/locate.js). */
|
|
75
75
|
profileDir:z.string(),profileName:z.string(),dshBin:z.string(),
|
|
76
|
-
registry:z.string(),
|
|
76
|
+
registry:z.string(),
|
|
77
77
|
/** Publicly named event history capacity; a lost cursor reports resetRequired. */
|
|
78
78
|
eventRetention:z.number().default(512),
|
|
79
79
|
/** Explicit official CLI readers; unset means unknown, never inferred from PATH or private files. */
|
|
@@ -236,8 +236,6 @@ export async function apply(ctx, config) {
|
|
|
236
236
|
locations.inferred.map(key=>[key,key==='sources'?locations.sources.map(source=>source.manifestUrl):locations[key]]))));
|
|
237
237
|
// Exact-save capability comes from the host's public package metadata. Older managers use the public CLI
|
|
238
238
|
// for installs and preserve restart-required; applications and compensation also use that CLI.
|
|
239
|
-
let pluginManager;
|
|
240
|
-
optional('pluginManager', service => { pluginManager=service; });
|
|
241
239
|
let dshBin=locations.dshBin;
|
|
242
240
|
if(!dshBin&&locations.profileDir&&!desktop)try{dshBin=createRequire(join(locations.profileDir,'package.json')).resolve('@deepseek-ai/dsh/lib/bin.js');}catch{dshBin=undefined;}
|
|
243
241
|
const cliUsable=Boolean(locations.desktopLauncher||dshBin&&(!desktop||locations.desktopCli||config.library?.dshBin));
|
|
@@ -245,9 +243,9 @@ export async function apply(ctx, config) {
|
|
|
245
243
|
if(locations.profileDir&&locations.profileName){
|
|
246
244
|
provisionApi=await import('@hanamesh/lib-provision');
|
|
247
245
|
installer=nodeBinding(()=>nodeRuntime.executable,nodeBinary=>createLibraryInstaller({profileDir:locations.profileDir,profileName:locations.profileName,dataRoot,
|
|
248
|
-
...(cliUsable?{nodeBinary,dshBin,desktopCli:locations.desktopCli,desktopLauncher:locations.desktopLauncher}:{}),pluginManagerVersion:locations.pluginManagerVersion,profileWriter,
|
|
249
|
-
registry:libraryConfig.registry,
|
|
250
|
-
coreService:()=>coreService,suiteSourceService:()=>suiteSourceService,suiteSourceMode:()=>library?.suiteSourceSettings().mode??'configured',
|
|
246
|
+
...(cliUsable?{nodeBinary,dshBin,desktopCli:locations.desktopCli,desktopLauncher:locations.desktopLauncher}:{}),pluginManagerVersion:locations.pluginManagerVersion,profileWriter,
|
|
247
|
+
registry:libraryConfig.registry,provision:provisionApi.provision,remove:provisionApi.remove,ledger:provisionApi.ledger,
|
|
248
|
+
coreService:()=>coreService,suiteSourceService:()=>suiteSourceService,suiteSourceMode:()=>library?.suiteSourceSettings().mode??'configured',emit:event=>library?.emit(event)}));
|
|
251
249
|
}
|
|
252
250
|
/** What a person must do so the library can install, in their words (C-MARKET probe `error.need`). */
|
|
253
251
|
const unavailable=()=>{
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion": "
|
|
3
|
-
"
|
|
2
|
+
"schemaVersion": "hanamesh.catalog.v1",
|
|
3
|
+
"generatedAt": "2026-11-05T00:00:00.000Z",
|
|
4
4
|
"items": [
|
|
5
5
|
{
|
|
6
6
|
"id": "fixture.install-target.plugin",
|
|
7
7
|
"name": "@hanamesh-fixture/install-target-plugin",
|
|
8
8
|
"displayName": "测试目录 · 安装目标插件",
|
|
9
9
|
"summary": "Install-target contract fixture (test catalog, not a real product).",
|
|
10
|
-
"latestVersion": "1.2.3",
|
|
11
10
|
"categories": [
|
|
12
11
|
"utility"
|
|
13
12
|
],
|
|
@@ -17,6 +16,43 @@
|
|
|
17
16
|
},
|
|
18
17
|
"publisher": {
|
|
19
18
|
"name": "HanaMesh fixture"
|
|
19
|
+
},
|
|
20
|
+
"itemId": "fixture.install-target.plugin",
|
|
21
|
+
"packageName": "@hanamesh-fixture/install-target-plugin",
|
|
22
|
+
"catalogKind": "plugin",
|
|
23
|
+
"source": {
|
|
24
|
+
"sourceId": "hanamesh",
|
|
25
|
+
"sourceRef": "fixture.install-target.plugin",
|
|
26
|
+
"sourceLinks": [
|
|
27
|
+
{
|
|
28
|
+
"sourceId": "hanamesh",
|
|
29
|
+
"sourceRef": "fixture.install-target.plugin",
|
|
30
|
+
"sourceUrl": "https://catalog-fixture.example/fixture.install-target.plugin",
|
|
31
|
+
"firstSeenAt": "2026-11-05T00:00:00.000Z",
|
|
32
|
+
"lastSeenAt": "2026-11-05T00:00:00.000Z"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"installMethods": [
|
|
37
|
+
{
|
|
38
|
+
"channel": "hanamesh",
|
|
39
|
+
"kind": "npm",
|
|
40
|
+
"spec": "@hanamesh-fixture/install-target-plugin",
|
|
41
|
+
"command": null,
|
|
42
|
+
"allowBuild": [],
|
|
43
|
+
"sourceId": "hanamesh",
|
|
44
|
+
"sourceRef": "fixture.install-target.plugin",
|
|
45
|
+
"target": {
|
|
46
|
+
"source": "npm",
|
|
47
|
+
"name": "@hanamesh-fixture/install-target-plugin",
|
|
48
|
+
"version": "1.2.3",
|
|
49
|
+
"allowBuild": []
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"oneClickInstall": {
|
|
54
|
+
"allowed": true,
|
|
55
|
+
"reason": null
|
|
20
56
|
}
|
|
21
57
|
},
|
|
22
58
|
{
|
|
@@ -24,7 +60,6 @@
|
|
|
24
60
|
"name": "@hanamesh-fixture/install-target-app",
|
|
25
61
|
"displayName": "测试目录 · 安装目标应用",
|
|
26
62
|
"summary": "Install-target contract fixture application (test catalog).",
|
|
27
|
-
"latestVersion": "0.4.0",
|
|
28
63
|
"categories": [
|
|
29
64
|
"hanamesh-app"
|
|
30
65
|
],
|
|
@@ -34,6 +69,43 @@
|
|
|
34
69
|
},
|
|
35
70
|
"publisher": {
|
|
36
71
|
"name": "HanaMesh fixture"
|
|
72
|
+
},
|
|
73
|
+
"itemId": "fixture.install-target.app",
|
|
74
|
+
"packageName": "@hanamesh-fixture/install-target-app",
|
|
75
|
+
"catalogKind": "application",
|
|
76
|
+
"source": {
|
|
77
|
+
"sourceId": "hanamesh",
|
|
78
|
+
"sourceRef": "fixture.install-target.app",
|
|
79
|
+
"sourceLinks": [
|
|
80
|
+
{
|
|
81
|
+
"sourceId": "hanamesh",
|
|
82
|
+
"sourceRef": "fixture.install-target.app",
|
|
83
|
+
"sourceUrl": "https://catalog-fixture.example/fixture.install-target.app",
|
|
84
|
+
"firstSeenAt": "2026-11-05T00:00:00.000Z",
|
|
85
|
+
"lastSeenAt": "2026-11-05T00:00:00.000Z"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"installMethods": [
|
|
90
|
+
{
|
|
91
|
+
"channel": "hanamesh",
|
|
92
|
+
"kind": "npm",
|
|
93
|
+
"spec": "@hanamesh-fixture/install-target-app",
|
|
94
|
+
"command": null,
|
|
95
|
+
"allowBuild": [],
|
|
96
|
+
"sourceId": "hanamesh",
|
|
97
|
+
"sourceRef": "fixture.install-target.app",
|
|
98
|
+
"target": {
|
|
99
|
+
"source": "npm",
|
|
100
|
+
"name": "@hanamesh-fixture/install-target-app",
|
|
101
|
+
"version": "0.4.0",
|
|
102
|
+
"allowBuild": []
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"oneClickInstall": {
|
|
107
|
+
"allowed": true,
|
|
108
|
+
"reason": null
|
|
37
109
|
}
|
|
38
110
|
},
|
|
39
111
|
{
|
|
@@ -45,14 +117,33 @@
|
|
|
45
117
|
"utility"
|
|
46
118
|
],
|
|
47
119
|
"repository": {
|
|
48
|
-
"url": "https://
|
|
120
|
+
"url": "https://github.com/fixture/repository-only"
|
|
49
121
|
},
|
|
50
122
|
"publisher": {
|
|
51
123
|
"name": "HanaMesh fixture"
|
|
124
|
+
},
|
|
125
|
+
"itemId": "fixture.install-target.repository-only",
|
|
126
|
+
"packageName": null,
|
|
127
|
+
"catalogKind": "entry",
|
|
128
|
+
"source": {
|
|
129
|
+
"sourceId": "hanamesh",
|
|
130
|
+
"sourceRef": "fixture.install-target.repository-only",
|
|
131
|
+
"sourceLinks": [
|
|
132
|
+
{
|
|
133
|
+
"sourceId": "hanamesh",
|
|
134
|
+
"sourceRef": "fixture.install-target.repository-only",
|
|
135
|
+
"sourceUrl": "https://catalog-fixture.example/fixture.install-target.repository-only",
|
|
136
|
+
"firstSeenAt": "2026-11-05T00:00:00.000Z",
|
|
137
|
+
"lastSeenAt": "2026-11-05T00:00:00.000Z"
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
"installMethods": [],
|
|
142
|
+
"oneClickInstall": {
|
|
143
|
+
"allowed": false,
|
|
144
|
+
"reason": "no-install-method"
|
|
52
145
|
}
|
|
53
146
|
}
|
|
54
147
|
],
|
|
55
|
-
"page": {
|
|
56
|
-
"total": 3
|
|
57
|
-
}
|
|
148
|
+
"page": {}
|
|
58
149
|
}
|