@hanamesh/dsh-app-host 0.6.24 → 0.6.25
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 +11 -1
- package/dist/client-ui.js +117 -22
- package/dist/install-target/harness.js +2 -0
- package/dist/install-target/suite.js +3 -3
- package/dist/library/catalog.js +4 -3
- package/dist/library/installation-status.js +6 -1
- package/docs/CONTRACT.md +32 -1
- package/docs/INSTALLATION_STATUS.md +6 -0
- package/docs/LIBRARY.md +1 -1
- package/docs/LICENSES.json +1 -1
- package/node_modules/@hanamesh/lib-provision/bin/hanamesh-provision.js +0 -0
- package/package.json +26 -23
- package/schemas/catalog-source.schema.json +5 -5
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
0.6.25 候选:本机 HTTPS 目录允许回环端口及 *.localhost,修复彩排种子初始化阻断检测监听;公网 HTTPS 非标准端口仍拒绝。Claude 官方 GitHub 市场清单按 repo 身份核对,保留不同来源拒绝。安装物回归命令见[安装状态](docs/INSTALLATION_STATUS.md),不以页面打开代替检测通过。
|
|
2
|
+
|
|
1
3
|
PX3 跨平台候选:Windows 可以运行插件/公开服务、attach 应用、受控只读 CLI 与普通包安装;`owned` 应用仍在创建进程、数据目录及请求凭据之前明确拒绝 `PLATFORM_UNSUPPORTED`。Windows 单测保留真实 attach 的 HTTP/租约/网关断言,并验证 owned 的持久失败、无进程/文件写入及不消费凭据;这些断言不构成 Windows owned 运行支持。独立 Node 可用不扩大 owned 支持;受管 Node 准备仍遵守原平台限制。Windows 本地快照采用文件 flush 加同目录 rename,不承诺断电后目录项持久;Coding OAuth Gateway 文件源因缺私有 ACL 证明继续拒绝,HTTP 提供方不变。各平台实际结果以本分支 GitHub Actions 矩阵收据为准。
|
|
2
4
|
|
|
3
5
|
R115返修(同0.6.23候选):登录shell按退出结果和封装JSON解析成功,忽略正常stderr;所选CLI保留管理器PATH与XDG目录/缺省,不再用空临时XDG隐藏全局版本。真实Bash/asdf/mise启动链回归与工具来源见 [安装状态](docs/INSTALLATION_STATUS.md)。
|
package/dist/client-ui.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export function NodeRuntimeSection():unknown;
|
|
|
12
12
|
export function LibraryAction():unknown;
|
|
13
13
|
/** The HanaMesh market page (applications + plugins; install / upgrade / uninstall / restart notice).
|
|
14
14
|
* `embedded` renders it inline for the Extension Management tab instead of as the shell overlay. */
|
|
15
|
-
export function LibraryOverlay(props?:{embedded?:boolean,preferredSubsectionId?:string,verification?:boolean}):unknown;
|
|
15
|
+
export function LibraryOverlay(props?:{embedded?:boolean,mainPage?:boolean,preferredSubsectionId?:string,verification?:boolean}):unknown;
|
|
16
16
|
/** rc.32: the「只能其一」notice shown at the top of the market page when dshmarket holds the seat. */
|
|
17
17
|
export function MarketConflictNotice():unknown;
|
|
18
18
|
/** Identifiers only; metadata and confirmation are owned by the client's market. */
|
|
@@ -38,3 +38,13 @@ export const INSTALL_TARGET_CONTRACT_VERSION:'1';
|
|
|
38
38
|
|
|
39
39
|
/** AppHost-owned registry selection, independent of catalog manifest sources. */
|
|
40
40
|
export function SuiteSourceSettingsSection():unknown;
|
|
41
|
+
|
|
42
|
+
/** Additive DSH layout seats and the Core-owned environment content extension. */
|
|
43
|
+
export function registerAppHostPages(ctx:unknown):()=>void;
|
|
44
|
+
export function EnvironmentContent():unknown;
|
|
45
|
+
/** Current catalog contract supplies none of these counts; null is explicit unknown, never zero. */
|
|
46
|
+
export interface CredibilityFacts {itemId?:string;signals?:{stars?:number|null;npmDownloads30d?:number|null;storeInstalls30d?:number|null;checkedAt?:string|null}|null;popularity?:{users30d?:number|null;asOf?:string|null}|null;checkedAt?:string|null;asOf?:string|null}
|
|
47
|
+
export function credibilityFacts(facts?:CredibilityFacts|null):{id:string;label:string;value:number|null;reason:'catalog-field-unavailable'|null}[];
|
|
48
|
+
export function readCredibility(source:unknown,item:{id:string},fetcher?:typeof fetch):Promise<CredibilityFacts>;
|
|
49
|
+
/** HanaMesh-view catalog website link; absent for fixtures and other provider protocols. */
|
|
50
|
+
export function catalogWebsiteLink(source:unknown,item:unknown):string|null;
|
package/dist/client-ui.js
CHANGED
|
@@ -609,6 +609,41 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
609
609
|
};
|
|
610
610
|
Object.assign(COPY.zh,{githubRepository:'来源仓库',githubCommit:'固定 commit',githubPath:'仓库子目录',githubBuild:'会在本机执行构建脚本',githubBuildPolicy:'确认后将按名单允许构建;pnpm 会把许可保存到当前 profile。',githubNoBuild:'未授予构建脚本许可'});
|
|
611
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'});
|
|
612
|
+
// Owned copy for the additive HanaMesh pages.
|
|
613
|
+
COPY.zh.cl1Page0="应用库";COPY.en.cl1Page0="Library";
|
|
614
|
+
COPY.zh.cl1Page1="详情";COPY.en.cl1Page1="Details";
|
|
615
|
+
COPY.zh.cl1Page2="返回应用库";COPY.en.cl1Page2="Back to library";
|
|
616
|
+
COPY.zh.cl1Page3="关于这个应用";COPY.en.cl1Page3="About this app";
|
|
617
|
+
COPY.zh.cl1Page4="可信度";COPY.en.cl1Page4="Credibility";
|
|
618
|
+
COPY.zh.cl1Page5="GitHub 星数";COPY.en.cl1Page5="GitHub stars";
|
|
619
|
+
COPY.zh.cl1Page6="npm 下载 / 30 天";COPY.en.cl1Page6="npm downloads / 30 days";
|
|
620
|
+
COPY.zh.cl1Page7="安装人数";COPY.en.cl1Page7="People who installed";
|
|
621
|
+
COPY.zh.cl1Page8="使用人数";COPY.en.cl1Page8="People who used";
|
|
622
|
+
COPY.zh.cl1Page9="当前目录未提供";COPY.en.cl1Page9="Not supplied by this catalog";
|
|
623
|
+
COPY.zh.cl1Page10="可信度数据缺失不代表 0;本机安装状态与平台采用度分别显示。";COPY.en.cl1Page10="Missing credibility data does not mean zero. Local installation state is separate from platform adoption.";
|
|
624
|
+
COPY.zh.cl1Page11="来源与安装目标";COPY.en.cl1Page11="Source and installation target";
|
|
625
|
+
COPY.zh.cl1Page12="在网站查看";COPY.en.cl1Page12="View on website";
|
|
626
|
+
COPY.zh.cl1Page13="发现适合你的工具,查看来源后再安装;账号与模型授权分别管理。";COPY.en.cl1Page13="Find tools for your work and review their sources before installing. Account and model authorization are managed separately.";
|
|
627
|
+
COPY.zh.cl1Page14="安装确认";COPY.en.cl1Page14="Confirm installation";
|
|
628
|
+
COPY.zh.cl1Page15="我已核对来源与安装目标";COPY.en.cl1Page15="I reviewed the source and installation target";
|
|
629
|
+
COPY.zh.cl1Page16="设置与连接";COPY.en.cl1Page16="Settings and connections";
|
|
630
|
+
COPY.zh.cl1Page17="账号与设备";COPY.en.cl1Page17="Account and device";
|
|
631
|
+
COPY.zh.cl1Page18="模型连接";COPY.en.cl1Page18="Model connections";
|
|
632
|
+
COPY.zh.cl1Page19="环境与来源";COPY.en.cl1Page19="Environment and sources";
|
|
633
|
+
COPY.zh.cl1Page20="HanaMesh / 模型连接";COPY.en.cl1Page20="HanaMesh / Model connections";
|
|
634
|
+
COPY.zh.cl1Page21="连接模型,保持掌控。";COPY.en.cl1Page21="Connect models, stay in control.";
|
|
635
|
+
COPY.zh.cl1Page22="登录账号不提供模型凭据。沿用宿主连接,按应用分别查看授权。";COPY.en.cl1Page22="Signing in does not supply model credentials. Use host connections and review authorization for each app.";
|
|
636
|
+
COPY.zh.cl1Page23="对应页面暂不可用,请确认 HanaMesh Core 已启用。";COPY.en.cl1Page23="This page is unavailable. Check that HanaMesh Core is enabled.";
|
|
637
|
+
COPY.zh.cl1Page24="目录来源";COPY.en.cl1Page24="Catalog sources";
|
|
638
|
+
COPY.zh.cl1Page25="展开后读取当前设置;不会自动保存或安装。";COPY.en.cl1Page25="Expand to read the current settings. Nothing is saved or installed automatically.";
|
|
639
|
+
COPY.zh.cl1Extra0="HanaMesh / 应用库";COPY.en.cl1Extra0="HanaMesh / Library";
|
|
640
|
+
COPY.zh.cl1Extra1="好工具,让想法走得更远。";COPY.en.cl1Extra1="Good tools take your ideas further.";
|
|
641
|
+
COPY.zh.cl1Extra2="安装之前,先看清楚。";COPY.en.cl1Extra2="Review before you install.";
|
|
642
|
+
COPY.zh.cl1Extra3="精确版本";COPY.en.cl1Extra3="Exact version";
|
|
643
|
+
COPY.zh.cl1Extra4="应用筛选";COPY.en.cl1Extra4="App filter";
|
|
644
|
+
COPY.zh.cl1Extra5="全部应用";COPY.en.cl1Extra5="All apps";
|
|
645
|
+
COPY.zh.cl1Extra6="还没有已安装项。";COPY.en.cl1Extra6="No installed items yet.";
|
|
646
|
+
COPY.zh.cl1Extra7="没有找到符合条件的应用。";COPY.en.cl1Extra7="No apps match these filters.";
|
|
612
647
|
const COPY_KEYS=new Map(Object.entries(COPY.zh).map(([key,text])=>[text,key]));
|
|
613
648
|
let localeService=null;
|
|
614
649
|
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];}
|
|
@@ -649,6 +684,8 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
649
684
|
h('details',null,h('summary',null,t('技术详情')),h('p',null,t('应用启动时按当前配置与应用声明匹配供应商并注入;这里只选择模型或撤回、恢复该连接的授权,不改变来源开关。'))),
|
|
650
685
|
routeRows.length?h('table',{className:'hm-provider-records'},h('thead',null,h('tr',null,...[t('应用'),t('用途'),t('供应商'),t('模型'),t('状态'),''].map((label,index)=>h('th',{key:index},label)))),h('tbody',null,...routeRows)):h('p',{className:'hm-provider-hint'},t('尚无需要模型服务的已安装应用。')));
|
|
651
686
|
}
|
|
687
|
+
let pageLayout=null;
|
|
688
|
+
const showLibrary=()=>{if(pageLayout){pageLayout.selectPanel('hanamesh-library');setLibraryVisible(false);}else setLibraryVisible(true);};
|
|
652
689
|
let libraryVisible=false;const libraryListeners=new Set();
|
|
653
690
|
const setLibraryVisible=value=>{libraryVisible=value;for(const listener of libraryListeners)listener(value);};
|
|
654
691
|
let targetSelection=null,targetSequence=0,pendingOperations={};
|
|
@@ -661,7 +698,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
661
698
|
const setPending=update=>{pendingOperations=typeof update==='function'?update(pendingOperations):update;for(const listener of pendingListeners)listener(pendingOperations);};
|
|
662
699
|
/** Public client entry: identifiers only; the market fetches its own catalog and owns confirmation. */
|
|
663
700
|
async function openInstallTarget(input,{handoffId}={}){
|
|
664
|
-
const sequence=++targetSequence;if(entryVisible)
|
|
701
|
+
const sequence=++targetSequence;if(entryVisible)showLibrary();
|
|
665
702
|
try{
|
|
666
703
|
if(!input||typeof input!=='object'||Array.isArray(input))throw new Error('INVALID_INPUT');
|
|
667
704
|
// rc.8: optional contract declaration; absent keeps v1 semantics, an unsupported version is refused before any request.
|
|
@@ -709,7 +746,7 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
709
746
|
function consumeInstallTargetHash(){
|
|
710
747
|
const hash=globalThis.location?.hash;if(!hash?.startsWith(INSTALL_TARGET_HASH))return;
|
|
711
748
|
const params=new URLSearchParams(hash.slice(INSTALL_TARGET_HASH.length));
|
|
712
|
-
if(new Set(params.keys()).size!==[...params.keys()].length){targetSequence++;if(entryVisible)
|
|
749
|
+
if(new Set(params.keys()).size!==[...params.keys()].length){targetSequence++;if(entryVisible)showLibrary();setTarget({status:'failed',error:'INVALID_INPUT'});return;}
|
|
713
750
|
const input=Object.fromEntries(params);
|
|
714
751
|
if(input.installTarget!==undefined){try{input.installTarget=JSON.parse(input.installTarget);}catch{setTarget({status:'failed',error:'INVALID_INPUT'});return;}}
|
|
715
752
|
void openInstallTarget(input).catch(()=>{});
|
|
@@ -739,8 +776,8 @@ window.__ModuleLoader__.load({id:'@hanamesh/dsh-app-host',factory:function(requi
|
|
|
739
776
|
function LibraryAction(){useLocale();
|
|
740
777
|
const[shown,setShown]=React.useState(entryVisible);
|
|
741
778
|
React.useEffect(()=>{entryListeners.add(setShown);return()=>entryListeners.delete(setShown);},[]);
|
|
742
|
-
if(!shown)return null;
|
|
743
|
-
return h('button',{type:'button',className:'hm-library-action',onClick:()=>
|
|
779
|
+
if(!shown||pageLayout)return null;
|
|
780
|
+
return h('button',{type:'button',className:'hm-library-action',onClick:()=>showLibrary()},t('市场'));
|
|
744
781
|
}
|
|
745
782
|
function LibrarySourcesSection(){useLocale();
|
|
746
783
|
const[sources,setSources]=React.useState([]),[draft,setDraft]=React.useState(''),[error,setError]=React.useState('');
|
|
@@ -900,8 +937,12 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
900
937
|
{method:'POST',path:'/apps/heartbeat',sample:{viewId:'verification-view',leaseToken:''}},
|
|
901
938
|
{method:'POST',path:'/apps/close',sample:{viewId:'verification-view',leaseToken:''}},
|
|
902
939
|
];
|
|
903
|
-
|
|
940
|
+
Object.assign(COPY.zh,{cl1Detail:'HanaMesh / 应用详情',cred0:'暂无',cred1:'当前暂无数据',cred2:'公开统计',cred3:'DSH 安装 / 30 天',cred4:'使用人数 / 30 天',cred5:'信号更新:',cred6:'使用人数更新:'});
|
|
941
|
+
Object.assign(COPY.en,{cl1Detail:'HanaMesh / Application details',cred0:'Not available',cred1:'No data available',cred2:'Public statistics',cred3:'DSH installs / 30 days',cred4:'Users / 30 days',cred5:'Signals updated: ',cred6:'Users updated: '});
|
|
942
|
+
function LibraryOverlay({embedded,mainPage=false,preferredSubsectionId,verification=false}={}){useLocale();
|
|
904
943
|
const[visible,setVisible]=React.useState(embedded?true:libraryVisible),[snapshot,setSnapshot]=React.useState(null),[error,setError]=React.useState(''),[receipt,setReceipt]=React.useState(null),[query,setQuery]=React.useState(''),[filter,setFilter]=React.useState(''),[extra,setExtra]=React.useState([]),[pending,updatePending]=React.useState(pendingOperations),[seenCategories,setSeenCategories]=React.useState([]),[changed,setChanged]=React.useState(false),[openingAppId,setOpeningAppId]=React.useState(null),[closing,setClosing]=React.useState(false);
|
|
944
|
+
const[detailId,setDetailId]=React.useState(null),[acceptedTarget,setAcceptedTarget]=React.useState(null),[libraryTab,setLibraryTab]=React.useState('all'),[credibility,setCredibility]=React.useState(null);
|
|
945
|
+
React.useEffect(()=>{let live=true;setCredibility(null);if(detailId&&visible)void readCredibility(snapshot?.source,{id:detailId}).then(value=>{if(live)setCredibility(value);});return()=>{live=false;};},[detailId,visible,snapshot?.source?.manifestUrl]);
|
|
905
946
|
const[target,updateTarget]=React.useState(targetSelection),[targetItemId,setTargetItemId]=React.useState(''),[targetPackageName,setTargetPackageName]=React.useState('');
|
|
906
947
|
const[verificationCall,setVerificationCall]=React.useState('GET /hanamesh/library/install-target'),[verificationInput,setVerificationInput]=React.useState('{}'),[verificationOutput,setVerificationOutput]=React.useState(null),[verifying,setVerifying]=React.useState(false);
|
|
907
948
|
const verificationBusy=React.useRef(false);
|
|
@@ -979,7 +1020,7 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
979
1020
|
setPending(p=>({...p,[key]:outcome.ok?(awaitReadback?{label,text:()=>(t(label)+t('读回中…')),busy:true}:{label,text:()=>(liveLoaded?t(label)+t('完成,已生效,可以直接使用')+baselineText(outcome.result):t(label)+t('完成,重启 DSH 后生效'))}):{label,text:()=>(outcome.unknown?t(label)+t('结果不可追溯,请查看已安装列表后再明确操作'):t(label)+t('失败:')+outcome.code+'('+failureReason(outcome.code,outcome.details)+')'+recoveryText(outcome.recovery)+suiteRecoveryText(outcome.details)),failed:true,diagnostic:outcome.details?.diagnostic}}));
|
|
980
1021
|
await load();return outcome;}catch(e){const code=String(e.message??e);setPending(p=>({...p,[key]:{label,text:()=>(t(label)+t('失败:')+code),failed:true}}));return{ok:false,code};}};
|
|
981
1022
|
const confirmTarget=async()=>{
|
|
982
|
-
const selected=targetSelection;if(selected?.status!=='confirmation-required'||pendingOperations[selected.item.id]?.busy)return;
|
|
1023
|
+
const selected=targetSelection;if(selected?.status!=='confirmation-required'||acceptedTarget!==selected||pendingOperations[selected.item.id]?.busy)return;
|
|
983
1024
|
setTarget({...selected,status:'installing'});
|
|
984
1025
|
const suite=selected.item.kind==='suite-upgrade';
|
|
985
1026
|
const reviewed={itemId:selected.item.id,packageName:selected.item.package.name,...(selected.item.installTarget?{installTarget:selected.item.installTarget}:{})};
|
|
@@ -1041,7 +1082,7 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1041
1082
|
const restartRequired=changed||Boolean(snapshot?.restartRequired);
|
|
1042
1083
|
const filters=[...BASE_FILTERS,...seenCategories.filter(c=>c!=='hanamesh-app').map(c=>[c,c])];
|
|
1043
1084
|
const openButton=row=>h('button',{type:'button',disabled:Boolean(openingAppId),onClick:()=>void open(row)},openingAppId===row.appId?t('打开中…'):t('打开'));
|
|
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}:{})};
|
|
1085
|
+
const card=(item,detail=false)=>{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
1086
|
const reviewOrInstall=label=>item.installTarget?openInstallTarget(installBody).catch(()=>{}):operate('/hanamesh/library/install',installBody,item.id,label);
|
|
1046
1087
|
let action=h('span',null,t('仅收录,不可安装')),state=null;
|
|
1047
1088
|
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,20 +1095,25 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1054
1095
|
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('卸载'));
|
|
1055
1096
|
else if(row?.state==='uninstalled-not-unloaded')action=h('span',null,t('已卸载,重启 DSH 后生效'));
|
|
1056
1097
|
else if(row)action=h('span',null,t('已安装,重启 DSH 后生效'));
|
|
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),
|
|
1098
|
+
return h('article',{key:item.id,'data-hanamesh-library-item':item.id,'data-hanamesh-kind':item.kind,className:detail?'hm-app-detail':'hm-app-card'},detail&&mainPage?null:h('h3',null,item.displayName),detail&&mainPage?null:h('p',null,item.summary),
|
|
1099
|
+
detail?h('div',{className:'hm-app-detail-content'},h('h4',null,t('关于这个应用')),h('p',null,item.description||item.summary),h('h4',null,t('可信度')),h('div',{className:'hm-credibility'},...credibilityFacts(credibility?.itemId===item.id?credibility:null).map(row=>h('div',{key:row.id},h('span',null,t(row.label)),h('strong',{'data-hanamesh-credibility':row.id},row.value===null?t('暂无'):row.value.toLocaleString()),h('small',null,row.value===null?t('当前暂无数据'):t('公开统计'))))),h('p',{className:'hm-market-state'},t('可信度数据缺失不代表 0;本机安装状态与平台采用度分别显示。')),credibility?.checkedAt?h('small',null,t('信号更新:')+credibility.checkedAt):null,credibility?.asOf?h('small',null,t('使用人数更新:')+credibility.asOf):null,h('h4',null,t('来源与安装目标')),h('p',null,item.package?.name??t('仅收录,不可安装')),item.installTarget?h('code',null,item.installTarget.source==='github'?'https://github.com/'+item.installTarget.repo+' @ '+item.installTarget.ref:item.installTarget.name+' @ '+item.installTarget.version):null,...(item.source?.sourceLinks??[]).map((link,index)=>h('p',{key:index},h('a',{href:link.sourceUrl,target:'_blank',rel:'noopener noreferrer'},link.sourceId+' · '+link.sourceRef))),catalogWebsiteLink(snapshot?.source,item)?h('a',{href:catalogWebsiteLink(snapshot?.source,item),target:'_blank',rel:'noopener noreferrer',className:'hm-website-link'},t('在网站查看')):null):null,
|
|
1058
1100
|
h('small',null,t(KIND_TEXT[item.kind])+' · '+(item.publisher?.name??t('未知发布者'))+((item.categories??[]).length?' · '+item.categories.join('、'):'')),
|
|
1059
|
-
state,action,op&&!busy?operationNotice(op):null);};
|
|
1101
|
+
state,h('div',{className:'hm-market-actions'},action,!detail?h('button',{type:'button',onClick:()=>setDetailId(item.id)},t('详情')):null),op&&!busy?operationNotice(op):null);};
|
|
1102
|
+
const detailItem=items.find(item=>item.id===detailId);
|
|
1060
1103
|
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'})):
|
|
1061
|
-
h('div',{className:'hm-library-grid',key:'catalog'},...items.map(card));
|
|
1062
|
-
const moreButton=nextCursor&&!receipt?h('button',{type:'button',className:'hm-library-more',key:'more',onClick:()=>void more()},t('更多')):null;
|
|
1063
|
-
const installedSection=!receipt&&(installed.length||plugins.length)?h('section',{className:'hm-market-installed',key:'installed'},h('h2',null,t('已安装')),h('ul',null,
|
|
1064
|
-
...installed.map(row=>h('li',{key:'app:'+row.packageName,'data-hanamesh-installed':row.packageName},t('应用 · ')+(row.name??row.packageName)+' · '+row.packageName+' '+(row.version??'')+' · '+(t(STATE_TEXT[row.state]??row.state)))),
|
|
1104
|
+
detailItem?h('div',{key:'detail'},h('button',{type:'button',onClick:()=>setDetailId(null)},t('返回应用库')),card(detailItem,true)):h('div',{className:'hm-library-grid',key:'catalog'},...items.map(item=>card(item)),snapshot&&items.length===0?h('p',{role:'status'},t('没有找到符合条件的应用。')):null);
|
|
1105
|
+
const moreButton=nextCursor&&!receipt&&!detailItem?h('button',{type:'button',className:'hm-library-more',key:'more',onClick:()=>void more()},t('更多')):null;
|
|
1106
|
+
const installedSection=!receipt&&!detailItem&&(installed.length||plugins.length)?h('section',{className:'hm-market-installed',key:'installed'},h('h2',null,t('已安装')),h('ul',null,
|
|
1107
|
+
...installed.map(row=>h('li',{key:'app:'+row.packageName,'data-hanamesh-installed':row.packageName},t('应用 · ')+(row.name??row.packageName)+' · '+row.packageName+' '+(row.version??'')+' · '+(t(STATE_TEXT[row.state]??row.state)),row.state==='registered'?openButton(row):null)),
|
|
1065
1108
|
...plugins.filter(row=>!PROTECTED.has(row.packageName)).map(row=>h('li',{key:'plugin:'+row.packageName,'data-hanamesh-installed':row.packageName},t('插件 · ')+row.packageName+' '+(row.version??'')+' · '+(t(STATE_TEXT[row.state]??row.state))+(row.bundle&&!row.active&&row.state==='installed'?t('(未启用为 profile 层)'):''),
|
|
1066
1109
|
row.state==='installed'&&!PROTECTED.has(row.packageName)&&!pending['plugin:'+row.packageName]?h('button',{type:'button',onClick:()=>void operate('/hanamesh/library/plugins/uninstall',{packageName:row.packageName},'plugin:'+row.packageName,t('卸载'))},t('卸载')):pending['plugin:'+row.packageName]?operationNotice(pending['plugin:'+row.packageName]):null)))):null;
|
|
1067
1110
|
// The seat owner may ask for a subsection to come first; `installed` is the only one it names today.
|
|
1068
|
-
const body=preferredSubsectionId==='installed'?[installedSection,catalogSection,moreButton]:[catalogSection,moreButton,installedSection];
|
|
1069
|
-
|
|
1070
|
-
|
|
1111
|
+
const body=mainPage?(libraryTab==='installed'?[installedSection??h('p',{role:'status'},t('还没有已安装项。'))]:[catalogSection,moreButton]):preferredSubsectionId==='installed'?[installedSection,catalogSection,moreButton]:[catalogSection,moreButton,installedSection];
|
|
1112
|
+
const reviewing=mainPage&&target!==null,detailing=mainPage&&Boolean(detailItem)&&!reviewing;
|
|
1113
|
+
return h('section',{className:(embedded?'hm-market hm-market-embedded':'hm-library-overlay hm-market')+(mainPage?' hm-apphost-page':'')},
|
|
1114
|
+
mainPage?h('div',{className:'hm-apphost-breadcrumb'},t(detailing?'HanaMesh / 应用详情':'HanaMesh / 应用库')):null,
|
|
1115
|
+
h('header',null,h('div',null,mainPage?h('div',{className:'hm-apphost-eyebrow'},reviewing?'APPHOST / INSTALL':detailing?'APPLICATION / DETAIL':'APPHOST / LIBRARY'):null,h('h1',null,mainPage?(detailing?detailItem.displayName:t(reviewing?'安装之前,先看清楚。':'好工具,让想法走得更远。')):t('应用库'))),mainPage?h('button',{type:'button',onClick:()=>{try{pageLayout.selectPanel('hanamesh-environment');}catch{setError(new Error('CORE_PAGE_UNAVAILABLE'));}}},t('环境与来源')):embedded?null:h('button',{type:'button',onClick:()=>setLibraryVisible(false)},t('关闭'))),
|
|
1116
|
+
mainPage?h('p',null,detailing?detailItem.summary:t('发现适合你的工具,查看来源后再安装;账号与模型授权分别管理。')):null,
|
|
1071
1117
|
h(MarketConflictNotice,null),h(HandoffIssueNotice,null),
|
|
1072
1118
|
snapshot?.restartBaseline?.known===false?h('p',{role:'alert',className:'hm-library-failed'},t('启动时没能读取 profile(')+snapshot.restartBaseline.code+t('),「需重启」状态无法判断,下面的状态都按已加载显示')):null,
|
|
1073
1119
|
verification===true?h('section',{className:'hm-install-target','aria-label':t('安装目标开发小界面')},h('h2',null,t('安装目标')),
|
|
@@ -1075,14 +1121,15 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1075
1121
|
h('form',{onSubmit:event=>{event.preventDefault();void openInstallTarget({...(targetItemId.trim()?{itemId:targetItemId.trim()}:{}),...(targetPackageName.trim()?{packageName:targetPackageName.trim()}:{} )}).catch(()=>{});}},
|
|
1076
1122
|
h('input',{'aria-label':t('目录条目 ID'),value:targetItemId,placeholder:t('itemId(可选)'),onChange:event=>setTargetItemId(event.target.value)}),
|
|
1077
1123
|
h('input',{'aria-label':t('包名'),value:targetPackageName,placeholder:t('packageName(可选)'),onChange:event=>setTargetPackageName(event.target.value)}),h('button',{type:'submit'},t('查看安装目标')))):null,
|
|
1078
|
-
target?h('div',{role:target.status==='confirmation-required'?'dialog':'status','aria-label':t('市场安装确认')},
|
|
1124
|
+
target?h('div',{role:target.status==='confirmation-required'?'dialog':'status','aria-label':t('市场安装确认'),className:'hm-install-target hm-install-review'},h('h2',null,t('安装确认')),
|
|
1079
1125
|
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,
|
|
1126
|
+
target.item?.installTarget?.source==='npm'?h('dl',{'data-npm-confirmation':true},h('dt',null,t('精确版本')),h('dd',null,target.item.installTarget.version)):null,
|
|
1080
1127
|
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
1128
|
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,
|
|
1082
1129
|
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,
|
|
1083
1130
|
target.item?.suiteUpgrade?.registry?h('p',null,'Registry:'+target.item.suiteUpgrade.registry):null,
|
|
1084
1131
|
...(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:''))),
|
|
1085
|
-
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('取消'))):
|
|
1132
|
+
target.status==='confirmation-required'?h('div',null,h('label',{className:'hm-install-ack'},h('input',{type:'checkbox','aria-label':t('我已核对来源与安装目标'),checked:acceptedTarget===target,onChange:event=>setAcceptedTarget(event.currentTarget.checked?target:null)}),t('我已核对来源与安装目标')),h('button',{type:'button',disabled:acceptedTarget!==target,onClick:()=>void confirmTarget()},t('确认安装')),h('button',{type:'button',onClick:()=>{targetSequence++;void reportHandoff(targetSelection?.handoffId,'cancelled');setTarget({...targetSelection,status:'cancelled'});}},t('取消'))):
|
|
1086
1133
|
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]),
|
|
1087
1134
|
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,
|
|
1088
1135
|
target.item?operationNotice(pending[target.item.id]):null,
|
|
@@ -1093,11 +1140,13 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1093
1140
|
h('textarea',{'aria-label':t('合约样例输入'),value:verificationInput,onChange:event=>setVerificationInput(event.target.value)}),
|
|
1094
1141
|
h('button',{type:'button',disabled:verifying,onClick:()=>void verify()},t('调用合约')),
|
|
1095
1142
|
h('pre',{'aria-label':t('合约调用输出')},verificationOutput===null?t('尚未调用'):JSON.stringify(verificationOutput,null,2))):null,
|
|
1096
|
-
h('div',{className:'hm-library-toolbar'},h('input',{type:'search',placeholder:t('搜索应用与插件'),value:query,onChange:e=>setQuery(e.target.value),onKeyDown:e=>{if(e.key==='Enter')void load();}}),h('button',{type:'button',onClick:()=>void load()},t('搜索')),
|
|
1143
|
+
reviewing||detailing?null:h('div',{className:'hm-library-toolbar'},h('input',{type:'search',placeholder:t('搜索应用与插件'),value:query,onChange:e=>setQuery(e.target.value),onKeyDown:e=>{if(e.key==='Enter')void load();}}),h('button',{type:'button',onClick:()=>void load()},t('搜索')),
|
|
1097
1144
|
h('select',{'aria-label':t('类别'),value:filter,onChange:e=>setFilter(e.target.value)},...filters.map(([value,label])=>h('option',{key:value||'all',value},t(label))))),
|
|
1145
|
+
mainPage&&!reviewing&&!detailing?h('div',{role:'tablist','aria-label':t('应用筛选'),className:'hm-library-tabs'},...[["all","全部应用"],["installed","已安装"]].map(([value,label])=>h('button',{type:'button',role:'tab',key:value,'aria-selected':libraryTab===value,onClick:()=>{setLibraryTab(value);setDetailId(null);}},t(label)))):null,
|
|
1146
|
+
reviewing&&target.status!=='confirmation-required'&&target.status!=='installing'?h('button',{type:'button',onClick:()=>setTarget(null)},t('返回应用库')):null,
|
|
1098
1147
|
restartRequired?h(RestartNotice,null):null,
|
|
1099
1148
|
error?FailureNotice({error}):null,
|
|
1100
|
-
...body);
|
|
1149
|
+
...(reviewing?[]:body),mainPage?h('footer',null,'HanaMesh · Let every use bloom.'):null);
|
|
1101
1150
|
}
|
|
1102
1151
|
/** The `market` seat object read by the shell's Extension Management panel. */
|
|
1103
1152
|
function createMarketSeat({verification=false}={}){
|
|
@@ -1132,11 +1181,57 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1132
1181
|
})();
|
|
1133
1182
|
return()=>{released=true;setMarketConflict('');setEntryVisible(true);dispose?.();};
|
|
1134
1183
|
}
|
|
1184
|
+
// These four counts are not present in the current catalog-view contract.
|
|
1185
|
+
// Never substitute local package state, publisher badges or guessed zeroes.
|
|
1186
|
+
// WX11/12: the existing Web detail projects Host 0.6.54+ githubStars as stars.
|
|
1187
|
+
// The incremental signals feed is a server ingestion API, never a browser scan.
|
|
1188
|
+
const credibilityCount=value=>Number.isSafeInteger(value)&&value>=0?value:null;
|
|
1189
|
+
const credibilityTime=value=>typeof value==='string'&&Number.isFinite(Date.parse(value))?value:null;
|
|
1190
|
+
function credibilityFacts(facts){return[
|
|
1191
|
+
{id:'stars',label:'GitHub 星数',value:credibilityCount(facts?.signals?.stars)},
|
|
1192
|
+
{id:'npm30',label:'npm 下载 / 30 天',value:credibilityCount(facts?.signals?.npmDownloads30d)},
|
|
1193
|
+
{id:'installs',label:'DSH 安装 / 30 天',value:credibilityCount(facts?.signals?.storeInstalls30d)},
|
|
1194
|
+
{id:'users',label:'使用人数 / 30 天',value:credibilityCount(facts?.popularity?.users30d)}
|
|
1195
|
+
].map(row=>({...row,reason:row.value===null?'catalog-field-unavailable':null}));}
|
|
1196
|
+
async function readCredibility(source,item,fetcher=globalThis.fetch){
|
|
1197
|
+
const link=catalogWebsiteLink(source,item),empty={itemId:item?.id,signals:null,popularity:null,checkedAt:null,asOf:null};
|
|
1198
|
+
if(!link||typeof fetcher!=='function')return empty;
|
|
1199
|
+
const origin=new URL(link).origin,id=encodeURIComponent(item.id),controller=new AbortController(),timer=setTimeout(()=>controller.abort(),8000);
|
|
1200
|
+
const read=async path=>{const response=await fetcher(origin+path,{method:'GET',credentials:'omit',redirect:'error',cache:'no-store',signal:controller.signal,headers:{accept:'application/json'}});if(!response.ok)throw Error('CREDIBILITY_UNAVAILABLE');const value=await response.json();if(value?.hanaId!==item.id)throw Error('CREDIBILITY_ID_MISMATCH');return value;};
|
|
1201
|
+
try{const [detail,popularity]=await Promise.allSettled([read('/api/v2/hanas/'+id),read('/hm/v1/custody/hanas/'+id+'/popularity')]);
|
|
1202
|
+
const signals=detail.status==='fulfilled'?detail.value.signals:null,pop=popularity.status==='fulfilled'?popularity.value:null;
|
|
1203
|
+
return {...empty,signals,popularity:pop,checkedAt:credibilityTime(signals?.checkedAt),asOf:credibilityTime(pop?.asOf)};
|
|
1204
|
+
}finally{clearTimeout(timer);}
|
|
1205
|
+
}
|
|
1206
|
+
function catalogWebsiteLink(source,item){
|
|
1207
|
+
if(source?.kind==='fixture'||typeof source?.manifestUrl!=='string'||typeof item?.id!=='string')return null;
|
|
1208
|
+
try{const url=new URL(source.manifestUrl);if(url.pathname!=='/catalog-source.json'||url.searchParams.get('view')!=='hanamesh')return null;return new URL('/hana/'+encodeURIComponent(item.id),url.origin).href;}catch{return null;}
|
|
1209
|
+
}
|
|
1210
|
+
function ConnectionTabs({selected,navigate}){return h('nav',{className:'hm-connection-tabs','aria-label':t('设置与连接')},...[["hanamesh-account","账号与设备"],["hanamesh-providers","模型连接"],["hanamesh-environment","环境与来源"]].map(([id,label])=>h('button',{type:'button',key:id,'aria-current':id===selected?'page':undefined,onClick:()=>navigate(id)},t(label))));}
|
|
1211
|
+
function ProvidersPage({navigate}){useLocale();const[error,setError]=React.useState(false);const go=id=>{try{navigate(id);setError(false);}catch{setError(true);}};return h('div',{className:'hm-apphost-page'},h('div',{className:'hm-apphost-breadcrumb'},t('HanaMesh / 模型连接')),h('header',null,h('div',{className:'hm-apphost-eyebrow'},'MODELS / PROVIDERS'),h('h1',null,t('连接模型,保持掌控。')),h('p',null,t('登录账号不提供模型凭据。沿用宿主连接,按应用分别查看授权。'))),h(ConnectionTabs,{selected:'hanamesh-providers',navigate:go}),error?h('p',{role:'alert'},t('对应页面暂不可用,请确认 HanaMesh Core 已启用。')):null,h('div',{className:'hm-apphost-card'},h(ProvidersSection)),h('footer',null,'HanaMesh · Let every use bloom.'));}
|
|
1212
|
+
function EnvironmentContent(){useLocale();const[expanded,setExpanded]=React.useState({});return h('div',{className:'hm-apphost-environment'},h('section',{className:'hm-apphost-card'},h(NodeRuntimeSection)),...[["sources","目录来源",LibrarySourcesSection],["suite","套件安装包来源",SuiteSourceSettingsSection],["handoff","网站安装交接",HandoffSettingsSection]].map(([id,label,Component])=>h('details',{key:id,className:'hm-apphost-card',onToggle:event=>{const open=event.currentTarget.open;setExpanded(previous=>({...previous,[id]:open}));}},h('summary',null,t(label)),expanded[id]?h(Component):h('p',null,t('展开后读取当前设置;不会自动保存或安装。')))));}
|
|
1213
|
+
function registerAppHostPages(ctx){
|
|
1214
|
+
const previous=pageLayout;pageLayout=ctx.layout;const releases=[];
|
|
1215
|
+
releases.push(ctx.slots.inject('main',()=>ctx.slots.register({name:'main',key:'hanamesh-library'},()=>h(LibraryOverlay,{embedded:true,mainPage:true}))));
|
|
1216
|
+
releases.push(ctx.slots.inject('main',()=>ctx.slots.register({name:'main',key:'hanamesh-providers'},()=>h(ProvidersPage,{navigate:id=>ctx.layout.selectPanel(id)}))));
|
|
1217
|
+
releases.push(ctx.slots.inject('sidebar.panellist',()=>ctx.slots.register({name:'sidebar.panellist',id:'hanamesh-library',order:-20,label:t('应用库')},AppLibraryIcon)));
|
|
1218
|
+
return()=>{for(const dispose of releases.reverse())dispose();if(pageLayout===ctx.layout)pageLayout=previous;};
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function AppLibraryIcon({size=20}){return h('span',{'aria-hidden':true,style:{display:'block',width:size,height:size,background:'currentColor',maskImage:'url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWdyaWQyeDIgbHVjaWRlLWdyaWQtMngyIiBhcmlhLWhpZGRlbj0idHJ1ZSI+PHBhdGggZD0iTTEyIDN2MTgiPjwvcGF0aD48cGF0aCBkPSJNMyAxMmgxOCI+PC9wYXRoPjxyZWN0IHg9IjMiIHk9IjMiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgcng9IjIiPjwvcmVjdD48L3N2Zz4=")',maskSize:'contain',maskRepeat:'no-repeat'}});}
|
|
1222
|
+
|
|
1223
|
+
const appHostPageStyles=`
|
|
1224
|
+
.hm-apphost-page{height:100%;overflow:auto;box-sizing:border-box;padding:36px 38px;max-width:1360px;margin:auto;color:var(--dsw-alias-label-primary,CanvasText);background:var(--dsw-alias-bg-base,Canvas);font:14px/1.55 var(--dsw-font-family,system-ui)}.hm-apphost-page *{box-sizing:border-box}.hm-apphost-page h1{font-size:32px;line-height:1.25;letter-spacing:-.025em;margin:0}.hm-apphost-page h2{font-size:17px}.hm-apphost-page p{color:var(--dsw-alias-label-secondary);line-height:1.7}.hm-apphost-breadcrumb{font-size:12px;color:var(--dsw-alias-label-tertiary);margin-bottom:28px}.hm-apphost-eyebrow{font-size:11px;font-weight:700;letter-spacing:.16em;color:var(--dsw-alias-brand-primary);margin-bottom:10px}.hm-apphost-page>header{margin-bottom:28px}.hm-apphost-page button,.hm-apphost-page select,.hm-apphost-page input{font:inherit;color:inherit;min-height:44px;padding:10px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-3);max-width:100%}.hm-apphost-page button{cursor:pointer}.hm-apphost-page button:disabled{opacity:.5;cursor:default}.hm-apphost-page :focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.hm-connection-tabs{display:flex;gap:8px;flex-wrap:wrap;margin:28px 0 24px}.hm-connection-tabs [aria-current=page]{color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.hm-apphost-card{padding:22px;border:1px solid var(--dsw-alias-border-l1);border-radius:18px;background:var(--dsw-alias-bg-layer-2);min-width:0}.hm-apphost-environment{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px;align-items:start}.hm-apphost-environment>details summary{cursor:pointer;font-weight:600;min-height:28px}.hm-apphost-page .hm-library-grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}.hm-apphost-page .hm-library-grid article{padding:22px;border-radius:18px;background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l1);display:flex;flex-direction:column;gap:16px}.hm-apphost-page .hm-library-grid h3{margin:0;font-size:16px}.hm-apphost-page .hm-market-actions{margin-top:auto}.hm-apphost-page .hm-library-toolbar{gap:12px;margin:24px 0}.hm-apphost-page .hm-app-detail{padding:22px;border:1px solid var(--dsw-alias-border-l1);border-radius:18px;background:var(--dsw-alias-bg-layer-2);margin:20px 0;overflow-wrap:anywhere}.hm-apphost-page .hm-app-detail h3{font-size:28px;margin:0 0 12px}.hm-credibility{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.hm-credibility>div{padding:16px;border:1px solid var(--dsw-alias-border-l1);border-radius:14px;background:var(--dsw-alias-bg-layer-1)}.hm-credibility span,.hm-credibility small{display:block;font-size:12px;color:var(--dsw-alias-label-tertiary)}.hm-credibility strong{display:block;font:26px/1.8 var(--dsh-font-family-code-default,monospace)}.hm-apphost-page .hm-install-review{padding:22px;border-radius:18px;background:var(--dsw-alias-bg-layer-2);margin:24px 0}.hm-install-ack{display:flex;align-items:center;gap:10px;margin:18px 0}.hm-install-ack input{width:20px;min-height:20px;flex:none;accent-color:var(--dsw-alias-brand-primary)}.hm-apphost-page .hm-website-link{display:inline-block;min-height:44px;color:var(--dsw-alias-brand-primary);padding:10px 0}.hm-library-tabs{display:flex;gap:5px;padding:4px;border:1px solid var(--dsw-alias-border-l1);border-radius:11px;width:max-content;margin:20px 0}.hm-library-tabs [aria-selected=true]{background:var(--dsw-alias-bg-layer-3);border-color:var(--dsw-alias-brand-primary)}.hm-apphost-page footer{font-size:11px;color:var(--dsw-alias-label-tertiary);margin-top:26px}
|
|
1225
|
+
@media(max-width:1000px){.hm-apphost-page .hm-library-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:640px){.hm-apphost-page>header{display:block}.hm-apphost-page>header button{margin-top:16px}.hm-apphost-page{padding:24px 18px}.hm-apphost-page h1{font-size:26px}.hm-apphost-page .hm-library-grid,.hm-apphost-environment,.hm-credibility{grid-template-columns:minmax(0,1fr)}.hm-apphost-card{padding:18px}}
|
|
1226
|
+
`;
|
|
1227
|
+
|
|
1135
1228
|
const name='hanamesh-app-host-client',inject=['slots','locale'];
|
|
1136
1229
|
// No cross-plugin reads here: the browser-side cordis context never carries host services such as hanameshCore
|
|
1137
1230
|
// (dsh-client-modules boots its own root context); Core status lives in Core's own Settings section.
|
|
1138
1231
|
function localizedSection(ctx,id,order,label,component){return ctx.slots.inject('settings.section',()=>{let dispose;const refresh=()=>{dispose?.();dispose=ctx.slots.register({name:'settings.section',id,order,label:t(label)},component);};refresh();const unsubscribe=localeService?.subscribe(refresh);return()=>{unsubscribe?.();dispose?.();};});}
|
|
1139
|
-
function apply(ctx,{verification=false}={}){localeService=ctx.locale??null;if(localeService)ctx.effect(()=>localeService.register('hanamesh.apphost',COPY),'hanamesh-app-host:locale');ctx.effect(()=>{const style=document.createElement('style');style.textContent='.hm-node-runtime{display:grid;gap:12px;max-width:900px;color:inherit}.hm-node-fields{display:grid;gap:10px}.hm-node-fields label{display:grid;gap:6px}.hm-node-runtime input,.hm-node-runtime select,.hm-node-runtime button{font:inherit;color:inherit;background:transparent;border:1px solid color-mix(in srgb,currentColor 30%,transparent);border-radius:8px;min-height:44px;padding:8px 12px;box-sizing:border-box;max-width:100%}.hm-node-runtime button{cursor:pointer}.hm-node-runtime button:hover:not(:disabled){background:color-mix(in srgb,currentColor 9%,transparent)}.hm-node-runtime button:focus-visible{outline:2px solid currentColor;outline-offset:2px}.hm-node-runtime button:disabled{opacity:.5;cursor:default}.hm-node-confirm,.hm-node-progress{border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:12px;padding:16px}.hm-node-confirm dl{display:grid;grid-template-columns:100px minmax(0,1fr);gap:8px}.hm-node-runtime dd{margin:0}.hm-node-runtime code,.hm-node-runtime dd{overflow-wrap:anywhere}.hm-node-runtime progress{width:100%}.hm-node-runtime [role=alert]{border-left:3px solid currentColor;padding-left:10px}'+'.hm-providers,.hm-library-sources{display:grid;gap:16px}.hm-providers table{width:100%;border-collapse:collapse}.hm-providers th,.hm-providers td{padding:8px;text-align:left;border-bottom:1px solid color-mix(in srgb,currentColor 14%,transparent)}.hm-provider-card{padding:16px;border:1px solid color-mix(in srgb,currentColor 18%,transparent);border-radius:12px}.hm-provider-row{display:grid;grid-template-columns:minmax(120px,1fr) auto minmax(180px,1fr) auto;gap:8px;align-items:center;margin:8px 0}.hm-source-row{display:grid;grid-template-columns:minmax(0,1fr) repeat(4,auto);gap:8px}.hm-source-row code{overflow-wrap:anywhere}.hm-source-add{display:flex;gap:8px}.hm-source-add input{flex:1}.hm-library-overlay{position:absolute;inset:0;z-index:30;pointer-events:auto;overflow:auto;padding:24px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.hm-library-overlay button,.hm-library-overlay input,.hm-library-overlay select,.hm-market-embedded button,.hm-market-embedded input,.hm-market-embedded select{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.hm-library-overlay>header{display:flex;justify-content:space-between;align-items:center}.hm-library-toolbar{display:flex;gap:8px;align-items:center;margin:8px 0}.hm-library-toolbar input[type=search]{flex:1;padding:6px 10px}.hm-library-more{margin:12px auto;display:block}.hm-library-failed{color:var(--dsw-alias-state-error-primary);margin:0}.hm-library-ok{color:var(--dsw-alias-state-success-primary);margin:0}.hm-restart-notice{padding:10px 12px;border:1px solid var(--dsw-alias-state-warn-primary);border-radius:8px;background:var(--dsw-alias-state-warn-tertiary);margin:8px 0}.hm-restart-link{margin-left:4px;font-weight:600}.hm-market-state{font-size:12px;color:var(--dsw-alias-label-secondary)}.hm-market-actions{display:flex;gap:8px;flex-wrap:wrap}.hm-market-embedded{display:block}.hm-market-embedded>header{display:flex;justify-content:space-between;align-items:center}.hm-market-conflict{padding:10px 12px;border:1px solid var(--dsw-alias-state-business-primary);border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 8%,transparent);margin:8px 0}.hm-install-target{display:grid;gap:8px;padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;margin:12px 0}.hm-install-target form{display:flex;gap:8px;flex-wrap:wrap}.hm-install-target input{flex:1;min-width:180px;padding:6px 10px}.hm-install-target dl{display:grid;grid-template-columns:80px 1fr;gap:6px}.hm-install-target dd{margin:0;overflow-wrap:anywhere}.hm-market-installed{margin-top:24px}.hm-market-installed ul{padding-left:18px;display:grid;gap:6px}.hm-library-toolbar select{padding:6px 10px}.hm-library-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:16px}.hm-library-grid article{display:grid;gap:10px;padding:16px;border:1px solid color-mix(in srgb,currentColor 16%,transparent);border-radius:12px}.hm-app-frame{display:grid;grid-template-rows:auto 1fr;height:calc(100vh - 130px)}.hm-market-embedded>.hm-app-frame{position:fixed;inset:0;z-index:1001;height:100vh;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);padding:12px 16px}.hm-app-frame>div{display:flex;justify-content:space-between}.hm-app-frame iframe{width:100%;height:100%;border:0}';style.textContent+='/* Only AppHost surfaces: never resize the host settings shell. */\n.hm-node-runtime,.hm-library-sources,.hm-providers,.hm-market{min-width:0;width:100%;max-width:100%;box-sizing:border-box;overflow-wrap:anywhere}\n.hm-node-runtime>*,.hm-library-sources>*,.hm-node-fields>*,.hm-handoff-settings>*,.hm-library-toolbar>*{min-width:0;max-width:100%;box-sizing:border-box}\n.hm-library-sources input,.hm-library-sources textarea,.hm-library-sources select,.hm-node-runtime input,.hm-node-runtime select{min-width:0;width:100%;max-width:100%;box-sizing:border-box;font:inherit;color:inherit;background:var(--dsw-alias-bg-layer-2)}\n.hm-library-sources button,.hm-market button{min-height:44px;max-width:100%;white-space:normal;font:inherit;color:inherit;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 12px}\n.hm-library-sources button:focus-visible,.hm-market button:focus-visible{outline:2px solid currentColor;outline-offset:2px}\n.hm-handoff-settings{display:grid;gap:12px}.hm-handoff-settings label{display:grid;gap:6px}.hm-handoff-settings input[type=checkbox]{width:auto}\n.hm-node-confirm,.hm-node-progress{min-width:0;max-width:100%;box-sizing:border-box}\n.hm-failure pre{max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;font-size:12px}.hm-failure summary{cursor:pointer}.hm-failure p{margin:8px 0}\n.hm-library-toolbar,.hm-source-add{flex-wrap:wrap}.hm-library-toolbar input[type=search]{min-width:0;width:100%;flex:1 1 180px}\n.hm-library-grid{grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr))}\n.hm-providers{overflow-x:auto}.hm-source-row{grid-template-columns:minmax(0,1fr);gap:6px}\n@media(max-width:640px){.hm-library-overlay{padding:12px}.hm-node-confirm{padding:10px}.hm-node-confirm dl,.hm-install-target dl{grid-template-columns:minmax(0,1fr)}.hm-node-confirm dt{font-weight:600}.hm-node-confirm dd{margin-bottom:6px}.hm-library-toolbar select{width:100%}}\n';style.textContent+='\n.hm-provider-records td{overflow-wrap:anywhere}.hm-providers select,.hm-providers input{min-width:0;max-width:100%;width:100%;box-sizing:border-box}.hm-provider-records details>summary{cursor:pointer;min-height:44px;display:flex;align-items:center}.hm-provider-records pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:12px}\n@media(max-width:640px){.hm-providers{overflow:visible}.hm-provider-records,.hm-provider-records tbody{display:block}.hm-provider-records thead{display:none}.hm-provider-records tr{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;padding:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;margin:10px 0}.hm-provider-records td{display:block;min-width:0;padding:0;border:0}.hm-provider-records td::before{content:attr(data-label);display:block;font-weight:600;margin-bottom:4px}.hm-provider-records td:empty{display:none}}\n';style.textContent+="\n.hm-providers,.hm-library-sources,.hm-node-runtime{overflow-wrap:normal;word-break:normal}\n.hm-providers h2,.hm-library-sources h2,.hm-node-runtime h2{margin:0;font-weight:600;line-height:1.5}\n.hm-providers p,.hm-library-sources p,.hm-node-runtime p{margin:0;line-height:1.6}\n.hm-suite-fields,.hm-suite-fields>label,.hm-handoff-settings,.hm-source-add{display:grid;grid-template-columns:minmax(0,1fr);gap:10px;min-width:0}\n.hm-suite-fields>*,.hm-source-add>*,.hm-providers>*,.hm-library-sources details,.hm-node-runtime details{min-width:0;max-width:100%;box-sizing:border-box}\n.hm-library-sources input,.hm-library-sources textarea,.hm-library-sources select,.hm-suite-fields select,.hm-providers select,.hm-providers input{display:block;width:100%;min-width:0;max-width:100%;box-sizing:border-box;min-height:44px;padding:8px;font:inherit;border:1px solid var(--dsw-alias-border-l2);border-radius:8px}\n.hm-library-sources input[type=checkbox]{display:inline-block;width:20px;min-height:20px;max-width:20px}\n.hm-library-sources summary,.hm-providers summary,.hm-node-runtime summary{min-height:44px;display:flex;align-items:center;cursor:pointer}\n.hm-library-sources code,.hm-library-sources dd,.hm-providers pre{overflow-wrap:anywhere;white-space:pre-wrap}\n.hm-handoff-settings>button,.hm-suite-fields>button{width:100%}\n@media(max-width:640px){.hm-provider-records tr{padding:8px}.hm-node-fields{grid-template-columns:minmax(0,1fr)}}\n";document.head.append(style);return()=>style.remove();},'hanamesh-app-host:style');
|
|
1232
|
+
function apply(ctx,{verification=false}={}){localeService=ctx.locale??null;if(localeService)ctx.effect(()=>localeService.register('hanamesh.apphost',COPY),'hanamesh-app-host:locale');ctx.effect(()=>{const style=document.createElement('style');style.textContent='.hm-node-runtime{display:grid;gap:12px;max-width:900px;color:inherit}.hm-node-fields{display:grid;gap:10px}.hm-node-fields label{display:grid;gap:6px}.hm-node-runtime input,.hm-node-runtime select,.hm-node-runtime button{font:inherit;color:inherit;background:transparent;border:1px solid color-mix(in srgb,currentColor 30%,transparent);border-radius:8px;min-height:44px;padding:8px 12px;box-sizing:border-box;max-width:100%}.hm-node-runtime button{cursor:pointer}.hm-node-runtime button:hover:not(:disabled){background:color-mix(in srgb,currentColor 9%,transparent)}.hm-node-runtime button:focus-visible{outline:2px solid currentColor;outline-offset:2px}.hm-node-runtime button:disabled{opacity:.5;cursor:default}.hm-node-confirm,.hm-node-progress{border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:12px;padding:16px}.hm-node-confirm dl{display:grid;grid-template-columns:100px minmax(0,1fr);gap:8px}.hm-node-runtime dd{margin:0}.hm-node-runtime code,.hm-node-runtime dd{overflow-wrap:anywhere}.hm-node-runtime progress{width:100%}.hm-node-runtime [role=alert]{border-left:3px solid currentColor;padding-left:10px}'+'.hm-providers,.hm-library-sources{display:grid;gap:16px}.hm-providers table{width:100%;border-collapse:collapse}.hm-providers th,.hm-providers td{padding:8px;text-align:left;border-bottom:1px solid color-mix(in srgb,currentColor 14%,transparent)}.hm-provider-card{padding:16px;border:1px solid color-mix(in srgb,currentColor 18%,transparent);border-radius:12px}.hm-provider-row{display:grid;grid-template-columns:minmax(120px,1fr) auto minmax(180px,1fr) auto;gap:8px;align-items:center;margin:8px 0}.hm-source-row{display:grid;grid-template-columns:minmax(0,1fr) repeat(4,auto);gap:8px}.hm-source-row code{overflow-wrap:anywhere}.hm-source-add{display:flex;gap:8px}.hm-source-add input{flex:1}.hm-library-overlay{position:absolute;inset:0;z-index:30;pointer-events:auto;overflow:auto;padding:24px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.hm-library-overlay button,.hm-library-overlay input,.hm-library-overlay select,.hm-market-embedded button,.hm-market-embedded input,.hm-market-embedded select{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.hm-library-overlay>header{display:flex;justify-content:space-between;align-items:center}.hm-library-toolbar{display:flex;gap:8px;align-items:center;margin:8px 0}.hm-library-toolbar input[type=search]{flex:1;padding:6px 10px}.hm-library-more{margin:12px auto;display:block}.hm-library-failed{color:var(--dsw-alias-state-error-primary);margin:0}.hm-library-ok{color:var(--dsw-alias-state-success-primary);margin:0}.hm-restart-notice{padding:10px 12px;border:1px solid var(--dsw-alias-state-warn-primary);border-radius:8px;background:var(--dsw-alias-state-warn-tertiary);margin:8px 0}.hm-restart-link{margin-left:4px;font-weight:600}.hm-market-state{font-size:12px;color:var(--dsw-alias-label-secondary)}.hm-market-actions{display:flex;gap:8px;flex-wrap:wrap}.hm-market-embedded{display:block}.hm-market-embedded>header{display:flex;justify-content:space-between;align-items:center}.hm-market-conflict{padding:10px 12px;border:1px solid var(--dsw-alias-state-business-primary);border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 8%,transparent);margin:8px 0}.hm-install-target{display:grid;gap:8px;padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;margin:12px 0}.hm-install-target form{display:flex;gap:8px;flex-wrap:wrap}.hm-install-target input{flex:1;min-width:180px;padding:6px 10px}.hm-install-target dl{display:grid;grid-template-columns:80px 1fr;gap:6px}.hm-install-target dd{margin:0;overflow-wrap:anywhere}.hm-market-installed{margin-top:24px}.hm-market-installed ul{padding-left:18px;display:grid;gap:6px}.hm-library-toolbar select{padding:6px 10px}.hm-library-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:16px}.hm-library-grid article{display:grid;gap:10px;padding:16px;border:1px solid color-mix(in srgb,currentColor 16%,transparent);border-radius:12px}.hm-app-frame{display:grid;grid-template-rows:auto 1fr;height:calc(100vh - 130px)}.hm-market-embedded>.hm-app-frame{position:fixed;inset:0;z-index:1001;height:100vh;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);padding:12px 16px}.hm-app-frame>div{display:flex;justify-content:space-between}.hm-app-frame iframe{width:100%;height:100%;border:0}';style.textContent+='/* Only AppHost surfaces: never resize the host settings shell. */\n.hm-node-runtime,.hm-library-sources,.hm-providers,.hm-market{min-width:0;width:100%;max-width:100%;box-sizing:border-box;overflow-wrap:anywhere}\n.hm-node-runtime>*,.hm-library-sources>*,.hm-node-fields>*,.hm-handoff-settings>*,.hm-library-toolbar>*{min-width:0;max-width:100%;box-sizing:border-box}\n.hm-library-sources input,.hm-library-sources textarea,.hm-library-sources select,.hm-node-runtime input,.hm-node-runtime select{min-width:0;width:100%;max-width:100%;box-sizing:border-box;font:inherit;color:inherit;background:var(--dsw-alias-bg-layer-2)}\n.hm-library-sources button,.hm-market button{min-height:44px;max-width:100%;white-space:normal;font:inherit;color:inherit;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 12px}\n.hm-library-sources button:focus-visible,.hm-market button:focus-visible{outline:2px solid currentColor;outline-offset:2px}\n.hm-handoff-settings{display:grid;gap:12px}.hm-handoff-settings label{display:grid;gap:6px}.hm-handoff-settings input[type=checkbox]{width:auto}\n.hm-node-confirm,.hm-node-progress{min-width:0;max-width:100%;box-sizing:border-box}\n.hm-failure pre{max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;font-size:12px}.hm-failure summary{cursor:pointer}.hm-failure p{margin:8px 0}\n.hm-library-toolbar,.hm-source-add{flex-wrap:wrap}.hm-library-toolbar input[type=search]{min-width:0;width:100%;flex:1 1 180px}\n.hm-library-grid{grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr))}\n.hm-providers{overflow-x:auto}.hm-source-row{grid-template-columns:minmax(0,1fr);gap:6px}\n@media(max-width:640px){.hm-library-overlay{padding:12px}.hm-node-confirm{padding:10px}.hm-node-confirm dl,.hm-install-target dl{grid-template-columns:minmax(0,1fr)}.hm-node-confirm dt{font-weight:600}.hm-node-confirm dd{margin-bottom:6px}.hm-library-toolbar select{width:100%}}\n';style.textContent+='\n.hm-provider-records td{overflow-wrap:anywhere}.hm-providers select,.hm-providers input{min-width:0;max-width:100%;width:100%;box-sizing:border-box}.hm-provider-records details>summary{cursor:pointer;min-height:44px;display:flex;align-items:center}.hm-provider-records pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:12px}\n@media(max-width:640px){.hm-providers{overflow:visible}.hm-provider-records,.hm-provider-records tbody{display:block}.hm-provider-records thead{display:none}.hm-provider-records tr{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;padding:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;margin:10px 0}.hm-provider-records td{display:block;min-width:0;padding:0;border:0}.hm-provider-records td::before{content:attr(data-label);display:block;font-weight:600;margin-bottom:4px}.hm-provider-records td:empty{display:none}}\n';style.textContent+="\n.hm-providers,.hm-library-sources,.hm-node-runtime{overflow-wrap:normal;word-break:normal}\n.hm-providers h2,.hm-library-sources h2,.hm-node-runtime h2{margin:0;font-weight:600;line-height:1.5}\n.hm-providers p,.hm-library-sources p,.hm-node-runtime p{margin:0;line-height:1.6}\n.hm-suite-fields,.hm-suite-fields>label,.hm-handoff-settings,.hm-source-add{display:grid;grid-template-columns:minmax(0,1fr);gap:10px;min-width:0}\n.hm-suite-fields>*,.hm-source-add>*,.hm-providers>*,.hm-library-sources details,.hm-node-runtime details{min-width:0;max-width:100%;box-sizing:border-box}\n.hm-library-sources input,.hm-library-sources textarea,.hm-library-sources select,.hm-suite-fields select,.hm-providers select,.hm-providers input{display:block;width:100%;min-width:0;max-width:100%;box-sizing:border-box;min-height:44px;padding:8px;font:inherit;border:1px solid var(--dsw-alias-border-l2);border-radius:8px}\n.hm-library-sources input[type=checkbox]{display:inline-block;width:20px;min-height:20px;max-width:20px}\n.hm-library-sources summary,.hm-providers summary,.hm-node-runtime summary{min-height:44px;display:flex;align-items:center;cursor:pointer}\n.hm-library-sources code,.hm-library-sources dd,.hm-providers pre{overflow-wrap:anywhere;white-space:pre-wrap}\n.hm-handoff-settings>button,.hm-suite-fields>button{width:100%}\n@media(max-width:640px){.hm-provider-records tr{padding:8px}.hm-node-fields{grid-template-columns:minmax(0,1fr)}}\n";style.textContent+=appHostPageStyles;document.head.append(style);return()=>style.remove();},'hanamesh-app-host:style');
|
|
1233
|
+
ctx.inject?.(['layout'],page=>{page.effect(()=>registerAppHostPages(page),'hanamesh-app-host:pages');});
|
|
1234
|
+
ctx.effect(()=>ctx.slots.inject('hanamesh.environment.content',()=>ctx.slots.register({name:'hanamesh.environment.content',id:'apphost',order:10},EnvironmentContent)),'hanamesh-app-host:environment-content');
|
|
1140
1235
|
ctx.effect(()=>localizedSection(ctx,'hanamesh-providers',18,"供应商",ProvidersSection),'hanamesh-app-host:providers');
|
|
1141
1236
|
ctx.effect(()=>localizedSection(ctx,'hanamesh-library-sources',19,"市场目录源",LibrarySourcesSection),'hanamesh-app-host:library-sources');
|
|
1142
1237
|
ctx.effect(()=>localizedSection(ctx,'hanamesh-suite-source',19.5,"套件安装包来源",SuiteSourceSettingsSection),'hanamesh-app-host:suite-source');
|
|
@@ -1148,5 +1243,5 @@ h('div',{className:'hm-source-add'},h('input',{value:draft,placeholder:'https://
|
|
|
1148
1243
|
ctx.effect(()=>{let stopped=false,timer;const tick=async()=>{await pollHandoffsVisibly();if(!stopped)timer=setTimeout(()=>void tick(),handoffPollMs);};void tick();return()=>{stopped=true;clearTimeout(timer);};},'hanamesh-app-host:website-handoff');
|
|
1149
1244
|
ctx.effect(()=>{globalThis.addEventListener?.('hashchange',consumeInstallTargetHash);consumeInstallTargetHash();return()=>globalThis.removeEventListener?.('hashchange',consumeInstallTargetHash);},'hanamesh-app-host:install-target-navigation');}
|
|
1150
1245
|
return{name,inject,apply,ProvidersSection,SuiteSourceSettingsSection,LibrarySourcesSection,HandoffSettingsSection,NodeRuntimeSection,LibraryAction,LibraryOverlay,MarketConflictNotice,createMarketSeat,openInstallTarget,
|
|
1151
|
-
MARKET_SEAT,MARKET_CONFLICT_TEXT,INSTALL_TARGET_HASH,INSTALL_TARGET_CONTRACT_VERSION,marketState:()=>({conflict:marketConflict,entryVisible})};
|
|
1246
|
+
registerAppHostPages,EnvironmentContent,credibilityFacts,readCredibility,catalogWebsiteLink,MARKET_SEAT,MARKET_CONFLICT_TEXT,INSTALL_TARGET_HASH,INSTALL_TARGET_CONTRACT_VERSION,marketState:()=>({conflict:marketConflict,entryVisible})};
|
|
1152
1247
|
}});
|
|
@@ -34,6 +34,8 @@ export async function loadClient({fetch:transport}){
|
|
|
34
34
|
render();await idle();
|
|
35
35
|
return{module,
|
|
36
36
|
text:()=>JSON.stringify(tree),
|
|
37
|
+
find:predicate=>find(tree,predicate),
|
|
38
|
+
async acknowledgeInstall(){const checkbox=find(tree,node=>node.type==='input'&&node.props['aria-label']==='我已核对来源与安装目标');if(!checkbox)throw new Error('Installation review acknowledgement is not visible');checkbox.props.onChange({currentTarget:{checked:true}});await idle();},
|
|
37
39
|
button:label=>find(tree,node=>node.type==='button'&&node.children.includes(label)),
|
|
38
40
|
async click(label){const button=find(tree,node=>node.type==='button'&&node.children.includes(label));if(!button)throw new Error('No visible button '+label);button.props.onClick();await idle();},
|
|
39
41
|
idle,
|
|
@@ -173,7 +173,7 @@ async function runRecoveryProvider(contract,record){
|
|
|
173
173
|
await record(id,'recovery','market shows '+caseId+' as '+(id==='RU01'?'a failure that was restored':'a failure whose restoration failed, never as installed or rolled back'),async()=>{
|
|
174
174
|
const item=recovery.cases.find(row=>row.id===caseId),source=await sourceRecoveryProfile(contract,item);
|
|
175
175
|
const host=await startProvider(contract,{profile:source.profile,installer:source.installer});const client=await loadClient({fetch:host.browserFetch});
|
|
176
|
-
try{await client.module.openInstallTarget({packageName:source.target.packageName});await client.idle();await client.click('确认安装');await host.settled();await client.tick(1000);
|
|
176
|
+
try{await client.module.openInstallTarget({packageName:source.target.packageName});await client.idle();await client.acknowledgeInstall();await client.click('确认安装');await host.settled();await client.tick(1000);
|
|
177
177
|
const text=client.text();
|
|
178
178
|
if(!text.includes('安装失败:'+item.expect.code)||!text.includes(expected))throw new Error('market text: '+text.slice(text.indexOf('安装失败')>=0?text.indexOf('安装失败'):0).slice(0,300));
|
|
179
179
|
if(text.includes(refused)||text.includes('安装完成'))throw new Error('market misreports the recovery result');
|
|
@@ -247,7 +247,7 @@ export async function runProviderSuite(){
|
|
|
247
247
|
await record('PC02','confirm','only an explicit confirmation installs, once, through the existing guarded route',async()=>{
|
|
248
248
|
expectEqual(host.installs.length,0,'installs before confirmation');
|
|
249
249
|
await client.module.openInstallTarget({packageName:'@hanamesh-fixture/install-target-app',contractVersion:'1'});await client.idle();
|
|
250
|
-
const confirm=client.button('确认安装');confirm.props.onClick();confirm.props.onClick();await client.idle();
|
|
250
|
+
await client.acknowledgeInstall();const confirm=client.button('确认安装');confirm.props.onClick();confirm.props.onClick();await client.idle();
|
|
251
251
|
expectEqual(host.posts.map(p=>[p.path,p.headers['x-hanamesh-client']]),[['/hanamesh/library/install','workspace-v1']],'install requests');
|
|
252
252
|
expectEqual(host.installs,['@hanamesh-fixture/install-target-app'],'installer calls');
|
|
253
253
|
});
|
|
@@ -258,7 +258,7 @@ export async function runProviderSuite(){
|
|
|
258
258
|
if(!client.button('确认安装'))throw new Error('localhost fragment did not reach confirmation');
|
|
259
259
|
await client.click('取消');expectEqual([host.posts.length,host.installs.length],[postsBefore,installsBefore],'localhost cancellation');
|
|
260
260
|
await client.module.openInstallTarget({packageName:'@hanamesh-fixture/install-target-plugin',contractVersion:'1'});await client.idle();
|
|
261
|
-
const confirm=client.button('确认安装');confirm.props.onClick();confirm.props.onClick();await client.idle();
|
|
261
|
+
await client.acknowledgeInstall();const confirm=client.button('确认安装');confirm.props.onClick();confirm.props.onClick();await client.idle();
|
|
262
262
|
expectEqual([host.posts.length,host.installs.length],[postsBefore+1,installsBefore+1],'localhost confirmed install once');
|
|
263
263
|
expectEqual(host.installs.at(-1),'@hanamesh-fixture/install-target-plugin','localhost installer target');
|
|
264
264
|
});
|
package/dist/library/catalog.js
CHANGED
|
@@ -12,14 +12,15 @@ const MAX_SOURCE_LINKS=500;
|
|
|
12
12
|
const plain=value=>typeof value==='string'&&value.length>0&&!/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u.test(value);
|
|
13
13
|
const own=(value,keys)=>value&&typeof value==='object'&&!Array.isArray(value)&&Object.keys(value).every(key=>keys.includes(key));
|
|
14
14
|
// WHATWG URL canonicalizes hostnames (including IPv6); no DNS lookup or origin aliasing.
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
const loopback=url=>['127.0.0.1','[::1]','localhost'].includes(url.hostname);
|
|
16
|
+
const catalogOrigin=url=>(url.protocol==='https:'&&(!url.port||loopback(url)||url.hostname.endsWith('.localhost')))||
|
|
17
|
+
(url.protocol==='http:'&&loopback(url));
|
|
17
18
|
|
|
18
19
|
export function validateManifestUrl(value){
|
|
19
20
|
let url;try{url=new URL(value);}catch{throw new AppHostError('INVALID_CATALOG_URL','Catalog manifest URL is invalid.');}
|
|
20
21
|
const viewQuery=!url.search||(url.searchParams.size===1&&url.searchParams.get('view')==='hanamesh');
|
|
21
22
|
requireCondition(catalogOrigin(url)&&!url.username&&!url.password&&viewQuery&&!url.hash,
|
|
22
|
-
'INVALID_CATALOG_URL','Catalog manifests require standard-port HTTPS
|
|
23
|
+
'INVALID_CATALOG_URL','Catalog manifests require standard-port HTTPS, local HTTPS (loopback or *.localhost), or loopback HTTP, with only an optional view=hanamesh query.');
|
|
23
24
|
return url;
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -17,6 +17,11 @@ const unknown=(row,code,message,action)=>({...row,status:'unknown',version:null,
|
|
|
17
17
|
const agentBase=channel=>base(channel,'agent-cli','official-user-profile',channel==='claude'?'Claude Code 用户级插件(不覆盖项目或其他隔离资料)':'Codex CLI 本地市场用户资料(不代表桌面 App、项目或其他隔离资料)');
|
|
18
18
|
const inventoryError=()=>{throw new AppHostError('AGENT_INVENTORY_INVALID','Official inventory shape is unsupported.',{},503)};
|
|
19
19
|
const qualified=x=>typeof x==='string'&&/^[a-z0-9][a-z0-9._-]*@[a-z0-9][a-z0-9._-]*$/.test(x)&&x.length<=257;
|
|
20
|
+
function claudeMarketplaceUrl(value){
|
|
21
|
+
if(value.source==='github'&&typeof value.repo==='string'&&/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(value.repo))return `https://github.com/${value.repo}`;
|
|
22
|
+
const url=['url','git'].includes(value.source)?value.url:null;
|
|
23
|
+
return value.source==='git'&&typeof url==='string'&&/^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\.git$/.test(url)?url.slice(0,-4):url;
|
|
24
|
+
}
|
|
20
25
|
function parseInventory(channel,plugins,marketplaces,target){
|
|
21
26
|
let rows,markets;
|
|
22
27
|
if(channel==='claude'){
|
|
@@ -29,7 +34,7 @@ function parseInventory(channel,plugins,marketplaces,target){
|
|
|
29
34
|
if(!markets.every(r=>object(r)&&typeof r.name==='string'&&r.name.length>0&&r.name.length<=128))inventoryError();
|
|
30
35
|
const sourceRows=markets.filter(r=>r.name===target.marketplace);
|
|
31
36
|
if(sourceRows.length>1)throw new AppHostError('AGENT_INVENTORY_CONFLICT','Conflicting marketplace identities.',{},503);
|
|
32
|
-
if(sourceRows.length){const m=sourceRows[0],url=channel==='claude'?(
|
|
37
|
+
if(sourceRows.length){const m=sourceRows[0],url=channel==='claude'?claudeMarketplaceUrl(m):(['git','url'].includes(m.marketplaceSource?.sourceType)?m.marketplaceSource.source:null);
|
|
33
38
|
if(url!==target.marketplaceUrl)throw new AppHostError('AGENT_MARKETPLACE_SOURCE_MISMATCH','The configured marketplace source is not the registered target.',{},503);
|
|
34
39
|
}
|
|
35
40
|
const id=`${target.pluginName}@${target.marketplace}`;
|
package/docs/CONTRACT.md
CHANGED
|
@@ -227,7 +227,7 @@ Support implementation: macOS13.5+ arm64/x64, known Node24.13.1 or24.22.0 (defau
|
|
|
227
227
|
Storage space budget is archive bytes + twice measured regular-file payload (new tree + staging); never delete another version or unknown files to make space. lib-provision alone owns staging/ledger/manifests; interrupted or cancelled downloads may leave its resumable owned cache. Another attempt requires a new visible confirmation. Existing versions remain until an explicit owned cleanup is designed; no automatic deletion or implied rollback. Offline startup verifies an existing active tree/ledger and standalone executable; failures are visible and never trigger a download.
|
|
228
228
|
|
|
229
229
|
|
|
230
|
-
目录来源 URL 接受标准端口 HTTPS
|
|
230
|
+
目录来源 URL 接受标准端口 HTTPS;HTTPS 本机回环 127.0.0.1、::1、localhost 及 *.localhost 可使用任意端口,另接受本机回环 `127.0.0.1`、`::1`、`localhost` 的任意端口 HTTP。使用 Node `URL` 解析后的主机名精确比较;其它来源保持原规则。凭据、fragment、查询和完整同源校验不变;不增加设置、映射或别名。目录来源自身 attribution 可使用该回环来源,普通条目展示链接仍按原 HTTPS 校验。
|
|
231
231
|
|
|
232
232
|
## B17 套件安装包来源(2026-10-21 候选)
|
|
233
233
|
|
|
@@ -259,3 +259,34 @@ B17 review repair(同0.6.8候选):`AppHost` 未注入 `runtimeLedgerReader
|
|
|
259
259
|
A2 0.6.22:普通插件必须有 Indexer 已审核的 installMethods 和 oneClickInstall.allowed:true;仅执行其 npm 精确版本或完整 GitHub SHA。缺目标具名拒绝,不根据包名查可变版本标签。CLI 使用显式 library.registry(若有),否则保留宿主原生 registry 配置。删除普通插件按包名内部直装方法、元数据查询及其专用设置/规则加载。套件仅透传 Core installCommand。安装失败保留脱敏 CLI/读回诊断及补偿结果;精确版本发布后即可原生验收。
|
|
260
260
|
|
|
261
261
|
A2 0.6.22:升级tuple必须带Core生成的installation(name/version/command/args),name/version与该tuple一致。AppHost传实际profile和可选配置来源;未配置来源由Core显式声明。CLI直接执行args;confirmation同时绑定该定义。installCommand是Core的可空修复展示文本,不解析命令前缀。旧Core缺定义不回退自拼。
|
|
262
|
+
|
|
263
|
+
## CL1 HanaMesh client pages (2026-11-10 candidate)
|
|
264
|
+
|
|
265
|
+
AppHost adds keyed main entries `hanamesh-library` and `hanamesh-providers`. Sidebar list id `hanamesh-library` (order 11, label 应用库) addresses the matching main key. The existing market seat, overlay fallback, website install-target entry, exact install/readback, app receipts, leases and close ownership remain intact; new layout-aware entry actions select the main page without creating a Session. The legacy footer action is hidden when the native main navigation is available.
|
|
266
|
+
|
|
267
|
+
Core declares root-scoped list slot `hanamesh.environment.content` as a child of main key `hanamesh-environment`. AppHost registers its own `EnvironmentContent` there: installation environment and lazily opened catalog/suite-source/handoff forms. Those forms use their original authenticated routes and stores; opening the environment does not read every closed form or save/install anything. Tabs select Core keys `hanamesh-account` / `hanamesh-environment` and AppHost `hanamesh-providers`. No sibling source import, Core allowlist change or host root/sidebar/conversation replacement is involved.
|
|
268
|
+
|
|
269
|
+
The library includes local installed/all tabs and a source-preserving details view. Installation confirmation shows the exact reviewed npm version or full GitHub ref/path/build permission, and requires acknowledgement of the **current resolved target object** before its original confirm action can post. A newly resolved target clears that acknowledgement; server-side fixed-target reread remains authoritative. The shipped conformance harness includes an explicit `acknowledgeInstall()` step before confirmation. Old directory `latestVersion` is still rejected/not displayed.
|
|
270
|
+
|
|
271
|
+
The current catalog-view DTO has no public GitHub stars / npm downloads / platform install people / usage people fields. Details render each as unavailable with a reason, never as zero or a local-inventory substitute. The website SearchSignals DTO is a different contract, and store installation次数 is not 人数. Supplying these figures needs a formally added catalog-view DTO; this candidate does not relax validation or perform request-time GitHub/npm calls. A “在网站查看” link is derived only from the reviewed HanaMesh-view catalog provider; fixture/other-provider routes are not guessed. No trading or asset UI is added to the client.
|
|
272
|
+
|
|
273
|
+
Scoped page styles consume the same host theme tokens. The library glyph reuses the supplied DS1 asset. Source/fixture checks do not establish real DSH loading or design screenshot acceptance; those remain separate CL1 gates.
|
|
274
|
+
|
|
275
|
+
### CL1 existing public credibility reads (2026-11-10)
|
|
276
|
+
|
|
277
|
+
On detail open only, the client uses the reviewed HanaMesh catalog origin's existing
|
|
278
|
+
`GET /api/v2/hanas/:id` and `GET /hm/v1/custody/hanas/:id/popularity` public reads.
|
|
279
|
+
The first is WX11/WX12's projection of Host 0.6.54+ `/v1/indexer/signals/changes`:
|
|
280
|
+
`githubStars` becomes `signals.stars`, with `npmDownloads30d`, nullable
|
|
281
|
+
`storeInstalls30d` and `checkedAt`. The second supplies `users30d` and its own
|
|
282
|
+
`asOf`. DSH installs are 30-day counts, never unique installation people; neither
|
|
283
|
+
npm downloads nor `installCount` is substituted. All missing/invalid/error values
|
|
284
|
+
show “暂无”; real zero stays zero, and timestamps remain separate.
|
|
285
|
+
|
|
286
|
+
No new backend, signal-feed consumption, source scraping, polling or catalog DTO
|
|
287
|
+
extension. Both requests omit credentials, refuse redirects and time out after
|
|
288
|
+
8 seconds; identity must match the selected item. Source routes are derived only
|
|
289
|
+
for the reviewed `/catalog-source.json?view=hanamesh` provider. Other catalog
|
|
290
|
+
providers and unavailable/CORS-denied public reads retain “暂无”. The source's
|
|
291
|
+
browser access rules are respected; there is no proxy/CORS bypass. Closing or
|
|
292
|
+
switching details ignores stale replies.
|
|
@@ -107,3 +107,9 @@ Official command references: [Claude Code plugin commands](https://code.claude.c
|
|
|
107
107
|
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.
|
|
108
108
|
|
|
109
109
|
R115 regression fixtures execute real non-TTY Bash, asdf 0.20.2 official shim and mise 2026.11.4 with default/custom/shell-defined global XDG selection. Tool provenance, hashes and the explicit test-only binary inputs are in source `tests/fixtures/installation-managers/README.md`; binaries do not enter the npm package.
|
|
110
|
+
|
|
111
|
+
0.6.25:Claude 官方市场清单的 `source: "github"` 使用 `repo` 的 owner/repository 身份与登记的 GitHub HTTPS 市场核对;`url` / `git` 继续核对其 URL;官方 GitHub HTTPS Git 来源允许同一仓库的 `.git` 后缀。来源不同仍为 `AGENT_MARKETPLACE_SOURCE_MISMATCH`,不会把无响应或缺少 CLI 当作未安装。
|
|
112
|
+
|
|
113
|
+
安装物回归:`node tests/native/installed-detection.mjs /absolute/HanaMesh.app /absolute/new-evidence-directory https://website-origin` 从实际 app 资源读取种子版本,以全新 HOME / DSH_HOME / shared home / user-data 启动同一可执行文件;仅在出现该按钮时选择 Set up later,不登录或开启记录;随后断言获准 Origin 的发现响应、真实 POST、五作用域及本 runtime 的完整套件/版本。检测失败退出非零,保留逐端口响应、UI 与首错;不以页面可打开或目录中存在包文件代替运行结果。该手工安装物测试需要 macOS GUI 会话,默认源码单测另覆盖全新彩排配置初始化。
|
|
114
|
+
|
|
115
|
+
未发布候选可在最后追加本人自建、无凭据且由正常 DSH CLI 安装的 profile 路径。回归把该资料复制到新 DSH_HOME,再运行同一安装物;不手改 app 或 dist。默认不传此参数时仍检查 app 原始种子。
|
package/docs/LIBRARY.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
## 目录源
|
|
10
10
|
|
|
11
11
|
- `library.fixture` 只用于受控验收;内容必须符合 `schemas/catalog-provider-page.schema.json`。
|
|
12
|
-
- `library.sources` **未配置**时默认为 HanaMesh 目录源 `https://market.hanamesh.com/catalog-source.json?view=hanamesh`(rc.26;显式 `[]` = 不要来源);可有多项,但浏览时必须恰好启用一项。目录 manifest 接受标准端口 HTTPS
|
|
12
|
+
- `library.sources` **未配置**时默认为 HanaMesh 目录源 `https://market.hanamesh.com/catalog-source.json?view=hanamesh`(rc.26;显式 `[]` = 不要来源);可有多项,但浏览时必须恰好启用一项。目录 manifest 接受标准端口 HTTPS;HTTPS 本机回环 127.0.0.1、::1、localhost 及 *.localhost 可使用任意端口;本机回环 127.0.0.1、::1、localhost 另接受任意端口 HTTP(Node URL 解析后精确匹配主机名,安全上下文回环例外)。无凭据/fragment,仅允许可选查询 view=hanamesh;endpoint 和重定向必须保持完整同源(协议、主机、端口),不把主机别名互换。新默认仅在初始 revision=0 且来源为空时播种,已保存旧来源、自定义来源和手动清空列表均不自动改写。
|
|
13
13
|
- 请求固定 `Accept: application/json` 与 `Accept-Encoding: identity`;最多三次同源跳转,拒绝压缩响应与超过 2 MiB 的响应。
|
|
14
14
|
- `categories` 含 `hanamesh-app` 且 `package.registry` 为 `npm` 的条目是应用(安装后读 `app.json`、供给 runtime);其它 `package.registry` 为 `npm` 的条目是插件(rc.28 起同样可装卸,只跑 `dsh plugin add/remove`);无 npm 包的条目(repository-only)只展示。
|
|
15
15
|
|
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.25",
|
|
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"
|
|
File without changes
|
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.25",
|
|
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",
|
|
@@ -68,6 +68,28 @@
|
|
|
68
68
|
"docs/DSH_COMPATIBILITY.md",
|
|
69
69
|
"docs/INSTALLATION_STATUS.md"
|
|
70
70
|
],
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "node scripts/build.mjs",
|
|
73
|
+
"test": "node scripts/safe-git.mjs node --test --test-reporter=tap --test-concurrency=1 tests/*.test.mjs",
|
|
74
|
+
"test:contract": "pnpm run build && node --test --test-reporter=tap --test-concurrency=1 tests/install-target-contract.test.mjs tests/catalog-major-compat.test.mjs",
|
|
75
|
+
"test:mutation": "node scripts/safe-git.mjs node scripts/mutations.mjs",
|
|
76
|
+
"test:types": "tsc --noEmit --strict --target ES2022 --module NodeNext --moduleResolution NodeNext tests/consumer.mts",
|
|
77
|
+
"test:native-driver": "node scripts/safe-git.mjs node --test --test-reporter=tap tests/native/driver.test.mjs",
|
|
78
|
+
"check": "node scripts/safe-git.mjs node scripts/check.mjs",
|
|
79
|
+
"prepack": "npm run build",
|
|
80
|
+
"demo": "node examples/demo.mjs",
|
|
81
|
+
"preflight:dsh": "node scripts/preflight-dsh.mjs",
|
|
82
|
+
"check:consistency": "node scripts/check-consistency.mjs",
|
|
83
|
+
"check:toolchain": "node scripts/check-toolchain.mjs",
|
|
84
|
+
"preflight": "node scripts/preflight.mjs",
|
|
85
|
+
"verify:pack": "node scripts/safe-git.mjs node scripts/verify-package.mjs",
|
|
86
|
+
"check:devkit-supply": "node scripts/check-devkit-consumption.mjs",
|
|
87
|
+
"check:provision-supply": "node scripts/check-provision-consumption.mjs",
|
|
88
|
+
"install:safe": "node scripts/safe-git.mjs pnpm install --frozen-lockfile",
|
|
89
|
+
"release:check": "hanamesh-release check --lockfile pnpm-lock.yaml --installation-targets release/installation-targets.json",
|
|
90
|
+
"release:publish": "hanamesh-release publish --lockfile pnpm-lock.yaml --installation-targets release/installation-targets.json",
|
|
91
|
+
"prepublishOnly": "hanamesh-release source-guard"
|
|
92
|
+
},
|
|
71
93
|
"dsh": {
|
|
72
94
|
"bundle": {
|
|
73
95
|
"patch": "./profile/cordis.patch.yml"
|
|
@@ -146,27 +168,8 @@
|
|
|
146
168
|
"@types/node": "24.13.4",
|
|
147
169
|
"@types/js-yaml": "4.0.9"
|
|
148
170
|
},
|
|
171
|
+
"packageManager": "pnpm@10.33.0",
|
|
149
172
|
"bundleDependencies": [
|
|
150
173
|
"@hanamesh/lib-provision"
|
|
151
|
-
]
|
|
152
|
-
|
|
153
|
-
"build": "node scripts/build.mjs",
|
|
154
|
-
"test": "node scripts/safe-git.mjs node --test --test-reporter=tap --test-concurrency=1 tests/*.test.mjs",
|
|
155
|
-
"test:contract": "pnpm run build && node --test --test-reporter=tap --test-concurrency=1 tests/install-target-contract.test.mjs tests/catalog-major-compat.test.mjs",
|
|
156
|
-
"test:mutation": "node scripts/safe-git.mjs node scripts/mutations.mjs",
|
|
157
|
-
"test:types": "tsc --noEmit --strict --target ES2022 --module NodeNext --moduleResolution NodeNext tests/consumer.mts",
|
|
158
|
-
"test:native-driver": "node scripts/safe-git.mjs node --test --test-reporter=tap tests/native/driver.test.mjs",
|
|
159
|
-
"check": "node scripts/safe-git.mjs node scripts/check.mjs",
|
|
160
|
-
"demo": "node examples/demo.mjs",
|
|
161
|
-
"preflight:dsh": "node scripts/preflight-dsh.mjs",
|
|
162
|
-
"check:consistency": "node scripts/check-consistency.mjs",
|
|
163
|
-
"check:toolchain": "node scripts/check-toolchain.mjs",
|
|
164
|
-
"preflight": "node scripts/preflight.mjs",
|
|
165
|
-
"verify:pack": "node scripts/safe-git.mjs node scripts/verify-package.mjs",
|
|
166
|
-
"check:devkit-supply": "node scripts/check-devkit-consumption.mjs",
|
|
167
|
-
"check:provision-supply": "node scripts/check-provision-consumption.mjs",
|
|
168
|
-
"install:safe": "node scripts/safe-git.mjs pnpm install --frozen-lockfile",
|
|
169
|
-
"release:check": "hanamesh-release check --lockfile pnpm-lock.yaml --installation-targets release/installation-targets.json",
|
|
170
|
-
"release:publish": "hanamesh-release publish --lockfile pnpm-lock.yaml --installation-targets release/installation-targets.json"
|
|
171
|
-
}
|
|
172
|
-
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "urn:dsh-community-market:schema:catalog-source:1.1.0",
|
|
4
4
|
"title": "DSH Community Market catalog source manifest",
|
|
5
|
-
"description": "A provider-neutral declaration for one user-selectable JSON catalog endpoint (standard-port HTTPS or loopback HTTP on 127.0.0.1, ::1 or localhost). A user registers its manifest URL; selection and all other user-owned state stay local. The smallest recommended profile supports q, category, cursor, and limit and uses 50 as an example page size, not a global cap.",
|
|
5
|
+
"description": "A provider-neutral declaration for one user-selectable JSON catalog endpoint (standard-port HTTPS, local HTTPS on loopback or *.localhost, or loopback HTTP on 127.0.0.1, ::1 or localhost). A user registers its manifest URL; selection and all other user-owned state stay local. The smallest recommended profile supports q, category, cursor, and limit and uses 50 as an example page size, not a global cap.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"required": [
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"type": "string",
|
|
42
42
|
"format": "uri",
|
|
43
43
|
"maxLength": 2048,
|
|
44
|
-
"pattern": "^(?:https://(?![^/?#]*@)(?![^/?#]*:)[^/?#\\s]+|http://(?:127\\.0\\.0\\.1|\\[::1\\]|localhost)(?::[0-9]+)?)(?:/[^#]*)?$"
|
|
44
|
+
"pattern": "^(?:https://(?![^/?#]*@)(?![^/?#]*:)[^/?#\\s]+|https://(?:127\\.0\\.0\\.1|\\[::1\\]|(?:[^/?#:@\\s]+\\.)*localhost)(?::[0-9]+)?|http://(?:127\\.0\\.0\\.1|\\[::1\\]|localhost)(?::[0-9]+)?)(?:/[^#]*)?$"
|
|
45
45
|
},
|
|
46
46
|
"attribution": {
|
|
47
47
|
"type": "object",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"type": "string",
|
|
62
62
|
"format": "uri",
|
|
63
63
|
"maxLength": 2048,
|
|
64
|
-
"pattern": "^(?:https://(?![^/?#]*@)(?![^/?#]*:)[^/?#\\s]+|http://(?:127\\.0\\.0\\.1|\\[::1\\]|localhost)(?::[0-9]+)?)(?:/[^#]*)?$"
|
|
64
|
+
"pattern": "^(?:https://(?![^/?#]*@)(?![^/?#]*:)[^/?#\\s]+|https://(?:127\\.0\\.0\\.1|\\[::1\\]|(?:[^/?#:@\\s]+\\.)*localhost)(?::[0-9]+)?|http://(?:127\\.0\\.0\\.1|\\[::1\\]|localhost)(?::[0-9]+)?)(?:/[^#]*)?$"
|
|
65
65
|
},
|
|
66
66
|
"notice": {
|
|
67
67
|
"type": "string",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"type": "string",
|
|
87
87
|
"format": "uri",
|
|
88
88
|
"maxLength": 2048,
|
|
89
|
-
"pattern": "^(?:https://(?![^/?#]*@)(?![^/?#]*:)[^/?#\\s]+|http://(?:127\\.0\\.0\\.1|\\[::1\\]|localhost)(?::[0-9]+)?)(?:/[^?#\\s]*)?/v1/plugins$",
|
|
90
|
-
"description": "Standard-port HTTPS, or HTTP on 127.0.0.1, ::1 or localhost at any port, without credentials, query or fragment. Endpoint must share the exact user-approved manifest origin and end in /v1/plugins. URL parsing and port validity are enforced by the consumer."
|
|
89
|
+
"pattern": "^(?:https://(?![^/?#]*@)(?![^/?#]*:)[^/?#\\s]+|https://(?:127\\.0\\.0\\.1|\\[::1\\]|(?:[^/?#:@\\s]+\\.)*localhost)(?::[0-9]+)?|http://(?:127\\.0\\.0\\.1|\\[::1\\]|localhost)(?::[0-9]+)?)(?:/[^?#\\s]*)?/v1/plugins$",
|
|
90
|
+
"description": "Standard-port HTTPS, HTTPS on loopback or *.localhost at any port, or HTTP on 127.0.0.1, ::1 or localhost at any port, without credentials, query or fragment. Endpoint must share the exact user-approved manifest origin and end in /v1/plugins. URL parsing and port validity are enforced by the consumer."
|
|
91
91
|
},
|
|
92
92
|
"method": {
|
|
93
93
|
"const": "GET"
|