@hanamesh/dsh-app-host 0.6.17 → 0.6.20
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 +3 -3
- package/dist/client-ui.js +14 -12
- package/dist/installation-status.d.ts +1 -1
- package/dist/library/install.js +10 -10
- package/dist/library/installation-status.js +3 -3
- package/dist/library/service.js +3 -3
- package/dist/library/suite.js +24 -11
- package/docs/INSTALLATION_STATUS.md +4 -2
- package/docs/LIBRARY.md +2 -0
- package/docs/LICENSES.json +12 -17
- package/docs/PROVENANCE.json +10 -14
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
0.6.16 候选:普通市场通过注入的宿主 pluginManager.registries() 读取源事实,并按宿主锚点/版本守卫加载公开 ./registry 规则模块;AppHost 不声明、安装或捆绑 manager。发布依赖/peer闭包与0.6.15一致。pnpm自有源(null)不显式传--registry,配置镜像则传同一源;查询30秒具名超时,脱敏原诊断同进UI和日志。
|
|
2
2
|
|
|
3
|
-
0.6.15 候选:市场保留官方 CLI 的 stdout/stderr 真实失败原因并脱敏,在卡片与安装确认的技术详情中显示。正文显示 pnpm
|
|
3
|
+
0.6.15 候选:市场保留官方 CLI 的 stdout/stderr 真实失败原因并脱敏,在卡片与安装确认的技术详情中显示。正文显示 pnpm 真实错误类别;宿主发布时间检查失败时列出受影响包与实际 cutoff;HanaMesh 总包安装/升级使用精确发布版本,发布后即可验收;不修改 profile、pnpm 供应链策略或安装执行路径。
|
|
4
4
|
|
|
5
5
|
官方桌面 0.2.0-rc.2 自带 pnpm 11.7.0 对同一包的多条精确 `minimumReleaseAgeExclude` 只采用首条,旧版条目会遮住后列新版,整份 lockfile 检查因而可阻断无关插件安装。本机桌面 0.2.1-rc.3 自带的 pnpm 11.28.5 已合并这些条目,相同样本通过;未推定首次修复版本。请通过官方渠道升级 DSH,保留失败的技术详情;AppHost 不绕过该检查。见 [兼容说明](docs/DSH_COMPATIBILITY.md)。
|
|
6
6
|
|
|
@@ -185,7 +185,7 @@ rc9 installation-target contract: the library accepts exact 127.0.0.1/localhost
|
|
|
185
185
|
|
|
186
186
|
## 0.4.0 · Devkit normal Git supply / 0.5.0 external provision supply
|
|
187
187
|
|
|
188
|
-
Development installs use Node 24.13.1, pnpm 10.33.0 and the frozen `pnpm-lock.yaml`, with pnpm package-manager self-management disabled.
|
|
188
|
+
Development installs use Node 24.13.1, pnpm 10.33.0 and the frozen `pnpm-lock.yaml`, with pnpm package-manager self-management disabled. `@hanamesh/devkit` (`^0.2.6`, development-only) and `@hanamesh/lib-provision` (`^0.2.1`, bundled into the runtime tarball) are installed from the public npm registry; the lock pins version and sha512 integrity. Source installs need no private Git access or credentials. The package identity is Devkit, never the shared root alias. Run `pnpm run check:devkit-supply` for the public provider contract, installed version range, registry lock form and CLI checks. The four mature tool engines and runtime payload are unchanged. No runtime Devkit dependency or bundled tool code is added.
|
|
189
189
|
|
|
190
190
|
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.
|
|
191
191
|
|
|
@@ -238,4 +238,4 @@ Actions runs on the standard public/free `macos-15` arm64 runner because the exi
|
|
|
238
238
|
|
|
239
239
|
## Core 公开套件声明的测试依赖
|
|
240
240
|
|
|
241
|
-
源码测试通过 `@hanamesh/core/suite` 读取 Core 单源公开命令。`@hanamesh/core` 是仓库声明的 devDependency
|
|
241
|
+
源码测试通过 `@hanamesh/core/suite` 读取 Core 单源公开命令。`@hanamesh/core` 是仓库声明的 devDependency,按 npm 版本范围 `^0.3.28` 从公开 npm 安装,冻结 pnpm 锁记录实际版本与 SRI;许可证记录见 `docs/LICENSES.json`。Core 不成为运行时依赖或 bundled 包。
|
package/dist/client-ui.js
CHANGED
|
@@ -53,7 +53,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
53
53
|
"copy45": "删除",
|
|
54
54
|
"copy46": "添加并启用",
|
|
55
55
|
"copy47": "套件安装包来源",
|
|
56
|
-
"copy48": "
|
|
56
|
+
"copy48": "选择 HanaMesh 总包的 npm 安装包 registry。市场目录源提供浏览清单,在「市场目录源」中单独设置。",
|
|
57
57
|
"copy49": "安装包来源",
|
|
58
58
|
"copy50": "现有配置(默认)",
|
|
59
59
|
"copy51": "Core 当前本机来源",
|
|
@@ -147,6 +147,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
147
147
|
"copy135": "检测不到",
|
|
148
148
|
"copy136": "(未启用)",
|
|
149
149
|
"copy137": "。请完全退出客户端,使用补齐命令(仅 macOS / Linux 终端;Windows 安全命令暂未提供)修复并重新打开:",
|
|
150
|
+
"copy302": "。请完全退出客户端,重新读取总包发布版本后修复并重新打开。",
|
|
150
151
|
"copy138": ";但应用库没能读回 profile(",
|
|
151
152
|
"copy139": "),已安装列表可能仍显示「需重启」",
|
|
152
153
|
"copy140": ";安装前状态未被改动(已逐项读回)",
|
|
@@ -187,7 +188,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
187
188
|
"copy175": "打开",
|
|
188
189
|
"copy176": "仅收录,不可安装",
|
|
189
190
|
"copy177": "HanaMesh 套件",
|
|
190
|
-
"copy178": "已安装 ·
|
|
191
|
+
"copy178": "已安装 · HanaMesh ",
|
|
191
192
|
"copy179": "套件不完整,请查看组件状态",
|
|
192
193
|
"copy180": "套件状态未知,请查看 Core 声明与阻断原因",
|
|
193
194
|
"copy181": "Core 完整性:",
|
|
@@ -227,7 +228,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
227
228
|
"copy215": "目录未提供版本",
|
|
228
229
|
"copy216": "测试目录(fixture)",
|
|
229
230
|
"copy217": "当前市场目录",
|
|
230
|
-
"copy218": "
|
|
231
|
+
"copy218": "确认后升级 HanaMesh 总包及其锁定组件;需要完全退出并重新打开客户端。",
|
|
231
232
|
"copy219": "确认安装",
|
|
232
233
|
"copy220": "取消",
|
|
233
234
|
"copy221": "正在查询市场目录…",
|
|
@@ -360,7 +361,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
360
361
|
"copy45": "Remove",
|
|
361
362
|
"copy46": "Add and enable",
|
|
362
363
|
"copy47": "Suite package source",
|
|
363
|
-
"copy48": "Choose the npm registry for the
|
|
364
|
+
"copy48": "Choose the npm registry for the HanaMesh bundle. Browseable catalogs are configured separately in Market catalog sources.",
|
|
364
365
|
"copy49": "Package source",
|
|
365
366
|
"copy50": "Existing configuration (default)",
|
|
366
367
|
"copy51": "Core’s current local source",
|
|
@@ -454,6 +455,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
454
455
|
"copy135": "Not available",
|
|
455
456
|
"copy136": " (disabled)",
|
|
456
457
|
"copy137": ". Fully quit the client and run the repair command (macOS / Linux terminal only; no safe Windows command is supplied), then reopen: ",
|
|
458
|
+
"copy302": ". Fully quit the client, read the published bundle version again, repair and reopen.",
|
|
457
459
|
"copy138": "; the market could not read the profile (",
|
|
458
460
|
"copy139": "), so the installed list may still show Restart required",
|
|
459
461
|
"copy140": "; the pre-install state is unchanged (each item read back)",
|
|
@@ -494,7 +496,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
494
496
|
"copy175": "Open",
|
|
495
497
|
"copy176": "Listed only; not installable",
|
|
496
498
|
"copy177": "HanaMesh suite",
|
|
497
|
-
"copy178": "Installed ·
|
|
499
|
+
"copy178": "Installed · HanaMesh ",
|
|
498
500
|
"copy179": "Suite incomplete. Check component status",
|
|
499
501
|
"copy180": "Suite status unknown. Check the Core declaration and blocking reasons",
|
|
500
502
|
"copy181": "Core completeness: ",
|
|
@@ -534,7 +536,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
534
536
|
"copy215": "No version provided by catalog",
|
|
535
537
|
"copy216": "Test catalog (fixture)",
|
|
536
538
|
"copy217": "Current market catalog",
|
|
537
|
-
"copy218": "Confirmation upgrades
|
|
539
|
+
"copy218": "Confirmation upgrades the HanaMesh bundle and its locked components. Fully quit and reopen the client afterwards.",
|
|
538
540
|
"copy219": "Confirm installation",
|
|
539
541
|
"copy220": "Cancel",
|
|
540
542
|
"copy221": "Reading market catalog…",
|
|
@@ -772,7 +774,7 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
772
774
|
h('p',null,t('现有 registry:'),h('code',null,value.configuredRegistry)),
|
|
773
775
|
h('p',null,t('已保存选择:')+(value.mode==='core'?t('Core 当前本机来源'):t('现有配置'))),
|
|
774
776
|
observation?.observable?h('div',null,h('p',{role:'status'},t('Core 来源:')+state.status+' · '+state.selection),state.registry?h('p',null,h('code',null,state.registry)):null,state.lastError?FailureNotice({error:state.lastError}):null):h('div',null,h('p',{role:'status'},t('Core 来源暂不可用。请检查 Core 插件及其来源设置。')),h('details',null,h('summary',null,t('技术详情')),h('code',null,observation?.code??'CORE_SUITE_SOURCE_MISSING'))),
|
|
775
|
-
h('details',null,h('summary',null,t('使用说明')),h('p',null,t('
|
|
777
|
+
h('details',null,h('summary',null,t('使用说明')),h('p',null,t('选择 HanaMesh 总包的 npm 安装包 registry。市场目录源提供浏览清单,在「市场目录源」中单独设置。')),h('p',null,t('保存选择不会安装。检查、确认和执行前都重新读取当前来源与 Core 兼容声明;来源变化后须重新查看并确认。')))):h('p',null,t('正在读取套件安装包来源…')));
|
|
776
778
|
}
|
|
777
779
|
function NodeRuntimeSection(){useLocale();
|
|
778
780
|
const[value,setValue]=React.useState(null),[draft,setDraft]=React.useState(null),[plan,setPlan]=React.useState(null),[error,setError]=React.useState(''),[working,setWorking]=React.useState(false);
|
|
@@ -849,7 +851,7 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
849
851
|
return(pnpmCode?pnpmCode+' · ':'')+(t(FAILURE_REASONS[code])??t('详细原因见宿主日志'));
|
|
850
852
|
};
|
|
851
853
|
const operationNotice=op=>op?h('div',null,h('p',{role:op.failed?'alert':'status',className:op.failed?'hm-library-failed':'hm-library-ok',style:{overflowWrap:'anywhere'}},t(op.text)),op.diagnostic?h('details',null,h('summary',null,t('技术详情')),h('pre',{style:{whiteSpace:'pre-wrap',overflowWrap:'anywhere'}},op.diagnostic)):null):null;
|
|
852
|
-
const suiteRecoveryText=details=>details?.stage==='suite-upgrade'?t(';升级未完成,部分组件可能已改变。当前读回:')+(details.actual?.components?.map(c=>c.label+' '+(c.version??t('检测不到'))+(c.active?'':t('(未启用)'))).join(';')||t('检测不到'))+t('。请完全退出客户端,使用补齐命令(仅 macOS / Linux 终端;Windows 安全命令暂未提供)修复并重新打开:')+details.command:'';
|
|
854
|
+
const suiteRecoveryText=details=>details?.stage==='suite-upgrade'?t(';升级未完成,部分组件可能已改变。当前读回:')+(details.actual?.components?.map(c=>c.label+' '+(c.version??t('检测不到'))+(c.active?'':t('(未启用)'))).join(';')||t('检测不到'))+(details.command?t('。请完全退出客户端,使用补齐命令(仅 macOS / Linux 终端;Windows 安全命令暂未提供)修复并重新打开:')+details.command:t('。请完全退出客户端,重新读取总包发布版本后修复并重新打开。')):'';
|
|
853
855
|
/** pluginManager applied it, but the profile could not be read back: the installed list may still say 「需重启」. */
|
|
854
856
|
const baselineText=result=>result?.restartBaseline?.updated===false?t(';但应用库没能读回 profile(')+result.restartBaseline.code+t('),已安装列表可能仍显示「需重启」'):'';
|
|
855
857
|
/** rc.10 install recovery result: only an item-by-item readback that matched the baseline is shown as restored. */
|
|
@@ -863,7 +865,7 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
863
865
|
const KIND_TEXT={application:t('应用'),plugin:t('插件'),listing:t('仅收录')};
|
|
864
866
|
const STATE_TEXT={registered:t('已安装'),installed:t('已安装'),'installed-not-loaded':t('需重启'),'uninstalled-not-unloaded':t('已卸载 · 需重启'),'runtime-missing':t('缺运行时'),invalid:t('包无效')};
|
|
865
867
|
// Mirrors PROTECTED_PACKAGES on the host: the suite is never offered an uninstall button (the host answers 403 anyway).
|
|
866
|
-
const PROTECTED=new Set(['@hanamesh/
|
|
868
|
+
const PROTECTED=new Set(['@hanamesh/hanamesh','@hanamesh/core','@hanamesh/usage','@hanamesh/dsh-app-host','hanamesh-brand']);
|
|
867
869
|
function RestartNotice({reason}){useLocale();
|
|
868
870
|
return h('p',{role:'status',className:'hm-restart-notice','data-hanamesh-restart':'required'},h('strong',null,t('需重新打开客户端')),' ',reason??t('插件更改需要重新打开客户端后生效。'),' ',h('span',{className:'hm-restart-hint'},t('请完全退出 HanaMesh 客户端或 DSH 后重新打开;关闭窗口不等于退出。')));
|
|
869
871
|
}
|
|
@@ -1049,7 +1051,7 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1049
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}:{})};
|
|
1050
1052
|
let action=h('span',null,t('仅收录,不可安装')),state=null;
|
|
1051
1053
|
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:''));
|
|
1052
|
-
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('已安装 ·
|
|
1054
|
+
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('检查兼容升级')));
|
|
1053
1055
|
if(busy)action=h('button',{type:'button',disabled:true},t(op.text));
|
|
1054
1056
|
else if(item.kind!=='listing'&&!row)action=h('button',{type:'button',onClick:()=>void operate('/hanamesh/library/install',installBody,item.id,t('安装'))},op?.failed?t('重试安装'):t('安装'));
|
|
1055
1057
|
else if(row&&item.upgradeAvailable)action=h('span',{className:'hm-market-actions'},h('button',{type:'button',onClick:()=>void operate('/hanamesh/library/install',installBody,item.id,t('升级'))},t('升级到 ')+item.latestVersion),row.state==='registered'?openButton(row):null);
|
|
@@ -1081,9 +1083,9 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1081
1083
|
h('input',{'aria-label':t('包名'),value:targetPackageName,placeholder:t('packageName(可选)'),onChange:event=>setTargetPackageName(event.target.value)}),h('button',{type:'submit'},t('查看安装目标')))):null,
|
|
1082
1084
|
target?h('div',{role:target.status==='confirmation-required'?'dialog':'status','aria-label':t('市场安装确认')},
|
|
1083
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('版本')),h('dd',null,target.item.latestVersion??t('目录未提供版本')),h('dt',null,t('来源')),h('dd',null,target.source?.kind==='fixture'?t('测试目录(fixture)'):target.source?.manifestUrl??t('当前市场目录'))):null,
|
|
1084
|
-
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('
|
|
1086
|
+
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,
|
|
1085
1087
|
target.item?.suiteUpgrade?.registry?h('p',null,'Registry:'+target.item.suiteUpgrade.registry):null,
|
|
1086
|
-
...(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.
|
|
1088
|
+
...(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:''))),
|
|
1087
1089
|
target.status==='confirmation-required'?h('div',null,h('button',{type:'button',onClick:()=>void confirmTarget()},t('确认安装')),h('button',{type:'button',onClick:()=>{targetSequence++;void reportHandoff(targetSelection?.handoffId,'cancelled');setTarget({...targetSelection,status:'cancelled'});}},t('取消'))):
|
|
1088
1090
|
target.status==='failed'?FailureNotice({error:target.diagnostic??target.error}):h('p',{role:['readback-failed','suite-upgrade-failed'].includes(target.status)?'alert':'status'},({resolving:t('正在查询市场目录…'),installing:t('安装中…'),installed:t('安装完成,请查看已安装列表'),'installed-live':t('安装完成,已加载,可以直接使用'),cancelled:t('已取消,未安装'),'result-unavailable':t('安装结果不可追溯,请查看已安装列表;不会自动重试'),'already-installed':t('已安装,无需重复安装'),failed:t('未安装:')+(target.error??pending[target.item?.id]?.text??t('安装失败')),'readback-failed':target.error,'suite-upgrade-failed':suiteTargetFailure(target)})[target.status]),
|
|
1089
1091
|
target.item?.source?h('div',{'aria-label':t('目录条目来源')},h('p',null,target.item.source.sourceId+' · '+target.item.source.sourceRef),...(target.item.source.sourceLinks??[]).map((link,index)=>h('p',{key:index},h('a',{href:link.sourceUrl,target:'_blank',rel:'noopener noreferrer'},link.sourceId+' · '+link.sourceRef),h('small',null,' '+link.firstSeenAt+' / '+link.lastSeenAt)))):null,
|
|
@@ -12,7 +12,7 @@ export interface InstallationStatusRequest {contractVersion:'1';consent:'read-in
|
|
|
12
12
|
export interface InstallationObservation {
|
|
13
13
|
channel:'hanamesh'|'dsh'|'claude'|'codex';
|
|
14
14
|
scope:{id:'current-runtime'|'other-runtime'|'agent-cli'|'desktop-app';kind:'responding-runtime'|'unobserved-runtime'|'official-user-profile'|'desktop-app';label:string};
|
|
15
|
-
status:'installed'|'not-installed'|'incomplete'|'unknown';version:string|null;versionKind:'
|
|
15
|
+
status:'installed'|'not-installed'|'incomplete'|'unknown';version:string|null;versionKind:'suite-bundle'|'agent-distribution';
|
|
16
16
|
components:readonly {name:string;version:string|null;active?:boolean;status?:string}[];
|
|
17
17
|
identity:{pluginName:string;marketplace:string}|null;
|
|
18
18
|
reason:{code:string;message:string;action:string}|null;
|
package/dist/library/install.js
CHANGED
|
@@ -10,10 +10,10 @@ import {noteFailurePhase} from './diagnostics.js';
|
|
|
10
10
|
import { validateDefinition } from '../descriptor.js';
|
|
11
11
|
import { itemKind } from './catalog.js';
|
|
12
12
|
import { profileSnapshot, runtimeSnapshot, profileChecks, runtimeChecks, packageRestoreArgs, keepOriginals } from './recovery.js';
|
|
13
|
-
import {prepareSuiteUpgrade,readSuiteStatus,createCoreSuiteAdapter} from './suite.js';
|
|
13
|
+
import {SUITE_BUNDLE,prepareSuiteUpgrade,readSuiteStatus,createCoreSuiteAdapter} from './suite.js';
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
export const PROTECTED_PACKAGES=Object.freeze(['@hanamesh/core','@hanamesh/usage','@hanamesh/
|
|
15
|
+
/** Suite packages are changed only by the confirmed suite upgrade command. */
|
|
16
|
+
export const PROTECTED_PACKAGES=Object.freeze([SUITE_BUNDLE,'@hanamesh/core','@hanamesh/usage','@hanamesh/dsh-app-host','hanamesh-brand']);
|
|
17
17
|
const blocked=new Set(PROTECTED_PACKAGES);
|
|
18
18
|
const packageName=value=>typeof value==='string'&&/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(value);
|
|
19
19
|
const versionText=value=>typeof value==='string'&&/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value);
|
|
@@ -195,24 +195,24 @@ export function createLibraryInstaller({profileDir,profileName,dataRoot,nodeBina
|
|
|
195
195
|
requireCondition(suitePlan?.planId===planId,'SUITE_PLAN_CHANGED','升级确认已变化,请重新查看并确认。',{},409);
|
|
196
196
|
const confirmed=suitePlan;suitePlan=undefined;
|
|
197
197
|
const fresh=await prepareSuiteUpgrade({coreSuitePlan:suiteProvider});
|
|
198
|
-
const identity=plan=>JSON.stringify({sourceBinding:plan.sourceBinding,components:plan.components,declarationId:plan.declarationId,registry:plan.registry,selectedUpgrade:plan.selectedUpgrade,physicalBaseline:plan.physicalBaseline});
|
|
198
|
+
const identity=plan=>JSON.stringify({sourceBinding:plan.sourceBinding,bundle:plan.bundle,components:plan.components,declarationId:plan.declarationId,registry:plan.registry,selectedUpgrade:plan.selectedUpgrade,physicalBaseline:plan.physicalBaseline});
|
|
199
199
|
requireCondition(identity(fresh)===identity(confirmed),'SUITE_PLAN_CHANGED','套件声明或版本已变化,请重新查看并确认。',{},409);
|
|
200
200
|
requireCondition(fresh.available,'SUITE_NO_UPDATE','当前没有兼容新版。',{},409);
|
|
201
201
|
const before=await readSuiteStatus(profileDir);
|
|
202
|
-
requireCondition(before.status==='installed'&&fresh.components.every((c,i)=>before.components[i]?.version===c.from),'SUITE_PLAN_CHANGED','已装版本或启用状态已变化,请重新查看并确认。',{},409);
|
|
202
|
+
requireCondition(before.status==='installed'&&before.version===fresh.bundle.from&&fresh.components.every((c,i)=>before.components[i]?.version===c.from),'SUITE_PLAN_CHANGED','已装版本或启用状态已变化,请重新查看并确认。',{},409);
|
|
203
203
|
requireCondition(cliAvailable,'DSH_CLI_UNAVAILABLE','套件升级需客户端随附的官方 CLI;请恢复后重试。',{},503);
|
|
204
204
|
const executing=await prepareSuiteUpgrade({coreSuitePlan:suiteProvider});
|
|
205
205
|
requireCondition(identity(executing)===identity(confirmed),'SUITE_PLAN_CHANGED','执行前套件安装包来源或声明已变化,请重新查看并确认。',{},409);
|
|
206
|
-
emit({type:'library.install-started',itemId:'hanamesh:suite-upgrade',packageName:
|
|
206
|
+
emit({type:'library.install-started',itemId:'hanamesh:suite-upgrade',packageName:SUITE_BUNDLE,kind:'suite-upgrade'});
|
|
207
207
|
try{
|
|
208
|
-
await run(['add','--save-exact','--strict-peer-dependencies',`--registry=${fresh.registry??registry??'https://registry.npmjs.org'}
|
|
208
|
+
await run(['add','--save-exact','--strict-peer-dependencies',`--registry=${fresh.registry??registry??'https://registry.npmjs.org'}`,`${SUITE_BUNDLE}@${fresh.bundle.to}`]);
|
|
209
209
|
const actual=await readSuiteStatus(profileDir);
|
|
210
210
|
const saved=await json(join(profileDir,'package.json'));
|
|
211
|
-
requireCondition(actual.status==='installed'&&fresh.components.every((c,i)=>actual.components[i]?.version===c.to
|
|
212
|
-
return{status:'restart-required',kind:'suite-upgrade',packageName:
|
|
211
|
+
requireCondition(actual.status==='installed'&&actual.version===fresh.bundle.to&&saved.dependencies?.[SUITE_BUNDLE]===fresh.bundle.to&&fresh.components.every((c,i)=>actual.components[i]?.version===c.to),'INSTALL_READBACK_MISMATCH','套件升级后的版本或启用状态不符,请完全退出后按补齐命令修复。',{},502);
|
|
212
|
+
return{status:'restart-required',kind:'suite-upgrade',packageName:SUITE_BUNDLE,components:fresh.components,version:actual.version};
|
|
213
213
|
}catch(error){
|
|
214
214
|
error.details={...error.details,stage:'suite-upgrade',actual:await readSuiteStatus(profileDir),command:fresh.installCommand};
|
|
215
|
-
emit({type:'library.install-failed',packageName:
|
|
215
|
+
emit({type:'library.install-failed',packageName:SUITE_BUNDLE,code:error.code??'SUITE_UPGRADE_FAILED'});throw error;
|
|
216
216
|
}
|
|
217
217
|
});},
|
|
218
218
|
async install(item,context){
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Read fresh public installation facts. No compatibility calculation, persistence or polling. */
|
|
2
2
|
import semver from 'semver';
|
|
3
3
|
import {AppHostError} from '../errors.js';
|
|
4
|
-
import {createCoreSuiteAdapter,SUITE_PACKAGES} from './suite.js';
|
|
4
|
+
import {SUITE_BUNDLE,createCoreSuiteAdapter,SUITE_PACKAGES} from './suite.js';
|
|
5
5
|
import {SUPPORTED_READER_VERSIONS,validReader,runOfficialInstallationCommand} from './installation-cli.js';
|
|
6
6
|
const object=x=>x!==null&&typeof x==='object'&&!Array.isArray(x);
|
|
7
7
|
const exact=x=>typeof x==='string'&&semver.valid(x)===x?x:null;
|
|
@@ -11,7 +11,7 @@ function abortable(work,signal){
|
|
|
11
11
|
if(signal.aborted)return Promise.reject(interrupted());
|
|
12
12
|
return new Promise((resolve,reject)=>{const abort=()=>reject(interrupted());signal.addEventListener('abort',abort,{once:true});Promise.resolve(work).then(resolve,reject).finally(()=>signal.removeEventListener('abort',abort))});
|
|
13
13
|
}
|
|
14
|
-
const base=(channel,id,kind,label)=>({channel,scope:{id,kind,label},status:'unknown',version:null,versionKind:['dsh','hanamesh'].includes(channel)?'
|
|
14
|
+
const base=(channel,id,kind,label)=>({channel,scope:{id,kind,label},status:'unknown',version:null,versionKind:['dsh','hanamesh'].includes(channel)?'suite-bundle':'agent-distribution',components:[],identity:null,reason:null});
|
|
15
15
|
const unknown=(row,code,message,action)=>({...row,status:'unknown',version:null,reason:reason(code,message,action)});
|
|
16
16
|
const agentBase=channel=>base(channel,'agent-cli','official-user-profile',channel==='claude'?'Claude Code 用户级插件(不覆盖项目或其他隔离资料)':'Codex CLI 本地市场用户资料(不代表桌面 App、项目或其他隔离资料)');
|
|
17
17
|
const inventoryError=()=>{throw new AppHostError('AGENT_INVENTORY_INVALID','Official inventory shape is unsupported.',{},503)};
|
|
@@ -58,7 +58,7 @@ export function createInstallationStatusReader({client='dsh',core=()=>undefined,
|
|
|
58
58
|
const row=base(client,'current-runtime','responding-runtime',client==='dsh'?'当前响应的 DSH runtime':'当前响应的 HanaMesh 客户端 runtime');
|
|
59
59
|
try{const value=await abortable(suite.readFacts(),signal);
|
|
60
60
|
const components=value.components.map(c=>({name:c.name,version:exact(c.version),...(['satisfied','missing','incompatible','damaged','unreadable','inactive','failed','ambiguous'].includes(c.status)?{status:c.status}:{}),...(typeof c.active==='boolean'?{active:c.active}:{})}));
|
|
61
|
-
const blocked=value.blocked.map(r=>({code:/^CORE_[A-Z0-9_]{1,75}$/.test(r.code)?r.code:'CORE_SUITE_BLOCKED',...(SUITE_PACKAGES.some(c=>c.name===r.moduleName)?{moduleName:r.moduleName}:{})}));
|
|
61
|
+
const blocked=value.blocked.map(r=>({code:/^CORE_[A-Z0-9_]{1,75}$/.test(r.code)?r.code:'CORE_SUITE_BLOCKED',...(r.moduleName===SUITE_BUNDLE||SUITE_PACKAGES.some(c=>c.name===r.moduleName)?{moduleName:r.moduleName}:{})}));
|
|
62
62
|
return{...row,status:value.status,version:value.status==='unknown'?null:exact(value.version),components,blocked,
|
|
63
63
|
reason:value.status==='unknown'?reason('CORE_SUITE_DECLARATION_UNKNOWN','Core 尚不能确认本 runtime 的套件完整性。','查看 Core 设置中的具名阻断原因,补齐其公开事实后重新检测。'):value.status==='incomplete'?reason('CORE_SUITE_CURRENT_INCOMPLETE','Core 报告本 runtime 的套件不完整。','在本客户端按 Core 组件说明修复后重新检测。'):null};
|
|
64
64
|
}catch(error){if(signal.aborted)throw interrupted();const code=['CORE_SUITE_DECLARATION_MISSING','CORE_SUITE_DECLARATION_INVALID'].includes(error.code)?error.code:'CORE_SUITE_READ_FAILED';return unknown(row,code,code==='CORE_SUITE_DECLARATION_MISSING'?'本 runtime 未提供 Core 套件声明方法。':'本次 Core 套件声明读取失败。','启用支持 protocol 1 getSuiteDeclaration 的 Core,查看其设置并重新检测。')}
|
package/dist/library/service.js
CHANGED
|
@@ -2,7 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { AppHostError, requireCondition, SerialQueue } from '../errors.js';
|
|
3
3
|
import { loadCatalog, isApplication, itemKind, upgradeAvailable, validateManifestUrl } from './catalog.js';
|
|
4
4
|
import { scanInstalled, scanInstalledPlugins, snapshotProfileDependencies } from './installed.js';
|
|
5
|
-
import {SUITE_TARGET,SUITE_PACKAGES,readSuiteStatus,CORE_SUITE_DECLARATION_MISSING,readSuiteSourceState} from './suite.js';
|
|
5
|
+
import {SUITE_BUNDLE,SUITE_TARGET,SUITE_PACKAGES,readSuiteStatus,CORE_SUITE_DECLARATION_MISSING,readSuiteSourceState} from './suite.js';
|
|
6
6
|
import { PROTECTED_PACKAGES } from './install.js';
|
|
7
7
|
import { handoffSettings } from './handoff.js';
|
|
8
8
|
import { INSTALLATION_STATUS_CAPABILITY } from '../installation-status.js';
|
|
@@ -70,7 +70,7 @@ export function createLibraryService({domain,host,config={},dataRoot,ledgerReade
|
|
|
70
70
|
requireCondition(packageName===undefined,'INVALID_INPUT','套件升级不接受包名或任意替换参数。');
|
|
71
71
|
requireCondition(typeof installer?.prepareSuiteUpgrade==='function','SUITE_UPGRADE_UNAVAILABLE','当前客户端还不支持安全套件升级,请使用补齐命令。',{},503);
|
|
72
72
|
const plan=await installer.prepareSuiteUpgrade();
|
|
73
|
-
return{contractVersion:'1',source:{kind:'suite',manifestUrl:'https://github.com/yzsnstotz'},item:{id:SUITE_TARGET,displayName:'HanaMesh 套件',kind:'suite-upgrade',package:{registry:'npm',name:
|
|
73
|
+
return{contractVersion:'1',source:{kind:'suite',manifestUrl:'https://github.com/yzsnstotz'},item:{id:SUITE_TARGET,displayName:'HanaMesh 套件',kind:'suite-upgrade',package:{registry:'npm',name:SUITE_BUNDLE},latestVersion:plan.bundle.to,installed:{state:'installed',version:suiteStatus.version},upgradeAvailable:plan.available,suiteUpgrade:plan}};
|
|
74
74
|
}
|
|
75
75
|
requireCondition(itemId!==undefined||packageName!==undefined,'INVALID_INPUT','itemId or packageName is required.');
|
|
76
76
|
requireCondition(itemId===undefined||(text(itemId,160)&&!/[\u0000-\u001f\u007f]/.test(itemId)),'INVALID_INPUT','itemId is invalid.');
|
|
@@ -152,7 +152,7 @@ export function createLibraryService({domain,host,config={},dataRoot,ledgerReade
|
|
|
152
152
|
get live(){return Boolean(installer?.live);},
|
|
153
153
|
async upgradeSuite(input){requireInstaller('Suite upgrade is unavailable.');
|
|
154
154
|
requireCondition(input&&Object.keys(input).length===1&&typeof input.planId==='string','INVALID_INPUT','Only the current planId is accepted.');
|
|
155
|
-
return await operation('install',async()=>{try{const result=await installer.upgradeSuite(input);suiteStatus={...await suiteFacts(),restartRequired:true};return result;}catch(error){if(error.details?.stage!=='suite-upgrade')throw error;const actual=await readSuiteStatus(config.profileDir);suiteStatus={...await suiteFacts(),restartRequired:true,upgradeError:error.code??'SUITE_UPGRADE_FAILED'};error.details={...error.details,stage:'suite-upgrade',actual,command:error.details.command};emit({type:'library.install-failed',packageName:
|
|
155
|
+
return await operation('install',async()=>{try{const result=await installer.upgradeSuite(input);suiteStatus={...await suiteFacts(),restartRequired:true};return result;}catch(error){if(error.details?.stage!=='suite-upgrade')throw error;const actual=await readSuiteStatus(config.profileDir);suiteStatus={...await suiteFacts(),restartRequired:true,upgradeError:error.code??'SUITE_UPGRADE_FAILED'};error.details={...error.details,stage:'suite-upgrade',actual,command:error.details.command};emit({type:'library.install-failed',packageName:SUITE_BUNDLE,code:error.code??'SUITE_UPGRADE_FAILED',details:{stage:'suite-upgrade',actual,command:error.details.command}});throw error;}});
|
|
156
156
|
},
|
|
157
157
|
async install(input){requireCondition(input?.itemId!==SUITE_TARGET,'SUITE_CONFIRMATION_REQUIRED','请在客户端确认完整升级计划。',{},403);requireInstaller('Install requires absolute profileDir, nodeBinary, dshBin and profileName.');const{item}=await resolveTarget(input??{});if(present(item.installed)&&!item.upgradeAvailable)return{status:'already-installed',itemId:item.id,packageName:item.package.name};return await installItem(item);},
|
|
158
158
|
async provision(input){requireInstaller('Runtime provision is unavailable.');
|
package/dist/library/suite.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {readFile} from 'node:fs/promises';
|
|
2
2
|
import {join} from 'node:path';
|
|
3
3
|
import semver from 'semver';
|
|
4
|
+
import {createRequire} from 'node:module';
|
|
5
|
+
import {pathToFileURL} from 'node:url';
|
|
4
6
|
import {randomUUID} from 'node:crypto';
|
|
5
7
|
import {requireCondition} from '../errors.js';
|
|
6
8
|
|
|
9
|
+
export const SUITE_BUNDLE='@hanamesh/hanamesh';
|
|
7
10
|
export const SUITE_TARGET='hanamesh:suite-upgrade';
|
|
8
11
|
export const SUITE_PACKAGES=Object.freeze([
|
|
9
12
|
{name:'@hanamesh/core',label:'Core',repo:'hanamesh-core'},
|
|
@@ -17,11 +20,16 @@ export async function readSuiteStatus(profileDir){
|
|
|
17
20
|
try{
|
|
18
21
|
const profile=await json(join(profileDir,'package.json'));
|
|
19
22
|
if(!profile.dependencies||!Array.isArray(profile.dsh?.profile?.bundles))throw new Error('unreadable profile');
|
|
23
|
+
const resolver=createRequire(pathToFileURL(join(profileDir,'package.json')));
|
|
24
|
+
let bundle,bundlePath;try{bundlePath=resolver.resolve(`${SUITE_BUNDLE}/package.json`);bundle=await json(bundlePath);}catch{}
|
|
25
|
+
const memberResolver=bundlePath?createRequire(bundlePath):resolver;
|
|
26
|
+
const selected=profile.dsh.profile.bundles.includes(SUITE_BUNDLE)&&Object.hasOwn(profile.dependencies,SUITE_BUNDLE);
|
|
20
27
|
const components=await Promise.all(SUITE_PACKAGES.map(async({name,label})=>{
|
|
21
|
-
let pkg;try{pkg=await json(
|
|
22
|
-
return{name,label,version:pkg?.name===name&&semver.valid(pkg.version)?pkg.version:null,active:
|
|
28
|
+
let pkg;try{pkg=await json(memberResolver.resolve(`${name}/package.json`));}catch{}
|
|
29
|
+
return{name,label,version:pkg?.name===name&&semver.valid(pkg.version)?pkg.version:null,active:selected};
|
|
23
30
|
}));
|
|
24
|
-
|
|
31
|
+
const version=bundle?.name===SUITE_BUNDLE&&semver.valid(bundle.version)?bundle.version:null;
|
|
32
|
+
return{status:version&&selected&&components.every(c=>c.version&&bundle.dependencies?.[c.name]===c.version)?'installed':'incomplete',version,components};
|
|
25
33
|
}catch{return{status:'unknown',version:null,components:[]};}
|
|
26
34
|
}
|
|
27
35
|
export const CORE_SUITE_DECLARATION_MISSING='Core 未提供套件声明';
|
|
@@ -31,10 +39,16 @@ const exact=value=>typeof value==='string'&&semver.valid(value)===value;
|
|
|
31
39
|
const digest=value=>typeof value==='string'&&/^[a-f0-9]{64}$/.test(value);
|
|
32
40
|
const nullableText=value=>value===null||text(value);
|
|
33
41
|
const invalid=()=>requireCondition(false,'CORE_SUITE_DECLARATION_INVALID','Core 套件声明无法用于精确安装。',{},503);
|
|
42
|
+
function exactInstallCommand(value){
|
|
43
|
+
if(value===null)return true;
|
|
44
|
+
const prefix=`dsh plugin --profile desktop add --save-exact ${SUITE_BUNDLE}@`;
|
|
45
|
+
return typeof value==='string'&&value.startsWith(prefix)&&exact(value.slice(prefix.length));
|
|
46
|
+
}
|
|
34
47
|
function validateDeclaration(value){
|
|
35
|
-
if(!object(value)||value.schemaVersion!==1||!text(value.checkedAt)||!
|
|
48
|
+
if(!object(value)||value.schemaVersion!==1||!text(value.checkedAt)||!exactInstallCommand(value.installCommand)||!digest(value.declarationId)||!text(value.nodeVersion)||!nullableText(value.registry)||!(value.bundleVersion===null||exact(value.bundleVersion))||!['complete','incomplete','unknown'].includes(value.completeness))invalid();
|
|
49
|
+
if(value.completeness==='complete'&&!exact(value.bundleVersion))invalid();
|
|
36
50
|
const manifest=value.manifest;
|
|
37
|
-
if(!object(manifest)||manifest.schemaVersion!==1||!text(manifest.id)||!object(manifest.core)||manifest.core.name!==SUITE_PACKAGES[0].name||!exact(manifest.core.version)||!text(manifest.core.repository)||!Array.isArray(manifest.components)||manifest.components.length!==2)invalid();
|
|
51
|
+
if(!object(manifest)||manifest.schemaVersion!==1||!text(manifest.id)||!object(manifest.bundle)||manifest.bundle.name!==SUITE_BUNDLE||!text(manifest.bundle.repository)||!object(manifest.core)||manifest.core.name!==SUITE_PACKAGES[0].name||!exact(manifest.core.version)||!text(manifest.core.repository)||!Array.isArray(manifest.components)||manifest.components.length!==2)invalid();
|
|
38
52
|
const members=new Map();
|
|
39
53
|
for(const row of manifest.components){if(!object(row)||!text(row.id)||!SUITE_PACKAGES.slice(1).some(p=>p.name===row.moduleName)||members.has(row.moduleName)||!text(row.versionRange)||!text(row.repository))invalid();members.set(row.moduleName,row.id);}
|
|
40
54
|
if(!Array.isArray(value.installed)||value.installed.length!==3||!Array.isArray(value.upgrades)||!Array.isArray(value.blocked)||!object(value.peerFacts)||!object(value.metadataDigests))invalid();
|
|
@@ -43,13 +57,12 @@ function validateDeclaration(value){
|
|
|
43
57
|
if(!object(row)||!text(row.id)||!SUITE_PACKAGES.some(p=>p.name===row.moduleName)||installed.has(row.moduleName)||!text(row.requiredRange)||!text(row.repository)||!(row.actualVersion===null||exact(row.actualVersion))||!nullableText(row.actualRepository)||!text(row.status)||(row.runningVersion!==undefined&&!exact(row.runningVersion)))invalid();
|
|
44
58
|
installed.set(row.moduleName,row);
|
|
45
59
|
}
|
|
46
|
-
for(const row of value.blocked)if(!object(row)||!text(row.code)||(row.
|
|
60
|
+
for(const row of value.blocked)if(!object(row)||!text(row.code)||(row.bundleVersion!==undefined&&!exact(row.bundleVersion))||(row.moduleName!==undefined&&!text(row.moduleName)))invalid();
|
|
47
61
|
if(!Object.values(value.peerFacts).every(nullableText)||!Object.values(value.metadataDigests).every(text))invalid();
|
|
48
62
|
for(const upgrade of value.upgrades){
|
|
49
|
-
if(!object(upgrade)||!exact(upgrade.
|
|
63
|
+
if(!object(upgrade)||!object(upgrade.bundle)||!text(upgrade.bundle.id)||upgrade.bundle.moduleName!==SUITE_BUNDLE||!exact(upgrade.bundle.version)||!text(upgrade.bundle.repository)||!digest(upgrade.bundle.metadataDigest)||!text(upgrade.registry)||!Array.isArray(upgrade.targets)||upgrade.targets.length!==3)invalid();
|
|
50
64
|
const targets=new Set();
|
|
51
65
|
for(const row of upgrade.targets){if(!object(row)||!text(row.id)||!SUITE_PACKAGES.some(p=>p.name===row.moduleName)||targets.has(row.moduleName)||!exact(row.version)||!text(row.repository)||!digest(row.metadataDigest))invalid();targets.add(row.moduleName);}
|
|
52
|
-
if(upgrade.targets.find(row=>row.moduleName===SUITE_PACKAGES[0].name).version!==upgrade.coreVersion)invalid();
|
|
53
66
|
}
|
|
54
67
|
return structuredClone(value);
|
|
55
68
|
}
|
|
@@ -98,12 +111,12 @@ export function createCoreSuiteAdapter({core=()=>undefined,registry,suiteSourceM
|
|
|
98
111
|
const selectedUpgrade=declaration.upgrades[0];
|
|
99
112
|
requireCondition(selectedUpgrade.registry===declaration.registry,'CORE_SUITE_SOURCE_MISMATCH','Core 升级组合来源与执行 registry 不符。',{},409);
|
|
100
113
|
const components=SUITE_PACKAGES.map(({name,label})=>{const from=declaration.installed.find(row=>row.moduleName===name).actualVersion;if(!exact(from))invalid();return{name,label,from,to:selectedUpgrade.targets.find(row=>row.moduleName===name).version};});
|
|
101
|
-
return{available:true,components,installCommand:declaration.installCommand,sourceBinding:binding,declarationId:declaration.declarationId,registry:declaration.registry,selectedUpgrade,physicalBaseline:declaration.installed,upgrades:declaration.upgrades,blocked:declaration.blocked};
|
|
114
|
+
return{available:true,bundle:{name:SUITE_BUNDLE,from:declaration.bundleVersion,to:selectedUpgrade.bundle.version},components,installCommand:declaration.installCommand,sourceBinding:binding,declarationId:declaration.declarationId,registry:declaration.registry,selectedUpgrade,physicalBaseline:declaration.installed,upgrades:declaration.upgrades,blocked:declaration.blocked};
|
|
102
115
|
};
|
|
103
116
|
Object.defineProperty(get,'unavailable',{get:()=>current()?null:CORE_SUITE_DECLARATION_MISSING});
|
|
104
117
|
get.readFacts=async()=>{
|
|
105
118
|
const declaration=await read();
|
|
106
|
-
return{status:declaration.completeness==='complete'?'installed':declaration.completeness,completeness:declaration.completeness,version:declaration.
|
|
119
|
+
return{status:declaration.completeness==='complete'?'installed':declaration.completeness,completeness:declaration.completeness,version:declaration.bundleVersion,
|
|
107
120
|
components:declaration.installed.map(row=>({...row,name:row.moduleName,label:SUITE_PACKAGES.find(p=>p.name===row.moduleName).label,version:row.actualVersion})),blocked:declaration.blocked};
|
|
108
121
|
};
|
|
109
122
|
return get;
|
|
@@ -119,7 +132,7 @@ export async function prepareSuiteUpgrade({coreSuitePlan}={}){
|
|
|
119
132
|
const plan=await coreSuitePlan();
|
|
120
133
|
requireCondition(plan!==undefined&&plan!==null,'CORE_SUITE_DECLARATION_MISSING',CORE_SUITE_DECLARATION_MISSING,{},503);
|
|
121
134
|
const invalid=()=>requireCondition(false,'CORE_SUITE_DECLARATION_INVALID','Core 套件声明无法用于精确安装。',{},503);
|
|
122
|
-
if(typeof plan!=='object'||Array.isArray(plan)||typeof plan.available!=='boolean'||!
|
|
135
|
+
if(typeof plan!=='object'||Array.isArray(plan)||typeof plan.available!=='boolean'||!object(plan.bundle)||plan.bundle.name!==SUITE_BUNDLE||!exact(plan.bundle.from)||!exact(plan.bundle.to)||!exactInstallCommand(plan.installCommand)||!Array.isArray(plan.components)||plan.components.length!==SUITE_PACKAGES.length)invalid();
|
|
123
136
|
const rows=new Map();
|
|
124
137
|
for(const row of plan.components){
|
|
125
138
|
if(!row||typeof row!=='object'||!SUITE_PACKAGES.some(p=>p.name===row.name)||rows.has(row.name)||typeof row.from!=='string'||semver.valid(row.from)!==row.from||typeof row.to!=='string'||semver.valid(row.to)!==row.to)invalid();
|
|
@@ -40,7 +40,7 @@ interface InstallationObservation {
|
|
|
40
40
|
kind:'responding-runtime'|'unobserved-runtime'|'official-user-profile'|'desktop-app';label:string};
|
|
41
41
|
status:'installed'|'not-installed'|'incomplete'|'unknown';
|
|
42
42
|
version:string|null;
|
|
43
|
-
versionKind:'
|
|
43
|
+
versionKind:'suite-bundle'|'agent-distribution';
|
|
44
44
|
components:readonly {name:string;version:string|null;active?:boolean;status?:string}[];
|
|
45
45
|
identity:{pluginName:string;marketplace:string}|null;
|
|
46
46
|
reason:{code:string;message:string;action:string}|null;
|
|
@@ -50,7 +50,7 @@ interface InstallationObservation {
|
|
|
50
50
|
|
|
51
51
|
The five distinct observations are: responding runtime, the other DSH/HanaMesh runtime (always `unknown`, not observed by this responder), Claude Code configured user-level CLI scope, Codex CLI configured local-marketplace user scope, and Codex/ChatGPT desktop App scope (always named `unknown`). CLI labels explicitly exclude project/other isolated profiles and desktop App. A valid absence is absence **only in the named configured scope**; never show it as a machine-wide uninstall. Preserve every responder/scope; ports are not durable instance identities. Conflicts between responders are unknown, never resolved by choosing one installed result.
|
|
52
52
|
|
|
53
|
-
Current runtime status/version/components come only from the optional public Core protocol `'1'` `getSuiteDeclaration()` **without an argument**, through the existing Core adapter. No registry request, health substitution, physical file-count completeness, version-range/peer/source algorithm or local upgrade selection is added. Complete maps to installed; incomplete stays incomplete; unknown stays unknown with top-level version null but known component versions and sanitized named blocked codes retained. Missing method, malformed declaration and read failure have distinct reasons. Each detection re-reads; Core removal/invalidation cannot reuse an old installed answer. Agent distribution version is independent of
|
|
53
|
+
Current runtime status/version/components come only from the optional public Core protocol `'1'` `getSuiteDeclaration()` **without an argument**, through the existing Core adapter. No registry request, health substitution, physical file-count completeness, version-range/peer/source algorithm or local upgrade selection is added. Complete maps to installed; incomplete stays incomplete; unknown stays unknown with top-level version null but known component versions and sanitized named blocked codes retained. Missing method, malformed declaration and read failure have distinct reasons. Each detection re-reads; Core removal/invalidation cannot reuse an old installed answer. Agent distribution version is independent of the DSH suite bundle version. Missing active fields remain absent.
|
|
54
54
|
|
|
55
55
|
## Explicit agent reader settings
|
|
56
56
|
|
|
@@ -94,3 +94,5 @@ Per-scope unknown reasons always include a safe code/message/action:
|
|
|
94
94
|
Start each explicit detection by clearing previous observations. Cancel fetch when the person clears/revokes/leaves, the consumer/identity changes, or the window unmounts. Discard late request generations. A failed read/capability disappearance never keeps old installed status. Do not poll, persist, forward inventory or change Core/Usage recording consent. G's website consumer owns these page lifecycle rules; the bridge cancels on disconnect and module unload and holds no cross-request observation cache.
|
|
95
95
|
|
|
96
96
|
Official command references: [Claude Code plugin commands](https://code.claude.com/docs/en/plugins/cli-reference), [Codex CLI plugin reference](https://learn.chatgpt.com/docs/cli/reference). [OpenAI local plugin scope documentation](https://developers.openai.com/plugins/build/plugins) describes multiple client scopes; CLI installation is not used here as proof of the desktop App.
|
|
97
|
+
|
|
98
|
+
For DSH/HanaMesh runtime observations, versionKind is suite-bundle and version is the installed @hanamesh/hanamesh version. Component rows retain their physical versions. Agent distribution observations retain their existing semantics.
|
package/docs/LIBRARY.md
CHANGED
|
@@ -94,3 +94,5 @@ HanaMesh 视图原样保留可选 `official:boolean`(包括 false)与 C-INDE
|
|
|
94
94
|
原生 lookup 异常包为 `REGISTRY_LOOKUP_FAILED`,原 Error 保留于 cause;已知具名码保留。`library.*-failed.details.diagnostic` 最多4001字符,含脱敏异常类型/消息/cause.code 与实际 registry configuration/fetch/readback、CLI run、profile readback 阶段;CLI 非零另含 exit、signal 与 stderr/输出摘要。同一摘要及 operationId 写宿主 logger.warn(logger失效时安全console),UI已有可展开技术详情显示,并提示检查 DSH 源设置/网络后手动重试。不记录请求头、正文、环境、stack 或任意 details;不猜历史丢失的原错。
|
|
95
95
|
|
|
96
96
|
规则模块只由宿主公开exports提供;普通DSH用与manager版本查询相同createRequire(anchor),Desktop限已证明的runtimeDir与匹配版本。没有新增manager依赖/peer、没有生产规则副本;无法定位/加载规则或端口不完整均REGISTRY_CONFIG_UNAVAILABLE。钉SHA的rc.2规则仅位于tests/fixtures,不进入发布包。
|
|
97
|
+
|
|
98
|
+
D1: DSH suite installation and upgrades use only @hanamesh/hanamesh. Core owns the bundle metadata and exact three dependency targets. A confirmed strict CLI add changes the bundle once; readback checks its saved version, activation and locked physical children. The suite display version is the bundle version. Ordinary market install/remove denies the bundle.
|
package/docs/LICENSES.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": {
|
|
3
3
|
"name": "@hanamesh/dsh-app-host",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.20",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"source": "git+https://github.com/yzsnstotz/hanamesh-plugin-app-host.git",
|
|
7
7
|
"purpose": "Application ownership, view leases, Router forwarding, and application library for official DSH"
|
|
@@ -11,16 +11,13 @@
|
|
|
11
11
|
"@hanamesh/lib-provision": {
|
|
12
12
|
"version": "0.2.1",
|
|
13
13
|
"license": "SEE LICENSE IN LICENSE",
|
|
14
|
-
"source": "
|
|
14
|
+
"source": "^0.2.1",
|
|
15
15
|
"purpose": "Runtime provision/remove/ledger API; 随包分发、源仓不变; no inlined copy",
|
|
16
|
-
"sha256": "4217b9fe1be98f6e82437539d1c4c43166ed1f5c292efff100733e0cb09530e9",
|
|
17
16
|
"specs": {
|
|
18
|
-
"dependencies": "
|
|
17
|
+
"dependencies": "^0.2.1"
|
|
19
18
|
},
|
|
20
|
-
"sourceCommit": "
|
|
21
|
-
"distribution": "bundleDependencies; original LICENSE at node_modules/@hanamesh/lib-provision/LICENSE"
|
|
22
|
-
"originalSource": "git+https://github.com/yzsnstotz/hanamesh-lib-provision.git#575d63fb70e08c47e980dbf25f07921a7ba5aa2a",
|
|
23
|
-
"archiveSha256": "4217b9fe1be98f6e82437539d1c4c43166ed1f5c292efff100733e0cb09530e9"
|
|
19
|
+
"sourceCommit": "838cf462de9192fb5f2d63497212e7275f5c6e39",
|
|
20
|
+
"distribution": "bundleDependencies; original LICENSE at node_modules/@hanamesh/lib-provision/LICENSE"
|
|
24
21
|
},
|
|
25
22
|
"zod": {
|
|
26
23
|
"version": "4.5.4",
|
|
@@ -235,27 +232,25 @@
|
|
|
235
232
|
}
|
|
236
233
|
},
|
|
237
234
|
"@hanamesh/devkit": {
|
|
238
|
-
"version": "0.2.
|
|
235
|
+
"version": "0.2.6",
|
|
239
236
|
"license": "SEE LICENSE IN LICENSE",
|
|
240
|
-
"source": "
|
|
237
|
+
"source": "https://registry.npmjs.org/@hanamesh/devkit/-/devkit-0.2.6.tgz",
|
|
241
238
|
"purpose": "Development-only centralized tool execution; never imported by runtime; no public peer",
|
|
242
239
|
"usedAs": [
|
|
243
240
|
"devDependencies"
|
|
244
241
|
],
|
|
245
242
|
"specs": {
|
|
246
|
-
"devDependencies": "
|
|
243
|
+
"devDependencies": "^0.2.6"
|
|
247
244
|
},
|
|
248
|
-
"sourceCommit": "e6ccf710369a77c5fbf9ce4810b182727e4f2aa8",
|
|
249
245
|
"licenseNotice": "# HanaMesh distribution notice\n\nThis package contains HanaMesh-owned code. The project owner confirmed that its\nown code may be distributed (D-2026-10-05-02) and directed correction of outdated\nprivate / UNLICENSED package metadata (D-2026-10-05-16, 2026-10-05).\n\nThis notice records that distribution authorization. It does not assign an SPDX\nlicense identifier, adopt MIT or another standard license, or grant additional\nrelicensing rights. Rights not covered by the owner's recorded distribution\nauthorization remain reserved. See LICENSE_RECORD.md for the package name,\nversion, source, purpose and third-party boundaries.\n\nThird-party components retain their existing licenses. No third-party component\nis relicensed by this notice. This metadata change is not an npm publication or\na change to repository visibility.\n",
|
|
250
|
-
"distributionRecord": "# Devkit license and distribution record\n\n| Name | Version | License / authorization | Source | Purpose |\n| --- | --- | --- | --- | --- |\n| @hanamesh/devkit | 0.2.
|
|
246
|
+
"distributionRecord": "# Devkit license and distribution record\n\n| Name | Version | License / authorization | Source | Purpose |\n| --- | --- | --- | --- | --- |\n| @hanamesh/devkit | 0.2.6 | SEE LICENSE IN LICENSE; HanaMesh-owned distribution authorized in D-2026-10-05-02 and D-2026-10-05-16; no new standard license or relicensing grant | yzsnstotz/hanamesh-server-shared, packages/devkit; baseline b2b5c9bb7faa990e3eb9f99007abd6427d62e88b / rc.1 | Development preflight, mutation execution, package verification and toolchain checks |\n\nThe original rc.1 manifest contained private=true and license=UNLICENSED, with no\nstandalone LICENSE text. Those obsolete metadata fields are superseded for rc.2\nby private=false and this explicit distribution notice. The old tarball and\nrecords remain unchanged. 0.2.0 adds Git tag-range installation and the\n`contract/` supply schema, fixtures and suite under the same authorization;\nit still adds no dependency. This package has no dependency or peerDependency and\nships no third-party runtime or compiler. It uses Node standard-library APIs;\nNode itself is supplied by the consumer and is not bundled here.\n\nAuthority: the project owner's 2026-10-05 instruction to correct lib-provision\nand devkit vendor metadata under D-2026-10-05-02, recorded in D-2026-10-05-16.\nThe notice does not extend that instruction into a new general license.\n",
|
|
251
247
|
"licenseSha256": "242b0b71d3a4a91899ccf38fb70f06d151f3f005c3d7ac7d1e4a6c0461dc0e2d",
|
|
252
248
|
"historicalArtifact": {
|
|
253
249
|
"version": "0.2.0",
|
|
254
250
|
"sha256": "de15f0913dd6de5ba9ce96b8d92ea862ec44489eb698628de963cbbead68bc25",
|
|
255
251
|
"sourceCommit": "8f9bcc69cbacf01d97ffe63bbbade4f865e6dd89"
|
|
256
252
|
},
|
|
257
|
-
"
|
|
258
|
-
"archiveSha256": "40d7ad33b2802677d12111943f3472aa6e4564ba000d48074a32de33ff51c7bb"
|
|
253
|
+
"sourceCommit": "019033b83aa0ede9e0c54d735f1ee5349fe39998"
|
|
259
254
|
},
|
|
260
255
|
"semver": {
|
|
261
256
|
"version": "7.8.5",
|
|
@@ -298,13 +293,13 @@
|
|
|
298
293
|
"@hanamesh/core": {
|
|
299
294
|
"version": "0.3.28",
|
|
300
295
|
"license": "MIT",
|
|
301
|
-
"source": "https://
|
|
296
|
+
"source": "https://registry.npmjs.org/@hanamesh/core/-/core-0.3.28.tgz",
|
|
302
297
|
"purpose": "Development-only public Core suite declaration and provider-owned install command for clean CI; never runtime or bundled",
|
|
303
298
|
"usedAs": [
|
|
304
299
|
"devDependencies"
|
|
305
300
|
],
|
|
306
301
|
"specs": {
|
|
307
|
-
"devDependencies": "
|
|
302
|
+
"devDependencies": "^0.3.28"
|
|
308
303
|
},
|
|
309
304
|
"sourceCommit": "62059ca586be2bffa054b5d392ebde41c51939ec",
|
|
310
305
|
"archiveSha256": "9ef8c250efa3bc46de583dc82103719d71d9f3dcc2233fd49731b4467337efa9",
|
package/docs/PROVENANCE.json
CHANGED
|
@@ -69,35 +69,31 @@
|
|
|
69
69
|
"historicalCandidateLicense": "UNLICENSED; no upstream-license inheritance or open-source grant asserted",
|
|
70
70
|
"developmentArtifacts": {
|
|
71
71
|
"@hanamesh/devkit": {
|
|
72
|
-
"version": "0.2.
|
|
73
|
-
"source": "
|
|
74
|
-
"sourceCommit": "
|
|
75
|
-
"mode": "
|
|
72
|
+
"version": "0.2.6",
|
|
73
|
+
"source": "https://registry.npmjs.org/@hanamesh/devkit/-/devkit-0.2.6.tgz",
|
|
74
|
+
"sourceCommit": "019033b83aa0ede9e0c54d735f1ee5349fe39998",
|
|
75
|
+
"mode": "Public npm package; development-only, excluded from runtime tarball",
|
|
76
76
|
"license": "SEE LICENSE IN LICENSE",
|
|
77
77
|
"distributionNotice": "Canonical LICENSE and LICENSE_RECORD.md copied verbatim to docs/LICENSES.json; no new MIT or relicensing grant",
|
|
78
78
|
"lockfile": {
|
|
79
79
|
"path": "pnpm-lock.yaml",
|
|
80
|
-
"resolution": "
|
|
80
|
+
"resolution": "npm registry version with sha512 integrity, no Git credentials"
|
|
81
81
|
},
|
|
82
82
|
"licenseSha256": "242b0b71d3a4a91899ccf38fb70f06d151f3f005c3d7ac7d1e4a6c0461dc0e2d",
|
|
83
83
|
"historicalArtifact": {
|
|
84
84
|
"version": "0.2.0",
|
|
85
85
|
"sha256": "de15f0913dd6de5ba9ce96b8d92ea862ec44489eb698628de963cbbead68bc25",
|
|
86
86
|
"sourceCommit": "8f9bcc69cbacf01d97ffe63bbbade4f865e6dd89"
|
|
87
|
-
}
|
|
88
|
-
"originalSource": "git+https://github.com/yzsnstotz/hanamesh-server-shared.git#semver:^0.2.0&path:/packages/devkit",
|
|
89
|
-
"sha256": "40d7ad33b2802677d12111943f3472aa6e4564ba000d48074a32de33ff51c7bb"
|
|
87
|
+
}
|
|
90
88
|
}
|
|
91
89
|
},
|
|
92
90
|
"externalArtifacts": {
|
|
93
91
|
"@hanamesh/lib-provision": {
|
|
94
92
|
"version": "0.2.1",
|
|
95
|
-
"source": "
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
100
|
-
"originalSource": "git+https://github.com/yzsnstotz/hanamesh-lib-provision.git#575d63fb70e08c47e980dbf25f07921a7ba5aa2a"
|
|
93
|
+
"source": "https://registry.npmjs.org/@hanamesh/lib-provision/-/lib-provision-0.2.1.tgz",
|
|
94
|
+
"mode": "Public npm package; bundled runtime dependency",
|
|
95
|
+
"sourceCommit": "838cf462de9192fb5f2d63497212e7275f5c6e39",
|
|
96
|
+
"license": "SEE LICENSE IN LICENSE"
|
|
101
97
|
}
|
|
102
98
|
},
|
|
103
99
|
"historicalInputNotice": "Top-level legacy input/runtime/prototype fields below describe the original rc.12 intake only. Current candidate identity and verification are in currentCandidate; they do not inherit legacy host/UI evidence."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanamesh/dsh-app-host",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.20",
|
|
4
4
|
"description": "HanaMesh application ownership, durable view leases, and application library for official DSH 0.2.x",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
88
|
"zod": "4.5.4",
|
|
89
|
-
"@hanamesh/lib-provision": "
|
|
89
|
+
"@hanamesh/lib-provision": "^0.2.1",
|
|
90
90
|
"semver": "7.8.5"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
}
|
|
116
116
|
},
|
|
117
117
|
"devDependencies": {
|
|
118
|
-
"@hanamesh/core": "
|
|
118
|
+
"@hanamesh/core": "^0.3.28",
|
|
119
119
|
"@deepseek-ai/cordis": "4.0.5-alpha.1",
|
|
120
120
|
"@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.2",
|
|
121
121
|
"@deepseek-ai/dsh-scope": "0.2.1-alpha.2",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"@deepseek-ai/dsh-storage-json": "0.2.1-alpha.2",
|
|
129
129
|
"@deepseek-ai/schemastery": "3.18.5-alpha.1",
|
|
130
130
|
"typescript": "5.8.3",
|
|
131
|
-
"@hanamesh/devkit": "
|
|
131
|
+
"@hanamesh/devkit": "^0.2.6",
|
|
132
132
|
"@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.2",
|
|
133
133
|
"@hanamesh/release-platform-gate": "file:vendor/hanamesh-release-platform-gate-0.1.10.tgz"
|
|
134
134
|
},
|