@hanamesh/dsh-app-host 0.6.20 → 0.6.21
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 +2 -0
- package/dist/client-ui.d.ts +4 -1
- package/dist/client-ui.js +23 -19
- 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 +26 -6
- package/dist/library/catalog.js +24 -7
- package/dist/library/github-target.js +42 -0
- package/dist/library/handoff.js +5 -2
- package/dist/library/install.js +17 -7
- package/dist/library/recovery.js +5 -3
- package/dist/library/routes.js +1 -0
- package/dist/library/service.js +35 -19
- package/docs/CONTRACT.md +2 -2
- package/docs/INSTALL_TARGET.md +20 -4
- package/docs/LIBRARY.md +1 -1
- package/docs/LICENSES.json +1 -1
- package/docs/SECURITY.md +2 -0
- package/package.json +1 -1
- package/schemas/catalog-provider-page.schema.json +97 -10
- package/schemas/install-target.schema.json +252 -38
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
0.6.21 候选:普通市场和网站交接消费 Indexer 的固定 GitHub SHA/子目录/包名/构建名单。客户端沿原确认页展示来源、完整 commit 与本机构建提示;确认回传同一目标,目录更新不得换 SHA。执行仍走受控官方 DSH CLI / pnpm,读回精确来源与启用项后报告需完全退出重开;没有改上游或另写安装器。详见 [安装目标](docs/INSTALL_TARGET.md)。初轮已完成隔离 DSH、网站及真实 DTO 验收;本轮 R25 另修未匹配固定目标时的拒绝与退休目录版本字段,仍待复审,不宣称已发布。
|
|
2
|
+
|
|
1
3
|
0.6.16 候选:普通市场通过注入的宿主 pluginManager.registries() 读取源事实,并按宿主锚点/版本守卫加载公开 ./registry 规则模块;AppHost 不声明、安装或捆绑 manager。发布依赖/peer闭包与0.6.15一致。pnpm自有源(null)不显式传--registry,配置镜像则传同一源;查询30秒具名超时,脱敏原诊断同进UI和日志。
|
|
2
4
|
|
|
3
5
|
0.6.15 候选:市场保留官方 CLI 的 stdout/stderr 真实失败原因并脱敏,在卡片与安装确认的技术详情中显示。正文显示 pnpm 真实错误类别;宿主发布时间检查失败时列出受影响包与实际 cutoff;HanaMesh 总包安装/升级使用精确发布版本,发布后即可验收;不修改 profile、pnpm 供应链策略或安装执行路径。
|
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
|
@@ -198,7 +198,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
198
198
|
"copy185": "检查兼容升级",
|
|
199
199
|
"copy186": "重试安装",
|
|
200
200
|
"copy187": "升级",
|
|
201
|
-
"copy188": "升级到 ",
|
|
202
201
|
"copy189": "补齐运行时",
|
|
203
202
|
"copy190": "卸载",
|
|
204
203
|
"copy191": "已卸载,重启 DSH 后生效",
|
|
@@ -224,8 +223,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
224
223
|
"copy211": "查看安装目标",
|
|
225
224
|
"copy212": "市场安装确认",
|
|
226
225
|
"copy213": "插件名",
|
|
227
|
-
"copy214": "版本",
|
|
228
|
-
"copy215": "目录未提供版本",
|
|
229
226
|
"copy216": "测试目录(fixture)",
|
|
230
227
|
"copy217": "当前市场目录",
|
|
231
228
|
"copy218": "确认后升级 HanaMesh 总包及其锁定组件;需要完全退出并重新打开客户端。",
|
|
@@ -281,7 +278,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
281
278
|
"copy268": "交接状态只给发起它的那个网站看",
|
|
282
279
|
"copy269": "一个网站不能读另一个网站的交接",
|
|
283
280
|
"copy270": "交接请求体不超过 4096 字节",
|
|
284
|
-
"copy271": "
|
|
281
|
+
"copy271": "交接只包含目录身份、合约版本及已审核的结构化安装目标;正文上限为 4096 字节,不接受来源命令",
|
|
285
282
|
"copy272": "端口在 1024–65535 之间、互不重复,至少一个",
|
|
286
283
|
"copy273": "1024 以下要管理员权限;没有端口就没有地方让网站找到",
|
|
287
284
|
"copy274": "网站必须写成来源(协议 + 域名 [+ 端口]),http 只允许 127.0.0.1 / localhost",
|
|
@@ -506,7 +503,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
506
503
|
"copy185": "Check compatible upgrade",
|
|
507
504
|
"copy186": "Retry installation",
|
|
508
505
|
"copy187": "Upgrade",
|
|
509
|
-
"copy188": "Upgrade to ",
|
|
510
506
|
"copy189": "Prepare runtime",
|
|
511
507
|
"copy190": "Uninstall",
|
|
512
508
|
"copy191": "Uninstalled; restart DSH to apply",
|
|
@@ -532,8 +528,6 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
532
528
|
"copy211": "Review installation target",
|
|
533
529
|
"copy212": "Confirm market installation",
|
|
534
530
|
"copy213": "Plugin name",
|
|
535
|
-
"copy214": "Version",
|
|
536
|
-
"copy215": "No version provided by catalog",
|
|
537
531
|
"copy216": "Test catalog (fixture)",
|
|
538
532
|
"copy217": "Current market catalog",
|
|
539
533
|
"copy218": "Confirmation upgrades the HanaMesh bundle and its locked components. Fully quit and reopen the client afterwards.",
|
|
@@ -589,7 +583,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
589
583
|
"copy268": "Handoff status is visible only to the website that created it.",
|
|
590
584
|
"copy269": "One website cannot read another website’s handoffs.",
|
|
591
585
|
"copy270": "Handoff request body must not exceed 4096 bytes.",
|
|
592
|
-
"copy271": "A
|
|
586
|
+
"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
587
|
"copy272": "Provide at least one distinct port between 1024 and 65535.",
|
|
594
588
|
"copy273": "Lower ports need administrator permissions. Without a port the website cannot find this client.",
|
|
595
589
|
"copy274": "Websites must be origins (scheme + domain [+ port]). HTTP is allowed only for 127.0.0.1 / localhost.",
|
|
@@ -621,6 +615,8 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
621
615
|
"copy301": "Supports macOS 13.5+ (Apple Silicon / Intel). Windows installation, guardian and cancellation verification are not connected; this flow does not support Windows."
|
|
622
616
|
}
|
|
623
617
|
};
|
|
618
|
+
Object.assign(COPY.zh,{githubRepository:'来源仓库',githubCommit:'固定 commit',githubPath:'仓库子目录',githubBuild:'会在本机执行构建脚本',githubBuildPolicy:'确认后将按名单允许构建;pnpm 会把许可保存到当前 profile。',githubNoBuild:'未授予构建脚本许可'});
|
|
619
|
+
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
620
|
const COPY_KEYS=new Map(Object.entries(COPY.zh).map(([key,text])=>[text,key]));
|
|
625
621
|
let localeService=null;
|
|
626
622
|
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 +662,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
666
662
|
let targetSelection=null,targetSequence=0,pendingOperations={};
|
|
667
663
|
const targetListeners=new Set(),pendingListeners=new Set();
|
|
668
664
|
const INSTALL_TARGET_HASH='#hanamesh-install?',INSTALL_TARGET_CONTRACT_VERSION='1';
|
|
665
|
+
const targetQuery=input=>new URLSearchParams({...input,...(input.installTarget?{installTarget:JSON.stringify(input.installTarget)}:{})});
|
|
669
666
|
const CORE_SUITE_FAILURES={CORE_SUITE_DECLARATION_MISSING:t('Core 未提供套件声明'),CORE_SUITE_DECLARATION_INVALID:t('Core 套件声明无法用于精确安装。')};
|
|
670
667
|
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
668
|
const setTarget=value=>{targetSelection=value;for(const listener of targetListeners)listener(value);};
|
|
@@ -677,11 +674,12 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
677
674
|
if(!input||typeof input!=='object'||Array.isArray(input))throw new Error('INVALID_INPUT');
|
|
678
675
|
// rc.8: optional contract declaration; absent keeps v1 semantics, an unsupported version is refused before any request.
|
|
679
676
|
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)||
|
|
677
|
+
if(Object.keys(input).some(key=>!['itemId','packageName','contractVersion','installTarget'].includes(key))||(!input.itemId&&!input.packageName)||
|
|
678
|
+
(input.installTarget!==undefined&&(!input.itemId||!input.installTarget||typeof input.installTarget!=='object'||Array.isArray(input.installTarget)))||
|
|
681
679
|
(input.itemId!==undefined&&(typeof input.itemId!=='string'||!input.itemId.length||input.itemId.length>160||/[\u0000-\u001f\u007f]/.test(input.itemId)))||
|
|
682
680
|
(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
681
|
setTarget({status:'resolving',input:{...input}});
|
|
684
|
-
const query=
|
|
682
|
+
const query=targetQuery(input),resolved=await request('/hanamesh/library/target?'+query);
|
|
685
683
|
if(sequence!==targetSequence)return{status:'superseded'};
|
|
686
684
|
const item=resolved.item,op=pendingOperations[item.id];
|
|
687
685
|
const status=op?.busy?'installing':['registered','installed','installed-not-loaded'].includes(item.installed?.state)&&!item.upgradeAvailable?'already-installed':'confirmation-required';
|
|
@@ -707,7 +705,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
707
705
|
if(handoffIssue?.poll)setHandoffIssue(null);
|
|
708
706
|
for(const row of value.handoffs??[]){
|
|
709
707
|
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};
|
|
708
|
+
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
709
|
let opened=false;
|
|
712
710
|
try{await openInstallTarget(input,{handoffId:row.handoffId});opened=true;}
|
|
713
711
|
catch(error){noteHandoffIssue(t('确认框打不开'),error);await reportHandoff(row.handoffId,'failed',{code:errorCode(error)});}
|
|
@@ -720,7 +718,9 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
720
718
|
const hash=globalThis.location?.hash;if(!hash?.startsWith(INSTALL_TARGET_HASH))return;
|
|
721
719
|
const params=new URLSearchParams(hash.slice(INSTALL_TARGET_HASH.length));
|
|
722
720
|
if(new Set(params.keys()).size!==[...params.keys()].length){targetSequence++;if(entryVisible)setLibraryVisible(true);setTarget({status:'failed',error:'INVALID_INPUT'});return;}
|
|
723
|
-
|
|
721
|
+
const input=Object.fromEntries(params);
|
|
722
|
+
if(input.installTarget!==undefined){try{input.installTarget=JSON.parse(input.installTarget);}catch{setTarget({status:'failed',error:'INVALID_INPUT'});return;}}
|
|
723
|
+
void openInstallTarget(input).catch(()=>{});
|
|
724
724
|
}
|
|
725
725
|
// rc.32 market seat. The shell's Extension Management panel (dsh-tauri-panel-extension) reads the client-side
|
|
726
726
|
// cordis service `market` via `ctx.reflect.get('market')` and shows a 「市场」 tab when it is there; it calls
|
|
@@ -990,14 +990,15 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
990
990
|
const selected=targetSelection;if(selected?.status!=='confirmation-required'||pendingOperations[selected.item.id]?.busy)return;
|
|
991
991
|
setTarget({...selected,status:'installing'});
|
|
992
992
|
const suite=selected.item.kind==='suite-upgrade';
|
|
993
|
-
const
|
|
993
|
+
const reviewed={itemId:selected.item.id,packageName:selected.item.package.name,...(selected.item.installTarget?{installTarget:selected.item.installTarget}:{})};
|
|
994
|
+
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
995
|
if(outcome){
|
|
995
996
|
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
997
|
if(suite){
|
|
997
998
|
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
999
|
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
1000
|
}
|
|
1000
|
-
try{const fresh=await request('/hanamesh/library/target?'+
|
|
1001
|
+
try{const fresh=await request('/hanamesh/library/target?'+targetQuery(reviewed));
|
|
1001
1002
|
const row=fresh.item?.installed;
|
|
1002
1003
|
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
1004
|
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 +1049,21 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1048
1049
|
const restartRequired=changed||Boolean(snapshot?.restartRequired);
|
|
1049
1050
|
const filters=[...BASE_FILTERS,...seenCategories.filter(c=>c!=='hanamesh-app').map(c=>[c,c])];
|
|
1050
1051
|
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}:{})};
|
|
1052
|
+
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}:{})};
|
|
1053
|
+
const reviewOrInstall=label=>item.installTarget?openInstallTarget(installBody).catch(()=>{}):operate('/hanamesh/library/install',installBody,item.id,label);
|
|
1052
1054
|
let action=h('span',null,t('仅收录,不可安装')),state=null;
|
|
1053
1055
|
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
1056
|
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
1057
|
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
|
|
1058
|
+
else if(item.kind!=='listing'&&!row)action=h('button',{type:'button',onClick:()=>void reviewOrInstall(t('安装'))},op?.failed?t('重试安装'):t('安装'));
|
|
1059
|
+
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
1060
|
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
1061
|
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
1062
|
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
1063
|
else if(row?.state==='uninstalled-not-unloaded')action=h('span',null,t('已卸载,重启 DSH 后生效'));
|
|
1062
1064
|
else if(row)action=h('span',null,t('已安装,重启 DSH 后生效'));
|
|
1063
1065
|
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('未知发布者'))+
|
|
1066
|
+
h('small',null,t(KIND_TEXT[item.kind])+' · '+(item.publisher?.name??t('未知发布者'))+((item.categories??[]).length?' · '+item.categories.join('、'):'')),
|
|
1065
1067
|
state,action,op&&!busy?operationNotice(op):null);};
|
|
1066
1068
|
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
1069
|
h('div',{className:'hm-library-grid',key:'catalog'},...items.map(card));
|
|
@@ -1082,7 +1084,9 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1082
1084
|
h('input',{'aria-label':t('目录条目 ID'),value:targetItemId,placeholder:t('itemId(可选)'),onChange:event=>setTargetItemId(event.target.value)}),
|
|
1083
1085
|
h('input',{'aria-label':t('包名'),value:targetPackageName,placeholder:t('packageName(可选)'),onChange:event=>setTargetPackageName(event.target.value)}),h('button',{type:'submit'},t('查看安装目标')))):null,
|
|
1084
1086
|
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('
|
|
1087
|
+
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,
|
|
1088
|
+
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,
|
|
1089
|
+
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
1090
|
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
1091
|
target.item?.suiteUpgrade?.registry?h('p',null,'Registry:'+target.item.suiteUpgrade.registry):null,
|
|
1088
1092
|
...(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:''))),
|
|
@@ -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
|
}
|