@tbox.cn/app-toolkit 0.7.0 → 0.7.2

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/dist/index.d.ts CHANGED
@@ -1004,7 +1004,8 @@ declare function invalidateContractsResolver(appDir?: string): void;
1004
1004
  * **code 枚举单源 = 本文件头映射表(additive-only;api.md §5 表与本表同步)**:
1005
1005
  * CREDENTIAL_FILE_MISSING #1 error effective credentialRef 引用凭据文件不在场
1006
1006
  * CREDENTIAL_TYPE_MISMATCH #2 error 凭据文件 .type 与绑定 credentialType 不一致
1007
- * SLOT_NOT_DECLARED #3 warning 服务槽无消费方声明(拼写/需求方未安装/旧槽位词汇)
1007
+ * SLOT_NOT_DECLARED #3 warning 服务槽无消费方声明(拼写/需求方未安装/旧槽位词汇;
1008
+ * v6.1 归属豁免——owned 服务不报)
1008
1009
  * SLOT_NOT_CONFIGURED #4 warning 需求方缺口(服务槽未配置)
1009
1010
  * INSTANCE_SUPPLY_UNMATCHED #5 error 绑定未命中已装供给(槽级/实例级覆盖)
1010
1011
  * IMPL_WITHOUT_PROVIDER #5/#13 error impl-only(implementation 缺 provider 绑定组头)
@@ -1437,9 +1438,10 @@ declare function pruneIntegrationBindings(appDir: string): Promise<PruneResult>;
1437
1438
  */
1438
1439
  /** 模块双键解析:id 精确 → 展示名(descriptor.name ?? id)唯一命中 → 404。 */
1439
1440
  declare function resolveModuleKey(walk: WalkManifestsResult, key: string): WalkModuleInfo;
1440
- /** 服务双键解析 → 真实 service id:服务键集(词汇 ∪ demand ∪ 供给足迹 ∪ configuredKeys
1441
+ /** 服务双键解析 → 真实 service id:服务键集(词汇 ∪ demand ∪ 供给足迹 ∪ configuredKeys ∪ 归属)
1441
1442
  * 精确命中 → 展示名(slotMeta.name ?? catalog.services[].name)唯一命中 → 404。
1442
- * configuredKeys = 当前集成配置 services 节键集(调用方注入)。 */
1443
+ * configuredKeys = 当前集成配置 services 节键集(调用方注入)。
1444
+ * v6.1 += 归属键(walk.ownership——纯归属无词汇/demand/供给的 owns 合法,O6 对称)。 */
1443
1445
  declare function resolveServiceKey(walk: WalkManifestsResult, configuredKeys: readonly string[], key: string): string;
1444
1446
 
1445
1447
  /**
@@ -1794,13 +1796,15 @@ interface ModuleDeclaration {
1794
1796
  * ?includeHidden=true 可见时徽标呈现) */
1795
1797
  hidden?: boolean;
1796
1798
  }
1797
- /** 服务需求声明(模块 demand 单元 / 平台服务条目——v4.4 D29 双端点同型;defaults 唯一落位 ServiceDetail) */
1799
+ /** 服务需求声明(模块 demand 单元 / 平台服务条目 / owned-not-consumed 投影条目——
1800
+ * v4.4 D29 双端点同型;defaults 唯一落位 ServiceDetail) */
1798
1801
  interface ServiceDemand {
1799
1802
  service: string;
1800
1803
  /** manifest demand meta(v7 title→name);缺席 UI 回退 service id */
1801
1804
  name?: string;
1802
1805
  description?: string;
1803
- /** demand optional === false(多模块 OR 聚合见 resolution echo;平台服务条目恒 false) */
1806
+ /** demand optional === false(多模块 OR 聚合见 resolution echo;平台服务条目与 owned
1807
+ * 投影条目恒 false——无 demand 源) */
1804
1808
  required: boolean;
1805
1809
  }
1806
1810
  /** GET /modules/:module(模块静态一站式 · PUT 读对偶) */
@@ -1825,9 +1829,11 @@ interface ModuleDetailView {
1825
1829
  binding: ModuleBinding | null;
1826
1830
  /** v6:owns.length > 0(moduleOwnershipWritable 单源——读标志与写守卫共用) */
1827
1831
  configEditable: boolean;
1828
- /** 本模块 demand(declare.consumes;卡片展开 + 编辑器静态上下文自足) */
1832
+ /** 本模块服务面 = demand owned 去重投影(2026-09-21 服务面投影批——通用合并无 consumes
1833
+ * 空判特例:consume 条目胜出[声明序原样、required = optional === false];owned-not-consumed
1834
+ * 追加[ownedServices 排序序、Set 去重,required 恒 false]。卡片展开 + 编辑器静态上下文自足) */
1829
1835
  services: ServiceDemand[];
1830
- /** v4.4 D31:include=serviceResolutions 内嵌(demand 服务过滤 ≡ 批量 ?service= 语义;<0.9/形态异常 → null——永不 503) */
1836
+ /** v4.4 D31:include=serviceResolutions 内嵌(v6.1 键集 = owned ∪ demand 服务过滤 ≡ 批量 ?service= 语义;<0.9/形态异常 → null——永不 503) */
1831
1837
  serviceResolutions?: ServiceResolutionsView | null;
1832
1838
  /** v4.4 D32:include=integrationSchemas 层级富化(零归属/未绑定 → null) */
1833
1839
  integrationSchemas?: LayerIntegrationSchemas | null;
@@ -1858,7 +1864,8 @@ interface IntegrationFieldRegistryView {
1858
1864
  provider: string;
1859
1865
  /** 作用域内 configSchema === null 的服务(UI「未提供参数模板」提示行) */
1860
1866
  schemaless: string[];
1861
- /** module 轴 = demand − 该厂商供给(Set 去重保序);app 轴恒 [](结构性:足迹 ⊆ 供给) */
1867
+ /** module 轴 = ownedServices − 该厂商供给(v6.1 scope 随归属——loadModuleFormViews 单源,
1868
+ * Set 去重保序);app 轴恒 [](结构性:足迹 ⊆ 供给) */
1862
1869
  unsupplied: string[];
1863
1870
  /** 作用域内全部非 null schema 的 additionalProperties 均 ≠ false(聚合;空真) */
1864
1871
  additionalPropertiesAllowed: boolean;
@@ -1925,7 +1932,7 @@ interface ServiceIntegrationSchemas {
1925
1932
  interface ServiceResolutionsView {
1926
1933
  /** P6 contracts echo(仅求值轴两端点携带) */
1927
1934
  contracts: ContractsResolution;
1928
- /** 键集 = 服务词汇 ∪ 已配置(模块/平台/孤儿全量) */
1935
+ /** 键集 = 服务词汇 ∪ 已配置 ∪ 归属(v6.1 += 归属——owned 服务恒可求值;模块/平台/孤儿全量) */
1929
1936
  resolutions: Record<string, ServiceResolutionEntry>;
1930
1937
  /** 谓词全量(doctor 同源;恒全量——subset 消费方客户端过滤) */
1931
1938
  issues: IntegrationIssue[];
@@ -1942,7 +1949,8 @@ interface ServiceResolutionEntry {
1942
1949
  layer?: BindingLayer;
1943
1950
  /** provider 在场时在场:(provider, service) ∈ 供给关系 */
1944
1951
  supplied?: boolean;
1945
- /** owner 模块 install id;平台服务/孤儿缺席 */
1952
+ /** owner 模块 install id(v6.1 = walk.ownership 归属单源——install id 轴,与模块清单 id 恒可 join;
1953
+ * 旧实现 demand owners[0] 为包名/@app 轴且漏 owned-not-consumed,已退役);平台服务/孤儿缺席 */
1946
1954
  module?: string;
1947
1955
  /** demand echo(OR 聚合);平台/孤儿恒 false;集成就绪判定单源(§7) */
1948
1956
  required?: boolean;
@@ -2227,7 +2235,7 @@ declare function loadProviderServiceDetailView(snapshot: ViewSnapshot, provider:
2227
2235
 
2228
2236
  /** P14 单源摘要函数:/service-resolutions map 值 ≡ /service-resolutions/:s 的 resolution 摘要基 */
2229
2237
  declare function resolveServiceSummary(service: string, snapshot: ViewSnapshot): ServiceResolutionEntry;
2230
- /** 批量求值(键集 = 服务词汇已配置;?service= 过滤语义——未知键缺席;issues 恒全量) */
2238
+ /** 批量求值(键集 = resolutionKeys 单源:词汇 需求侧 ∪ 已配置 ∪ 归属;?service= 过滤语义——未知键缺席;issues 恒全量) */
2231
2239
  declare function loadServiceResolutionsView(snapshot: ViewSnapshot, issues: IntegrationIssue[], filter?: string[]): ServiceResolutionsView;
2232
2240
  /** 求值单体(完整结构 instances + inheritance + 过滤 issues;P14 extends 结构保证) */
2233
2241
  declare function loadServiceResolutionDetail(service: string, snapshot: ViewSnapshot, allIssues: IntegrationIssue[]): ServiceResolutionDetail;
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import{a as Ve,b as T,c as De}from"./chunk-WUULQDOV.js";import{z as k}from"zod";var z=/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/,ft=k.object({cardType:k.string(),schemaVersion:k.number().optional()}),vn=k.object({route:k.string(),component:k.string()}),yn=k.object({route:k.string(),label:k.string().optional(),icon:k.string().optional(),order:k.number().optional()}),Sn=k.object({id:k.string(),range:k.string().optional(),required:k.boolean().default(!0)}),wn=k.object({service:k.string(),provider:k.string().regex(z,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:k.string(),credentialType:k.string(),local:k.boolean().optional(),configSchema:k.string().optional(),credentialSchema:k.string().optional()}),hn=k.object({service:k.string(),optional:k.boolean().default(!0),defaults:k.array(k.object({provider:k.string().regex(z,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:k.string()})).default([]),name:k.string().optional(),description:k.string().optional()}),Rn=k.object({service:k.string()}).strict(),In=k.object({id:k.string(),type:k.string()}),kn=k.object({schemaVersion:k.number().default(1),id:k.string(),name:k.string().optional(),description:k.string().optional(),hidden:k.boolean().optional(),version:k.string().default("0.0.0"),kind:k.enum(["platform","business","third-party"]).default("business"),risk:k.object({level:k.enum(["high","medium","low"]).default("low"),writeBoundary:k.enum(["sdk-enforced","source"]).default("source")}).default({}),distribution:k.object({defaultMode:k.enum(["hybrid","sdk","codegen","local"]).default("codegen")}).default({}),declare:k.object({handlers:k.array(k.string()).default([]),tools:k.array(k.string()).default([]),cards:k.array(ft).default([]),routes:k.array(k.string()).default([]),pages:k.array(vn).default([]),tabs:k.array(yn).default([]),providers:k.object({slots:k.array(wn).default([])}).default({}),owns:k.array(Rn).default([]),consumes:k.array(hn).default([]),resources:k.array(In).default([])}).default({}),dependencies:k.object({modules:k.array(Sn).default([])}).default({}),env:k.array(k.string()).default([])}).strict();function gt(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let n=[],r=e;"contributes"in r&&n.push("(root): manifest 旧键 `contributes` 已更名 `declare`(v6 声明面)——codegen 副本经 `module update --source` 重新生成 / sdk 模式升级模块包 / 手改两键");let t=r.declare;t&&typeof t=="object"&&!Array.isArray(t)&&"services"in t&&n.push("declare: manifest 旧键 `declare.services` 已更名 `declare.consumes`(消费关系定向化)——同上三路径升级"),!("id"in r)&&"name"in r&&n.push("(root): manifest 标识键 `name` 已更名 `id`(v7 词汇统一)——codegen 副本经 `module update --source` 重新生成 / sdk 模式升级模块包 / 手改两键");let i=t&&typeof t=="object"&&!Array.isArray(t)?t:void 0,o=Array.isArray(i?.consumes)&&i.consumes.some(s=>s!==null&&typeof s=="object"&&"title"in s);return("title"in r||o)&&n.push("(root): manifest 展示名键 `title` 已更名 `name`(v7 词汇统一;declare.consumes[].title 同步改 name)——同上三路径升级"),n}function se(e){let n=gt(e);if(n.length>0)return{ok:!1,errors:n,legacy:!0};let r=kn.safeParse(e);return r.success?{ok:!0,value:r.data}:{ok:!1,errors:r.error.issues.map(t=>`${t.path.join(".")||"(root)"}: ${t.message}`)}}var mt=/\$\$?\{([A-Z][A-Z0-9_]*)(?::-([^}]*))?\}/g;function bn(e){return JSON.stringify(e).slice(1,-1)}function Fe(e,n=process.env){let r=[],t=e.replace(mt,(i,o,s)=>{if(i.startsWith("$$"))return i.slice(1);let l=n[o];return l!==void 0?bn(l):s!==void 0?bn(s):(r.push(o),i)});return r.length>0?{missing:r}:{text:t,missing:[]}}import{mkdirSync as vt,existsSync as Cn,readFileSync as yt,writeFileSync as St}from"fs";import{dirname as wt,join as An}from"path";function ve(e){let n={};for(let[r,t]of Object.entries(e)){if(typeof t!="string"){n[r]=null;continue}n[r]=t.length<=4?"****":`${t.slice(0,2)}****`}return n}var x=class extends Error{code;httpStatus;fields;constructor(n,r,t,i){super(t),this.name="AppToolkitError",this.code=n,this.httpStatus=r,this.fields=i}};function J(e){return e.notes.length>0?e.notes[0]:e.version===null?"contracts 不可解析(未安装)——检查应用依赖安装后重试":e.strictValidation?e.ownershipBindingV6===!1?`contracts ${e.version??"(版本未知)"} 不支持 v6 modules 绑定形状(OWNERSHIP_BINDING_V6 标记缺席)——升级应用 @tbox.cn/app-contracts 依赖后可用`:"contracts workspace 源码态未构建——执行 pnpm --filter @tbox.cn/app-contracts build 后重试":`contracts ${e.version} 无严格校验面(需 ≥0.9.0)——升级应用 @tbox.cn/app-contracts 依赖后可用`}function ye(e,n){if(n!==void 0&&(n.includes("/")||n.includes("\\")||n.includes("..")))throw new x("VALIDATION_FAILED",400,`凭据 stem 派生输入含路径敌对字符(${e})——拒绝派生`)}function X(e){if(ye("provider",e.provider),ye("service",e.service),ye("instanceId",e.instanceId),ye("domain",e.domain),e.instanceId!==void 0){let n=e.domain??e.service??"global";return`${e.provider}-${e.instanceId}-${n}`}return e.service!==void 0?`${e.provider}-${e.service}`:`${e.provider}-global`}function ht(e){return`secret://${e}`}function _(e){return`config/credentials/${e}.json`}function ae(e,n){let r=An(e,_(n));if(!Cn(r))return null;try{let t=JSON.parse(yt(r,"utf8"));if(typeof t.type!="string")return null;let{type:i,...o}=t,s={};for(let[l,p]of Object.entries(o))typeof p=="string"&&(s[l]=p);return{type:i,values:s}}catch{return null}}function _e(e,n,r){let t=An(e,_(n)),i=Cn(t);return vt(wt(t),{recursive:!0}),St(t,`${JSON.stringify({type:r.type,...r.values},null,2)}
2
- `,"utf8"),i}import{mkdirSync as Rt,renameSync as It,writeFileSync as kt}from"fs";import{dirname as bt}from"path";function $(e,n){En(bt(e));let r=`${e}.tmp-${process.pid}-${Date.now()}`;kt(r,n,"utf8"),It(r,e)}function En(e){Rt(e,{recursive:!0})}import{existsSync as F,readdirSync as Le,readFileSync as ee}from"fs";import{join as P}from"path";import{existsSync as Ct,readFileSync as On,mkdirSync as At,writeFileSync as Et}from"fs";import xn from"path";function Se(e){return xn.join(e,".tbox","app.json")}function Mn(e){let n=Se(e);if(!Ct(n))return null;try{let r=JSON.parse(On(n,"utf8")),t=r?.templateVersion;return typeof t!="string"||t.trim().length===0?null:{templateVersion:t.trim(),npmModules:Array.isArray(r?.npmModules)?r.npmModules:[]}}catch{return null}}function Ot(e,n){let r=Se(e);At(xn.dirname(r),{recursive:!0}),Et(r,`${JSON.stringify(n,null,2)}
3
- `,"utf8")}function $e(e){let n=Mn(e);if(n===null)return null;let r=Se(e);try{let t=JSON.parse(On(r,"utf8"));return{...n,miniappContainers:Array.isArray(t?.miniappContainers)?t.miniappContainers:[]}}catch{return{...n,miniappContainers:[]}}}function xt(e,n){let r=e.npmModules.filter(t=>t.id!==n.id);return{...e,npmModules:[...r,n]}}function Mt(e,n){return{...e,npmModules:e.npmModules.filter(r=>r.id!==n)}}function jt(e,n){let r=(e.miniappContainers??[]).filter(t=>t.id!==n.id);return{...e,miniappContainers:[...r,n]}}function Tt(e,n,r){return{...e,npmModules:e.npmModules.map(t=>t.id===n?{...t,...r}:t)}}function jn(e){return/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)&&!e.includes("..")}function Nt(e,n){if(!jn(e))throw new Error(`非法模块 id "${e}"(来自 ${n}):仅允许小写字母/数字/中划线`)}function Tn(e){try{let n=JSON.parse(e);if(!Array.isArray(n.slots))return null;let r=n.slots.filter(i=>typeof i=="string"),t={};if(n.meta&&typeof n.meta=="object"&&!Array.isArray(n.meta))for(let[i,o]of Object.entries(n.meta)){if(!o||typeof o!="object"||Array.isArray(o))continue;let{name:s,description:l}=o,p={};typeof s=="string"&&s.length>0&&(p.name=s),typeof l=="string"&&l.length>0&&(p.description=l),(p.name!==void 0||p.description!==void 0)&&(t[i]=p)}return{slots:r,meta:t}}catch{return null}}function we(e,n){let r=t=>{try{let i=JSON.parse(t),o=se(i);if(o.ok)return{kind:"strict",id:o.value.id,version:o.value.version,descriptor:o.value,declare:o.value.declare};if(o.legacy)return{kind:"legacy",detail:o.errors.join("; ")};if(i&&typeof i=="object"&&"declare"in i){let s=i;return{kind:"loose",...typeof s.id=="string"?{id:s.id}:{},declare:{providers:s.declare?.providers,consumes:s.declare?.consumes}}}return null}catch{return null}};if(n)return n.read(e,r)??null;if(!F(e))return null;try{return r(ee(e,"utf8"))}catch{return null}}function Pt(e){let n=P(e,".tbox","app.json");if(!F(n))return[];try{let r=JSON.parse(ee(n,"utf8"));return Array.isArray(r.npmModules)?r.npmModules.filter(t=>!!t&&typeof t=="object"&&typeof t.id=="string"&&typeof t.package=="string"):[]}catch{return[]}}function Vt(e){let n=P(e,".tbox-dev.local"),r=P(n,"dev-manifest.json");if(!F(r))return[];try{let t=JSON.parse(ee(r,"utf8")),i=[];for(let[o,s]of Object.entries(t.redirects??{}))typeof s!="string"||!o.startsWith("@tbox.cn/app-")||i.push({pkg:o,dir:P(n,s)});return i}catch{return[]}}function Pn(e,n){let r=[],t=[e];for(let l of["apps","packages"]){let p=P(e,l);if(F(p))try{for(let c of Le(p,{withFileTypes:!0}))c.isDirectory()&&t.push(P(p,c.name))}catch{}}let i=new Set,o=(l,p,c)=>{let m=n?n.read(p,Tn):Tn(ee(p,"utf8"));m!=null&&r.push({dir:l,slots:m.slots,meta:m.meta,via:c})},s=P(e,"config","service-slots.json");F(s)&&o(e,s,"config-override");for(let l of t){let p=P(l,"node_modules","@tbox.cn");if(!F(p))continue;let c=[];try{c=Le(p)}catch{continue}for(let m of c){let I=P(p,m);if(i.has(I))continue;i.add(I);let h=P(I,"service-slots.json"),v=P(I,"src","service-slots.json");F(h)?o(I,h,"package"):F(v)&&o(I,v,"package")}}for(let l of t)for(let p of[P(l,"service-slots.json"),P(l,"src","service-slots.json")])F(p)&&o(l,p,"local");return r}function V(e,n){let r=[],t={providers:{},services:{},credentialTypes:{}},i={},o=[],s={},l=new Set,p=(a,g,w,S)=>{for(let u of a){let y=t.providers[u.provider]??={},b=y[u.implementation];b?b.services.includes(u.service)||b.services.push(u.service):(y[u.implementation]={provider:u.provider,implementation:u.implementation,credentialType:u.credentialType,owner:g,...S?.name?{name:S.name}:{},...S?.description?{description:S.description}:{},...u.local?{local:!0}:{},...u.configSchema?{configSchema:u.configSchema}:{},...u.credentialSchema?{credentialSchema:u.credentialSchema}:{},services:[u.service]},t.credentialTypes[u.credentialType]??={owner:g,packageDir:w,...u.credentialSchema?{credentialSchema:u.credentialSchema}:{}});let d=`${u.provider}\0${u.service}`;i[d]||(i[d]={...u.configSchema?{configSchema:u.configSchema}:{},...u.credentialSchema?{credentialSchema:u.credentialSchema}:{},packageDir:w})}},c=a=>a.kind==="strict"?{name:a.descriptor.name,description:a.descriptor.description}:void 0,m=(a,g)=>{for(let w of a){let S=s[w];S===void 0?s[w]=g:S!==g&&o.push({severity:"error",code:"OWNERSHIP_CONFLICT",module:g,message:`服务 ${w} 归属冲突:${S} 与 ${g} 均声明 owns(先声明 ${S} 胜出)——修正 manifest declare.owns 互斥`})}},I=(a,g)=>{a.kind==="legacy"&&o.push({severity:"error",code:"OLD_MANIFEST_KEY",module:g,message:`${g}:${a.detail}`})},h=a=>a.kind==="strict"||a.kind==="loose"?a.declare:null,v=(a,g)=>{let w=a.optional!==!1,S=a.defaults??[],u=t.services[a.service];if(u){u.optional=u.optional&&w;let y=new Set(u.defaults.map(b=>`${b.provider}\0${b.implementation}`));for(let b of S){let d=`${b.provider}\0${b.implementation}`;y.has(d)||(u.defaults.push(b),y.add(d))}u.owners.includes(g)||u.owners.push(g);return}t.services[a.service]={optional:w,defaults:[...S],...a.name?{name:a.name}:{},...a.description?{description:a.description}:{},owners:[g]}};for(let a of Pt(e)){if(l.has(a.id))continue;let g=P(e,"packages",a.id),w=P(e,"node_modules",...a.package.split("/")),S=we(P(g,"tbox.module.json"),n)??we(P(w,"tbox.module.json"),n);if(S?.kind==="legacy"){I(S,a.id),l.add(a.id);continue}if(!S)continue;l.add(a.id);let u=F(P(g,"tbox.module.json"))?g:w,y=h(S);S.kind==="strict"&&r.push({id:a.id,dir:u,pkg:a.mode==="sdk"?a.package:`@app/${a.id}`,descriptor:S.descriptor});let b=y?.providers?.slots??[];b.length&&p(b,a.package,u,c(S));let d=y?.consumes??[];for(let E of d)v(E,a.package);let R=S.kind==="strict"?S.descriptor.declare.owns:[];R.length&&m(R.map(E=>E.service),a.id)}for(let{pkg:a,dir:g}of Vt(e)){let w=we(P(g,"tbox.module.json"),n);if(w?.kind==="legacy"){I(w,a);continue}if(!w?.id||l.has(w.id))continue;l.add(w.id);let S=h(w),u=S?.providers?.slots??[];u.length&&p(u,a,g,c(w));let y=S?.consumes??[];for(let d of y)v(d,a);let b=w.kind==="strict"?w.descriptor.declare.owns:[];b.length&&m(b.map(d=>d.service),w.id)}let A=P(e,"packages");if(F(A)){let a=[];try{a=Le(A,{withFileTypes:!0}).filter(g=>g.isDirectory()).map(g=>g.name)}catch{}for(let g of a){if(l.has(g))continue;let w=P(A,g),S=we(P(w,"tbox.module.json"),n);if(S?.kind==="legacy"){I(S,g),l.add(g);continue}if(!S)continue;let u=S.id??g;if(l.has(u))continue;l.add(u);let y=h(S);S.kind==="strict"&&r.push({id:u,dir:w,pkg:`@app/${u}`,descriptor:S.descriptor});let b=y?.providers?.slots??[];b.length&&p(b,`@app/${u}`,w,c(S));let d=y?.consumes??[];for(let E of d)v(E,`@app/${u}`);let R=S.kind==="strict"?S.descriptor.declare.owns:[];R.length&&m(R.map(E=>E.service),u)}}let O=new Set,f={};for(let a of Pn(e,n)){for(let g of a.slots)O.add(g);for(let[g,w]of Object.entries(a.meta))f[g]===void 0&&(f[g]=w)}return{modules:r,catalog:t,serviceSchemas:i,vocabulary:[...O].sort(),slotMeta:f,ownership:s,declarationIssues:o}}function Nn(e,n,r){let t=P(e,"src",n,"index.ts");if(!F(t))return!1;try{let i=ee(t,"utf8");return new RegExp(`export\\s+const\\s+${r}\\b`).test(i)}catch{return!1}}function Dt(e){let n=P(e,"src","server","index.ts");if(!F(n))return"";try{return ee(n,"utf8")}catch{return""}}function Vn(e){return e.match(/declaration\s*:\s*\{[\s\S]*?moduleId\s*:\s*['"]([^'"]+)['"]/)?.[1]}function Ft(e){let n=[],r=V(e),t=$e(e),i=new Map;for(let o of t?.npmModules??[])i.set(o.id,o.mode);for(let o of r.modules){let s=i.get(o.id)??"local",l=Nn(o.dir,"server","serverModule"),p=o.descriptor.declare;n.push({id:o.id,pkg:s==="sdk"?o.pkg:`@app/${o.id}`,mode:s,hasServerEntry:l,hasClientEntry:Nn(o.dir,"client","clientModule"),hasCards:(p.cards?.length??0)>0,...l?{moduleId:Vn(Dt(o.dir))}:{}})}return n.sort((o,s)=>o.id.localeCompare(s.id))}function _t(e){return V(e).ownership}function L(e,n){let r=e?.modules?.[n]?.provider;if(typeof r=="string"&&r.length>0)return{provider:r,layer:"module"};let t=e?.provider;return typeof t=="string"&&t.length>0?{provider:t,layer:"app"}:{provider:null,layer:null}}function G(e,n){let r=(n.descriptor.declare.owns??[]).map(t=>t.service).sort();return r.length===0?{writable:!1,reason:"zero-ownership",ownedServices:[]}:{writable:!0,ownedServices:r}}function We(e,n){return[...new Set(Object.values(e.providers[n]??{}).flatMap(r=>r.services))].sort()}function H(e){if(!e||typeof e!="object")return!1;let n=Object.keys(e),r=new Set(["provider","credentialType","configSchema"]);if(!n.every(i=>r.has(i)))return!1;let t=e;return typeof t.provider=="string"&&t.provider.length>0&&typeof t.credentialType=="string"&&t.credentialType.length>0&&(t.configSchema===void 0||typeof t.configSchema=="string")}function Dn(e,n,r){return e==="*"||r.has(e)?null:{severity:"error",code:"INSTANCE_KEY_NOT_REGISTERED",instance:e,message:`integrations: ${n} 键 ${e} 不在 malls 白名单内(${[...r].join(", ")})`}}function Be(e,n){let r=new Set(n),t=[],i=(o,s)=>{let l=Dn(o,s,r);l&&t.push(l)};for(let o of Object.keys(e.configByInstance??{}))i(o,"configByInstance");for(let o of Object.keys(e.credentialRefByInstance??{}))i(o,"credentialRefByInstance");for(let[o,s]of Object.entries(e.services??{}))for(let l of Object.keys(s.instances??{}))i(l,`services.${o}.instances`);return t}function ne(e){let n=[],r=e.contracts,{integrations:t,suppliedProviders:i,demandedServices:o,supplies:s,malls:l,credentialSchemaMissing:p,vendorConfigKeys:c,vendorGlobalConfigKeys:m,vendorConfigSchemaMissing:I,credentialFileMissing:h,credentialFileType:v,realmSwitchHints:A,moduleResourceNeeds:O,ownership:f,installedModuleIds:a}=e,g=l?new Set(l):void 0;for(let d of A??[])n.push({severity:"warning",code:"REALM_SWITCH_HINT",message:d});let w=new Set(Object.keys(i).map(d=>d.slice(0,d.indexOf("\0"))).filter(d=>d.length>0)),S=(d,R,E,C)=>{if(typeof E?.provider=="string"&&typeof E.implementation=="string"&&E.provider&&E.implementation)return i[ce(E.provider,E.implementation)]?.credentialType;if(typeof R.provider=="string"&&typeof R.implementation=="string")return i[ce(R.provider,R.implementation)]?.credentialType;let M=R.provider?.credentialType;if(typeof M=="string")return M;if(!s)return;let N=C??Object.keys(R.instances??{})[0]??"",j=r.resolveEffectiveService(t,d,N,s,f);if(!(j.status!=="ok"||typeof j.effective.provider!="string"))return i[ce(j.effective.provider,j.effective.implementation)]?.credentialType};if(h||v)for(let[d,R]of Object.entries(t.services))for(let[E,C]of Object.entries(R.instances??{})){if(C.enabled===!1)continue;let M=C.credentialRef??R.credentialRef??t.credentialRefByInstance?.[E]??t.credentialRef;if(typeof M!="string"||!M.startsWith("secret://"))continue;let N=M.slice(9);h?.[N]===!0&&n.push({severity:"error",code:"CREDENTIAL_FILE_MISSING",service:d,instance:E,message:`integrations: 凭据文件缺失 ${N}(${d}@${E} effective ref=${M};档内 config/credentials/ 无此文件)`});let j=v?.[N];if(j){let D=S(d,R,C,E);D&&j!==D&&n.push({severity:"error",code:"CREDENTIAL_TYPE_MISMATCH",service:d,instance:E,message:`integrations: 凭据文件 ${N}.json type=${j} 与绑定 credentialType ${D} 不一致(${d}@${E}——transport 创建期将按 type 选策略)`})}}let u=(d,R)=>{if(!g)return;let E=Dn(d,R,g);E&&n.push(E)};for(let[d]of Object.entries(t.configByInstance??{}))u(d,"configByInstance");for(let[d]of Object.entries(t.credentialRefByInstance??{}))u(d,"credentialRefByInstance");let y=Object.entries(t.services).filter(([,d])=>d.instances==null||d.instances["*"]!=null).map(([d])=>d);if(y.length>0){let d=Object.entries(t.services).filter(([,R])=>R.instances!=null&&R.instances["*"]==null).map(([R])=>R);d.length>0&&n.push({severity:"warning",code:"WILDCARD_ALIGNMENT",message:`integrations: 激活形态不对称(通配:${y.join(", ")};显式键集:${d.join(", ")})——动态 mallId 将在显式键集槽上 INSTANCE_NOT_FOUND(provider 业务限制表达位),确认是否齐步`})}let b=r.normalizeInstances({instances:t.instances,defaultInstanceId:t.defaultInstanceId});b.instances.length>=2&&b.defaultInstanceId===null&&n.push({severity:"warning",code:"MULTI_INSTANCE_NO_DEFAULT",message:`integrations: ${b.instances.length} 个部署实例(${b.instances.map(d=>d.id).join(", ")})均无 defaultInstanceId——无 scope 参数访问将落全局会话(默认商圈不注入)`});for(let[d,R]of Object.entries(t.services)){if(o[d]||n.push({severity:"warning",code:"SLOT_NOT_DECLARED",service:d,message:`integrations: 服务槽 ${d} 无消费方声明(拼写错误或需求方未安装)——若为拆分前旧槽位词汇(member.main/parking.main/promotion.read/shopping-guide.main),参照 cookbook·app-config 槽位迁移配方展开为新槽`}),typeof R.provider=="string"?typeof R.implementation=="string"&&!i[ce(R.provider,R.implementation)]&&n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:d,message:`integrations: provider ${R.provider}/${R.implementation} 未命中已装供给(${d} 槽级)——装对应 provider 包或改绑`}):R.provider!==void 0&&!H(R.provider)&&n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:d,message:`integrations: 内联 provider 超受控形状(${d} 槽级;允许键 provider/credentialType/configSchema)`}),p){let C=S(d,R);C&&p[C]===!0&&n.push({severity:"error",code:"SCHEMA_FILE_MISSING",service:d,message:`integrations: credentialType ${C} 的 schema 引用不存在(${d};manifest 声明指向缺失文件)`})}typeof R.provider=="object"&&typeof R.implementation!="string"&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:d,message:`integrations: 内联厂商声明必须同时提供 implementation(${d} 槽级)`});for(let[C,M]of Object.entries(R.instances??{})){u(C,`services.${d}.instances`);let N=M.provider!==void 0,j=M.implementation!==void 0;if(j&&!N&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:d,instance:C,message:`integrations: 实例级 implementation 需伴随 provider(${d}@${C}——impl-only 禁止,provider 是绑定组头)`}),N&&j){let D=M.provider,W=M.implementation;typeof D=="string"&&typeof W=="string"?i[ce(D,W)]||n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:d,instance:C,message:`integrations: 实例级 provider 覆盖 ${D}/${W} 未命中已装供给(${d}@${C})`}):H(D)||n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:d,instance:C,message:`integrations: 实例级内联 provider 超受控形状(${d}@${C})`})}}}for(let[d,R]of[["root",t.provider],...Object.entries(t.modules??{}).map(([E,C])=>[`modules.${E}`,C?.provider])])typeof R!="string"||R.length===0||w.has(R)||n.push({severity:"error",code:"VENDOR_NOT_INSTALLED",module:d.startsWith("modules.")?d.slice(8):void 0,message:`integrations: ${d} provider ${R} 未命中已装供给——装对应 provider 包或 provider use 改绑`});if(s)for(let[d,R]of Object.entries(t.services)){let E=R.instances?Object.keys(R.instances):[""];for(let C of E){let M=r.resolveEffectiveService(t,d,C,s,f);M.status==="binding-unresolved"&&n.push({severity:"error",code:"BINDING_UNRESOLVED",service:d,instance:C||void 0,message:`integrations: ${M.message}`})}}for(let[d,R]of Object.entries(t.services))R.implementation!==void 0&&R.provider===void 0&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:d,message:`integrations: 槽级 implementation 需伴随 provider(${d}——impl-only 禁止,provider 是绑定组头)`});for(let[d,R]of Object.entries(t.modules??{})){if(!(R?.provider!==void 0||R?.config!==void 0))continue;let C=a?!a.has(d):!1,M=0;if(f)for(let j of Object.values(f))j===d&&(M+=1);if(C||!(f===void 0)&&M===0){let j=C?"未安装(键 = install id)":"未声明任何 owns(无模块级配置位)";n.push({severity:"error",code:"MODULE_CONFIG_DEAD",module:d,message:`integrations: modules.${d} 携带 provider/config 但模块${j}(MODULE_CONFIG_DEAD——模块级集成位作用于 declare.owns 服务,改 declare.owns 或删除该节点)`})}}if(c){let d=new Set,R=!1,E=C=>{typeof C!="string"||C.length===0||(c[C]&&d.add(C),!c[C]&&!I?.[C]&&(R=!0),I?.[C]&&(R=!0))};E(t.provider);for(let C of Object.values(t.modules??{}))E(C?.provider);for(let C of Object.values(t.services)){let M=C.provider;E(typeof C.provider=="string"?C.provider:M?.provider)}if(d.size>0&&!R){let C=new Set;for(let j of d)for(let D of c[j]??[])C.add(D);let M=new Set;for(let j of d)for(let D of m?.[j]??[])M.add(D);let N=(j,D,W,Z)=>{for(let[Q]of Object.entries(j??{}))(W??C).has(Q)?Z&&Z.size>0&&!Z.has(Q)&&n.push({severity:"warning",code:"GLOBAL_FIELD_UNDECLARED",message:`integrations: ${D} 键 ${Q} 过 schema 校验但未声明 x-tbox-global(不进应用/模块全局表单;已配置值照常生效——如需全局编辑请在 provider schema 标记)`}):n.push({severity:"error",code:"DOMAIN_CONFIG_INVALID",message:`integrations: ${D} 键 ${Q} 不在引用厂商(${[...d].join("/")})任何槽 schema properties 内(死配置)`})};N(t.config,"root.config",void 0,M);for(let[j,D]of Object.entries(t.configByInstance??{}))N(D,`root.configByInstance[${j}]`,void 0,M);for(let[j,D]of Object.entries(t.modules??{})){if(!D?.config)continue;let W=L(t,j).provider??void 0;if(W===void 0){N(D.config,`modules.${j}.config`,void 0,M);continue}let Z=c[W];if(!Z||I?.[W])continue;let Q=m?.[W];N(D.config,`modules.${j}.config`,new Set(Z),Q)}}}for(let[d,R]of Object.entries(o)){let E=t.services[d];if(!E){n.push({severity:"warning",code:"SLOT_NOT_CONFIGURED",service:d,message:`integrations: 服务槽 ${d}(需求方 ${R.owners.join(", ")})未配置${R.optional?"(可选槽)":"(必需槽——模块将走降级链)"}`});continue}let C=Object.entries(E.instances??{}).filter(([,M])=>M.enabled===!1).map(([M])=>M);C.length>0&&n.push({severity:"warning",code:"INSTANCE_DISABLED",service:d,instance:C.join(", "),message:`integrations: ${d} 实例禁用(${C.join(", ")})`})}for(let[d,R]of Object.entries(t.modules??{})){let E=O?.[d];O&&!(d in O)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:d,message:`integrations: modules.${d} 未命中已装模块(键 = install id——检查 .tbox/app.json entry.id / packages/ 目录名)`});for(let[C,M]of Object.entries(R?.resources??{})){let N=M?.type;(typeof N!="string"||!r.RESOURCE_TYPE_IDS.includes(N))&&n.push({severity:"error",code:"RESOURCE_TYPE_UNKNOWN",module:d,message:`integrations: modules.${d}.resources.${C} type 非法(${String(N)};词汇表 = ${r.RESOURCE_TYPE_IDS.join("/")})`}),E&&E.size>0&&!E.has(C)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:d,message:`integrations: modules.${d}.resources.${C} 未被模块 manifest declare.resources 声明`})}}return n}function ce(e,n){return`${e}\0${n}`}import{existsSync as Ue,readFileSync as $t,readdirSync as Lt}from"fs";import{join as he}from"path";function _n(e){return e.replaceAll("-","_").toUpperCase()}function Fn(e){if(!Ue(e))return null;try{let n=JSON.parse($t(e,"utf8"));return n&&typeof n=="object"?n:null}catch{return null}}function Wt(e){let n=new Set,r=e.properties;if(r&&typeof r=="object"&&!Array.isArray(r))for(let t of Object.keys(r))n.add(t);return n}function de(e,n,r,t=process.env){let i={};for(let[u,y]of Object.entries(n.catalog.providers))for(let[b,d]of Object.entries(y))i[`${u}\0${b}`]={services:[...d.services],owner:d.owner,credentialType:d.credentialType};let o={};for(let[u,y]of Object.entries(n.catalog.services))o[u]={optional:y.optional,owners:[...y.owners]};let s={},l={},p={},c={},m={};for(let u of n.modules){m[u.id]=new Set((u.descriptor.declare.resources??[]).map(y=>y.id));for(let y of u.descriptor.declare.providers?.slots??[]){if(y.configSchema){let b=Fn(he(u.dir,y.configSchema));if(b){let d=s[y.provider]??=new Set,R=l[y.provider]??=new Set;for(let C of Wt(b))d.add(C);let E=b.properties;if(E&&typeof E=="object"&&!Array.isArray(E))for(let[C,M]of Object.entries(E))M&&typeof M=="object"&&M["x-tbox-global"]===!0&&R.add(C)}else p[y.provider]=!0}y.credentialSchema&&!Ue(he(u.dir,y.credentialSchema))&&(c[y.credentialType]=!0)}}let I={},h=new Set,v=he(e,"config","credentials");if(Ue(v))for(let u of Lt(v)){if(!u.endsWith(".json"))continue;let y=u.slice(0,-5);h.add(y);let b=Fn(he(v,u));b&&typeof b.type=="string"&&(I[y]=b.type)}let A=r,O=[],f=u=>{typeof u=="string"&&u.startsWith("secret://")&&O.push(u)};for(let u of Object.values(A.services??{}))if(u&&typeof u=="object"){f(u.credentialRef);for(let y of Object.values(u.instances??{}))y&&typeof y=="object"&&f(y.credentialRef)}for(let u of Object.values(A.credentialRefByInstance??{}))f(u);f(A.credentialRef);let a={};for(let u of O){let y=u.slice(9);t[_n(y)]===void 0&&(h.has(y)||(a[y]=!0))}let g=[];for(let[u,y]of Object.entries(A.services??{})){let b=y&&typeof y=="object"&&typeof y.provider=="string"?y.provider:void 0;for(let[d,R]of Object.entries((y&&typeof y=="object"?y.instances:void 0)??{})){let E=R&&typeof R=="object"&&typeof R.provider=="string"?R.provider:void 0;b&&E&&E!==b&&g.push(`integrations: ${u}@${d} 实现覆盖跨厂商(${b} → ${E})——凭据域切换,确认该 mall 对应凭据在场`)}}let S=((Array.isArray(A.instances)?A.instances:void 0)??[]).map(u=>u&&typeof u=="object"&&typeof u.id=="string"?u.id:void 0).filter(u=>typeof u=="string");return{suppliedProviders:i,demandedServices:o,credentialFileMissing:a,credentialFileType:I,credentialSchemaMissing:c,vendorConfigKeys:s,vendorGlobalConfigKeys:l,vendorConfigSchemaMissing:p,realmSwitchHints:g,moduleResourceNeeds:m,...S.length>0?{malls:S}:{},ownership:n.ownership,installedModuleIds:new Set([...n.modules.map(u=>u.id),...new Set(Object.values(n.ownership))])}}import{existsSync as ti,readFileSync as ri}from"fs";import{join as oi,resolve as si}from"path";function Ke(e){return V(e).catalog}function Re(e){let n=V(e).catalog,r={};for(let[o,s]of Object.entries(n.providers)){r[o]={};for(let[l,p]of Object.entries(s))r[o][l]={provider:p.provider,implementation:p.implementation,credentialType:p.credentialType,owner:p.owner,...p.local?{local:!0}:{},...p.configSchema?{configSchema:p.configSchema}:{},...p.credentialSchema?{credentialSchema:p.credentialSchema}:{},services:[...p.services]}}let t={};for(let[o,s]of Object.entries(n.services))t[o]={optional:s.optional,defaults:s.defaults.map(l=>({...l})),owners:[...s.owners]};let i={};for(let[o,s]of Object.entries(n.credentialTypes))i[o]={owner:s.owner,...s.credentialSchema?{credentialSchema:s.credentialSchema}:{}};return{providers:r,services:t,credentialTypes:i}}async function ze(e,n,r,t=process.env){let i=r.module,o=V(e),s=i.buildSupplyLookup(Re(e)),l=de(e,o,n,t);return ne({contracts:i,integrations:n,supplies:s,...l})}import{existsSync as Ht,rmSync as Yt}from"fs";import{join as qt}from"path";import{existsSync as Bt,readFileSync as Ut}from"fs";import{join as $n}from"path";var Kt=$n("config","integrations.json");function B(e,n){let r=$n(e,Kt),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!Bt(r))return null;try{return t(Ut(r,"utf8"))}catch{return null}}async function Ln(e,n){let r=await T(e),t=B(e,n);if(t===null)return{config:null,strict:!1,contracts:r};if(r.strictValidation&&r.module.parseIntegrationsConfig)try{return{config:r.module.parseIntegrationsConfig(t),strict:!0,contracts:r}}catch(i){if(i instanceof Error&&Array.isArray(i.issues)){let o=i.issues.filter(s=>Array.isArray(s.path)).map(s=>s.path.map(String).join(".")).filter(s=>s.length>0);throw new x("VALIDATION_FAILED",400,"integrations.json 校验失败",o.length>0?o:void 0)}throw new x("VALIDATION_FAILED",400,i instanceof Error?i.message:String(i))}return{config:t,strict:!1,contracts:r}}function le(e,n,r){return e.includes(r)||n.includes(r)}import{readdirSync as zt,existsSync as Ie,readFileSync as Jt}from"fs";import{join as ke}from"path";function Wn(e,n,r){let t=[];if(n){let i=X({provider:e});t.push({stem:i,ref:`secret://${i}`,input:n})}for(let[i,o]of Object.entries(r??{})){let s=X({provider:e,instanceId:i});t.push({instanceId:i,stem:s,ref:`secret://${s}`,input:o})}return t}function Bn(e,n,r,t,i){let o=[];if(t){let s=X({provider:e,service:n});o.push({stem:s,ref:`secret://${s}`,input:t})}for(let[s,l]of Object.entries(i??{})){let p=X({provider:e,instanceId:s,domain:r});o.push({instanceId:s,stem:p,ref:`secret://${p}`,input:l})}return o}function Ge(e,n,r){return n.map(t=>({stem:t.stem,ref:t.ref,overwrote:r?Ie(ke(e,_(t.stem))):_e(e,t.stem,t.input)}))}function Gt(e,n){return Ie(ke(e,_(n)))}function Je(e,n){if(typeof e=="string"){e.startsWith("secret://")&&n.add(e.slice(9));return}if(Array.isArray(e)){for(let r of e)Je(r,n);return}if(e&&typeof e=="object")for(let r of Object.values(e))Je(r,n)}function te(e){let n=ke(e,"config","credentials"),r=new Set,t=ke(e,"config","integrations.json");if(Ie(t))try{Je(JSON.parse(Jt(t,"utf8")),r)}catch{}let i=[];if(!Ie(n))return i;let o=[];try{o=zt(n).filter(s=>s.endsWith(".json")).map(s=>s.slice(0,-5))}catch{return i}for(let s of o.sort()){if(r.has(s))continue;let l=ae(e,s);i.push({severity:"warning",code:"ORPHANED_CREDENTIAL",message:`${_(s)} 不再被引用(凭据文件保留,可手动清理)`})}return i}function be(e){if(typeof e=="string")return e.length>0?e:void 0;if(e&&typeof e=="object"&&H(e)){let n=e.provider;return n.length>0?n:void 0}}async function Zt(e){let n=qt(e,"config","integrations.json"),r=B(e);if(r===null)return{removed:[],orphanCredentials:[],skipped:"not-configured"};let t=await T(e);if(!t.strictValidation)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};let i;try{let v=Fe(JSON.stringify(r),process.env);if(v.missing.length>0||v.text===void 0)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};i=JSON.parse(v.text)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let o;try{o=await ze(e,i,t,process.env)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let s=V(e),l=new Set(Object.keys(s.catalog.providers)),p=s.ownership,c=structuredClone(r);c.services??={};let m=[];for(let v of o)if(v.severity==="error"){if(v.code==="VENDOR_NOT_INSTALLED")if(v.module){let O=(c.modules??{})[v.module];O?.provider&&(m.push(`modules.${v.module}.provider=${String(O.provider)}`),delete O.provider,Object.keys(O).length===0&&delete c.modules[v.module])}else c.provider&&(m.push(`root.provider=${c.provider}`),delete c.provider);else if(v.code==="MODULE_CONFIG_DEAD"&&v.module){let A=c.modules??{};if(A[v.module]){let O=A[v.module],f=[O.provider!==void 0?"provider":void 0,O.config!==void 0?"config":void 0,O.resources!==void 0?"resources":void 0].filter(Boolean);m.push(`modules.${v.module}(${f.join("+")} 整节点)`),delete c.modules[v.module]}}else if(v.code==="BINDING_UNRESOLVED"&&v.service){let A=c.services[v.service];if(!A)continue;let O=p[v.service];if([v.instance?be(A.instances?.[v.instance]?.provider):void 0,be(A.provider),O!==void 0?be(c.modules?.[O]?.provider):void 0,be(c.provider)].filter(a=>typeof a=="string").some(a=>l.has(a)))continue;if(v.instance){let a=A.instances;if(!a||!(v.instance in a))continue;delete a[v.instance],m.push(`services.${v.service}.instances.${v.instance}`),Object.keys(a).length===0&&delete A.instances,Object.keys(A).length===0&&delete c.services[v.service]}else delete c.services[v.service],m.push(`services.${v.service}`)}}if(Object.keys(c.services).length===0&&delete c.services,m.length===0)return{removed:m,orphanCredentials:[]};let I=!c.provider&&Object.keys(c.services??{}).length===0&&Object.keys(c.config??{}).length===0&&Object.keys(c.configByInstance??{}).length===0&&!c.credentialRef&&Object.keys(c.credentialRefByInstance??{}).length===0&&(c.instances??[]).length===0&&c.defaultInstanceId==null&&Object.keys(c.modules??{}).length===0;if(!I&&(c.services??={},typeof t.module.parseIntegrationsConfig=="function"))try{t.module.parseIntegrationsConfig(c)}catch{return{removed:[],orphanCredentials:[],skipped:"validation-failed"}}let h=[];return I?Ht(n)&&Yt(n,{force:!0}):$(n,`${JSON.stringify(c,null,2)}
4
- `),h=te(e).map(v=>v.message),{removed:m,orphanCredentials:h}}function Ce(e,n){let r=e.modules.find(i=>i.id===n);if(r)return r;let t=e.modules.filter(i=>(i.descriptor.name??i.descriptor.id)===n);if(t.length===1)return t[0];throw t.length>1?new x("MODULE_NOT_FOUND",404,`模块展示名「${n}」命中多个模块:${t.map(i=>`${i.descriptor.name}(id=${i.id})`).join(" / ")}——请改用模块 id 寻址`):new x("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块(id / 展示名均未命中)`)}function Y(e,n,r){let t=new Set;for(let s of Object.values(e.catalog.providers))for(let l of Object.values(s))for(let p of l.services)t.add(p);if(e.vocabulary.includes(r)||Object.hasOwn(e.catalog.services,r)||t.has(r)||n.includes(r))return r;let i=[],o=s=>{i.includes(s)||i.push(s)};for(let s of e.vocabulary)(e.slotMeta[s]?.name??e.catalog.services[s]?.name)===r&&o(s);for(let[s,l]of Object.entries(e.catalog.services))l.name===r&&o(s);if(i.length===1)return i[0];throw i.length>1?new x("SERVICE_NOT_FOUND",404,`服务展示名「${r}」命中多个服务:${i.join(" / ")}——请改用服务 id 寻址`):new x("SERVICE_NOT_FOUND",404,`服务 ${r} 不在服务词汇(已装契约包 ∪ 已配置)`)}import{existsSync as zn,readFileSync as Jn}from"fs";import{join as re,resolve as Qt}from"path";import Xt from"ajv";var ue=["provider","config","configByInstance","credentialRef","credentialRefByInstance","instances","defaultInstanceId"],pe=["provider","config"];var q=re("config","integrations.json");function ie(e,n){if(e===n)return!0;if(Array.isArray(e)&&Array.isArray(n))return e.length!==n.length?!1:e.every((r,t)=>ie(r,n[t]));if(e&&n&&typeof e=="object"&&typeof n=="object"){let r=Object.keys(e),t=Object.keys(n);return r.length!==t.length?!1:r.every(i=>ie(e[i],n[i]))}return!1}function Oe(e,n){if(typeof e!="string"&&e&&typeof e=="object")for(let[r,t]of Object.entries(e)){if((r==="provider"||r==="instanceId")&&typeof t=="string"&&!z.test(t))throw new x("VALIDATION_FAILED",400,`${r} 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`${n}.${r}`]);Oe(t,`${n}.${r}`)}}function Ae(e,n,r){if(!(!e||typeof e!="object"||Array.isArray(e))){for(let t of Object.keys(e))if(!(r&&(t==="*"||t==="**"))&&!z.test(t))throw new x("VALIDATION_FAILED",400,`${n} 键 ${t} 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)——进凭据 stem 派生,防路径逃逸`,[n])}}function Un(e,n,r){if(r==="root"){let t=e.instances;Array.isArray(t)&&t.forEach((i,o)=>{let s=i&&typeof i=="object"?i.id:void 0;if(typeof s=="string"&&!z.test(s))throw new x("VALIDATION_FAILED",400,`instances[${o}].id 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`root.instances[${o}].id`])}),Ae(e.configByInstance,"root.configByInstance",!1),Ae(e.credentialRefByInstance,"root.credentialRefByInstance",!1)}else Ae(e.instances,"services.instances",!0);Ae(n.credentialsByInstance,"credentialsByInstance",!1)}function Ee(e,n){let r=re(e,q),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!zn(r))return null;try{return t(Jn(r,"utf8"))}catch{return null}}function He(e){let n=(e.instances??[]).map(r=>r.id);return n.length===0?[]:Be(e,n)}function er(e,n,r,t){let{catalog:i}=V(e,t),o=i.providers[n];if(!o)return;let s=new Set;for(let l of Object.values(o))(r===void 0||l.services.includes(r))&&s.add(l.credentialType);return s.size===1?[...s][0]:void 0}function Kn(e,n,r,t,i,o){if(typeof t.type!="string"||t.type.length===0)throw new x("VALIDATION_FAILED",400,"凭据 type 缺失或为空字符串",["credentials.type"]);let s=i??er(e,n,r,o);if(s!==void 0&&s!=="-"&&t.type!==s)throw new x("VALIDATION_FAILED",400,`凭据 type=${t.type} 与绑定 credentialType ${s} 不一致`,["credentials.type"]);if(r===void 0)return;let{serviceSchemas:l}=V(e,o),p=l[`${n}\0${r}`];if(!p?.credentialSchema)return;let c=Qt(p.packageDir,p.credentialSchema);if(zn(c))try{let I=new Xt({allErrors:!0}).compile(JSON.parse(Jn(c,"utf8")));if(!I({type:t.type,...t.values})){let h=(I.errors??[]).map(v=>`credentials.values.${String(v.instancePath||v.params?.missingProperty||"").replace(/^\//,"")}`);throw new x("VALIDATION_FAILED",400,"凭据字段校验失败(ajv 字段级)",h)}}catch(m){if(m instanceof x)throw m}}function Ye(e,n={}){let{onApplied:r,cache:t}=n;function i(c,m,I,h){let v=c!==null,A=m.length>0,O=!h&&v,f=!h&&A;O&&($(re(e,q),`${JSON.stringify(c,null,2)}
5
- `),t?.invalidate([re(e,q)]));let a=O||f;a&&I.push(...te(e));let g=a&&r!==void 0;g&&r?.();let w=[];return v&&w.push(q),A&&w.push(...m.map(S=>_(S.stem))),{written:a,restartScheduled:g,files:w,credentials:m,issues:I}}let o;async function s(){o=await T(e)}function l(c,m){return c.filter(I=>Array.isArray(I.path)).map(I=>{let h=I.path.map(String).join(".");return m!==""&&h.startsWith(m)&&h.length>m.length?h.slice(m.length):h}).filter(I=>I.length>0)}function p(c,m,I){let h=o;if(!h||!h.strictValidation||!h.module.parseIntegrationsConfig)throw new x("CONTRACTS_NOT_RESOLVED",503,"contracts 严格校验面不可用(需 ≥0.9)——写路径门控失败(工厂边缘断言应先行拦截)");try{h.module.parseIntegrationsConfig(c)}catch(v){throw v instanceof Error&&Array.isArray(v.issues)?new x("VALIDATION_FAILED",400,"节点 schema 校验失败",l(v.issues,I)):new x("VALIDATION_FAILED",400,v instanceof Error?v.message:String(v))}}return{warmup:s,applyApp(c,m={}){Oe(c,"root"),Un(c,m,"root");let I=[],h=Ee(e,t),v=h??{services:{}};h===null&&I.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let A={...v};for(let y of ue)y in c||delete A[y];for(let[y,b]of Object.entries(c))A[y]=b;let O=typeof A.provider=="string"?A.provider:"app",f=Wn(O,m.credentials,m.credentialsByInstance);for(let y of f)Kn(e,O,void 0,y.input,void 0,t);let a=f.find(y=>y.instanceId===void 0);if(m.credentials&&a&&(A.credentialRef=a.ref),m.credentialsByInstance){let y={...A.credentialRefByInstance??{}};for(let b of f)b.instanceId!==void 0&&(y[b.instanceId]=b.ref);A.credentialRefByInstance=y}let g=m.credentials!==void 0||m.credentialsByInstance!==void 0,w=ie(h,A);if(w&&!g)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:I};p(A,I,"");let S=m.dryRun===!0,u=Ge(e,f,S);return I.push(...He(A)),i(w?null:A,u,I,m.dryRun)},applyModule(c,m,I={}){Oe(m,"root");let{modules:h,catalog:v,ownership:A}=V(e,t),O=h.find(d=>d.id===c);if(!O)throw new x("MODULE_NOT_FOUND",404,`模块 ${c} 非已装模块`);if(!G({modules:h,catalog:v,ownership:A},O).writable)throw new x("VALIDATION_FAILED",400,`模块 ${c} 未声明任何 declare.owns——无模块级配置位(模块级 provider/config 作用于归属服务)`);let a=[],g=Ee(e,t);if(g===null&&Object.keys(m).length===0)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:a};g===null&&a.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let w=g??{services:{}},S={...w.modules??{}},u={...S[c]??{}};for(let d of Object.keys(m))if(!pe.includes(d))throw new x("VALIDATION_FAILED",400,`模块集成位仅接受 ${pe.join("/")} 键(收到 ${d})`,[d]);let y={...u};for(let d of pe){let R=m[d];R==null||R===""||typeof R=="object"&&!Array.isArray(R)&&Object.keys(R).length===0?delete y[d]:y[d]=R}Object.keys(y).length===0?delete S[c]:S[c]=y;let b={...w,modules:S};return ie(g,b)?{written:!1,restartScheduled:!1,files:[],credentials:[],issues:a}:(p(b,a,`modules.${c}.`),a.push(...He(b)),i(b,[],a,I.dryRun))},applyService(c,m,I={}){Oe(m,"root"),Un(m,I,"slot");let h=[],v=Ee(e,t);if(!le(V(e,t).vocabulary,Object.keys(v?.services??{}),c))throw new x("SERVICE_NOT_FOUND",404,`服务 ${c} 不在服务词汇(已装契约包 ∪ 已配置)`);v===null&&h.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let A=v??{services:{}},O={...A.services??{}},f={...A,services:O};O[c]={...m};let a=m.provider,g=a!==null&&typeof a=="object"?a:void 0,w=typeof a=="string"?a:typeof g?.provider=="string"?g.provider:"app",S=c.includes(".")?c.slice(0,c.indexOf(".")):c,u=Bn(w,c,S,I.credentials,I.credentialsByInstance);for(let M of u)Kn(e,w,c,M.input,typeof g?.credentialType=="string"?g.credentialType:void 0,t);let y=O[c],b=u.find(M=>M.instanceId===void 0);if(I.credentials&&b&&(y.credentialRef=b.ref),I.credentialsByInstance){let M={...y.instances??{}};for(let N of u){if(N.instanceId===void 0)continue;let j={...M[N.instanceId]??{}};j.credentialRef=N.ref,M[N.instanceId]=j}y.instances=M}let d=I.credentials!==void 0||I.credentialsByInstance!==void 0,R=ie(v,f);if(R&&!d)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:h};p(f,h,`services.${c}.`);let E=I.dryRun===!0,C=Ge(e,u,E);return h.push(...He(f)),i(R?null:f,C,h,I.dryRun)},deleteService(c){let m=[],I=Ee(e,t);if(!le(V(e,t).vocabulary,Object.keys(I?.services??{}),c))throw new x("SERVICE_NOT_FOUND",404,`服务 ${c} 不在服务词汇(已装契约包 ∪ 已配置)`);let h={...I?.services??{}};if(!(c in h))return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:m};delete h[c];let v={...I??{services:{}},services:h};$(re(e,q),`${JSON.stringify(v,null,2)}
6
- `),t?.invalidate([re(e,q)]),m.push(...te(e));let A=r!==void 0;return A&&r?.(),{written:!0,restartScheduled:A,files:[q],credentials:[],issues:m}}}}import{existsSync as nr}from"fs";import{join as tr}from"path";function qe(e){let n=tr(e,"config","integrations.json");if(nr(n))return{generated:!1,reason:"in-place",services:[]};let r=[];for(let o of V(e).modules)for(let s of o.descriptor.declare.providers?.slots??[])s.local===!0&&r.push({service:s.service,provider:s.provider,implementation:s.implementation});if(r.length===0)return{generated:!1,reason:"no-local-slots",services:[]};let t={},i=new Set(r.map(o=>o.provider));if(i.size===1){let[o]=i;for(let s of r)t[s.service]={};$(n,`${JSON.stringify({provider:o,services:t},null,2)}
1
+ import{a as Ve,b as T,c as De}from"./chunk-WUULQDOV.js";import{z as k}from"zod";var z=/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/,ft=k.object({cardType:k.string(),schemaVersion:k.number().optional()}),vn=k.object({route:k.string(),component:k.string()}),yn=k.object({route:k.string(),label:k.string().optional(),icon:k.string().optional(),order:k.number().optional()}),Sn=k.object({id:k.string(),range:k.string().optional(),required:k.boolean().default(!0)}),wn=k.object({service:k.string(),provider:k.string().regex(z,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:k.string(),credentialType:k.string(),local:k.boolean().optional(),configSchema:k.string().optional(),credentialSchema:k.string().optional()}),hn=k.object({service:k.string(),optional:k.boolean().default(!0),defaults:k.array(k.object({provider:k.string().regex(z,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:k.string()})).default([]),name:k.string().optional(),description:k.string().optional()}),Rn=k.object({service:k.string()}).strict(),In=k.object({id:k.string(),type:k.string()}),kn=k.object({schemaVersion:k.number().default(1),id:k.string(),name:k.string().optional(),description:k.string().optional(),hidden:k.boolean().optional(),version:k.string().default("0.0.0"),kind:k.enum(["platform","business","third-party"]).default("business"),risk:k.object({level:k.enum(["high","medium","low"]).default("low"),writeBoundary:k.enum(["sdk-enforced","source"]).default("source")}).default({}),distribution:k.object({defaultMode:k.enum(["hybrid","sdk","codegen","local"]).default("codegen")}).default({}),declare:k.object({handlers:k.array(k.string()).default([]),tools:k.array(k.string()).default([]),cards:k.array(ft).default([]),routes:k.array(k.string()).default([]),pages:k.array(vn).default([]),tabs:k.array(yn).default([]),providers:k.object({slots:k.array(wn).default([])}).default({}),owns:k.array(Rn).default([]),consumes:k.array(hn).default([]),resources:k.array(In).default([])}).default({}),dependencies:k.object({modules:k.array(Sn).default([])}).default({}),env:k.array(k.string()).default([])}).strict();function gt(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let n=[],r=e;"contributes"in r&&n.push("(root): manifest 旧键 `contributes` 已更名 `declare`(v6 声明面)——codegen 副本经 `module update --source` 重新生成 / sdk 模式升级模块包 / 手改两键");let t=r.declare;t&&typeof t=="object"&&!Array.isArray(t)&&"services"in t&&n.push("declare: manifest 旧键 `declare.services` 已更名 `declare.consumes`(消费关系定向化)——同上三路径升级"),!("id"in r)&&"name"in r&&n.push("(root): manifest 标识键 `name` 已更名 `id`(v7 词汇统一)——codegen 副本经 `module update --source` 重新生成 / sdk 模式升级模块包 / 手改两键");let i=t&&typeof t=="object"&&!Array.isArray(t)?t:void 0,o=Array.isArray(i?.consumes)&&i.consumes.some(s=>s!==null&&typeof s=="object"&&"title"in s);return("title"in r||o)&&n.push("(root): manifest 展示名键 `title` 已更名 `name`(v7 词汇统一;declare.consumes[].title 同步改 name)——同上三路径升级"),n}function se(e){let n=gt(e);if(n.length>0)return{ok:!1,errors:n,legacy:!0};let r=kn.safeParse(e);return r.success?{ok:!0,value:r.data}:{ok:!1,errors:r.error.issues.map(t=>`${t.path.join(".")||"(root)"}: ${t.message}`)}}var mt=/\$\$?\{([A-Z][A-Z0-9_]*)(?::-([^}]*))?\}/g;function bn(e){return JSON.stringify(e).slice(1,-1)}function Fe(e,n=process.env){let r=[],t=e.replace(mt,(i,o,s)=>{if(i.startsWith("$$"))return i.slice(1);let l=n[o];return l!==void 0?bn(l):s!==void 0?bn(s):(r.push(o),i)});return r.length>0?{missing:r}:{text:t,missing:[]}}import{mkdirSync as vt,existsSync as Cn,readFileSync as yt,writeFileSync as St}from"fs";import{dirname as wt,join as An}from"path";function ve(e){let n={};for(let[r,t]of Object.entries(e)){if(typeof t!="string"){n[r]=null;continue}n[r]=t.length<=4?"****":`${t.slice(0,2)}****`}return n}var x=class extends Error{code;httpStatus;fields;constructor(n,r,t,i){super(t),this.name="AppToolkitError",this.code=n,this.httpStatus=r,this.fields=i}};function J(e){return e.notes.length>0?e.notes[0]:e.version===null?"contracts 不可解析(未安装)——检查应用依赖安装后重试":e.strictValidation?e.ownershipBindingV6===!1?`contracts ${e.version??"(版本未知)"} 不支持 v6 modules 绑定形状(OWNERSHIP_BINDING_V6 标记缺席)——升级应用 @tbox.cn/app-contracts 依赖后可用`:"contracts workspace 源码态未构建——执行 pnpm --filter @tbox.cn/app-contracts build 后重试":`contracts ${e.version} 无严格校验面(需 ≥0.9.0)——升级应用 @tbox.cn/app-contracts 依赖后可用`}function ye(e,n){if(n!==void 0&&(n.includes("/")||n.includes("\\")||n.includes("..")))throw new x("VALIDATION_FAILED",400,`凭据 stem 派生输入含路径敌对字符(${e})——拒绝派生`)}function X(e){if(ye("provider",e.provider),ye("service",e.service),ye("instanceId",e.instanceId),ye("domain",e.domain),e.instanceId!==void 0){let n=e.domain??e.service??"global";return`${e.provider}-${e.instanceId}-${n}`}return e.service!==void 0?`${e.provider}-${e.service}`:`${e.provider}-global`}function ht(e){return`secret://${e}`}function _(e){return`config/credentials/${e}.json`}function ae(e,n){let r=An(e,_(n));if(!Cn(r))return null;try{let t=JSON.parse(yt(r,"utf8"));if(typeof t.type!="string")return null;let{type:i,...o}=t,s={};for(let[l,u]of Object.entries(o))typeof u=="string"&&(s[l]=u);return{type:i,values:s}}catch{return null}}function _e(e,n,r){let t=An(e,_(n)),i=Cn(t);return vt(wt(t),{recursive:!0}),St(t,`${JSON.stringify({type:r.type,...r.values},null,2)}
2
+ `,"utf8"),i}import{mkdirSync as Rt,renameSync as It,writeFileSync as kt}from"fs";import{dirname as bt}from"path";function $(e,n){En(bt(e));let r=`${e}.tmp-${process.pid}-${Date.now()}`;kt(r,n,"utf8"),It(r,e)}function En(e){Rt(e,{recursive:!0})}import{existsSync as F,readdirSync as Le,readFileSync as ee}from"fs";import{join as V}from"path";import{existsSync as Ct,readFileSync as On,mkdirSync as At,writeFileSync as Et}from"fs";import xn from"path";function Se(e){return xn.join(e,".tbox","app.json")}function Mn(e){let n=Se(e);if(!Ct(n))return null;try{let r=JSON.parse(On(n,"utf8")),t=r?.templateVersion;return typeof t!="string"||t.trim().length===0?null:{templateVersion:t.trim(),npmModules:Array.isArray(r?.npmModules)?r.npmModules:[]}}catch{return null}}function Ot(e,n){let r=Se(e);At(xn.dirname(r),{recursive:!0}),Et(r,`${JSON.stringify(n,null,2)}
3
+ `,"utf8")}function $e(e){let n=Mn(e);if(n===null)return null;let r=Se(e);try{let t=JSON.parse(On(r,"utf8"));return{...n,miniappContainers:Array.isArray(t?.miniappContainers)?t.miniappContainers:[]}}catch{return{...n,miniappContainers:[]}}}function xt(e,n){let r=e.npmModules.filter(t=>t.id!==n.id);return{...e,npmModules:[...r,n]}}function Mt(e,n){return{...e,npmModules:e.npmModules.filter(r=>r.id!==n)}}function jt(e,n){let r=(e.miniappContainers??[]).filter(t=>t.id!==n.id);return{...e,miniappContainers:[...r,n]}}function Tt(e,n,r){return{...e,npmModules:e.npmModules.map(t=>t.id===n?{...t,...r}:t)}}function jn(e){return/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)&&!e.includes("..")}function Nt(e,n){if(!jn(e))throw new Error(`非法模块 id "${e}"(来自 ${n}):仅允许小写字母/数字/中划线`)}function Tn(e){try{let n=JSON.parse(e);if(!Array.isArray(n.slots))return null;let r=n.slots.filter(i=>typeof i=="string"),t={};if(n.meta&&typeof n.meta=="object"&&!Array.isArray(n.meta))for(let[i,o]of Object.entries(n.meta)){if(!o||typeof o!="object"||Array.isArray(o))continue;let{name:s,description:l}=o,u={};typeof s=="string"&&s.length>0&&(u.name=s),typeof l=="string"&&l.length>0&&(u.description=l),(u.name!==void 0||u.description!==void 0)&&(t[i]=u)}return{slots:r,meta:t}}catch{return null}}function we(e,n){let r=t=>{try{let i=JSON.parse(t),o=se(i);if(o.ok)return{kind:"strict",id:o.value.id,version:o.value.version,descriptor:o.value,declare:o.value.declare};if(o.legacy)return{kind:"legacy",detail:o.errors.join("; ")};if(i&&typeof i=="object"&&"declare"in i){let s=i;return{kind:"loose",...typeof s.id=="string"?{id:s.id}:{},declare:{providers:s.declare?.providers,consumes:s.declare?.consumes}}}return null}catch{return null}};if(n)return n.read(e,r)??null;if(!F(e))return null;try{return r(ee(e,"utf8"))}catch{return null}}function Pt(e){let n=V(e,".tbox","app.json");if(!F(n))return[];try{let r=JSON.parse(ee(n,"utf8"));return Array.isArray(r.npmModules)?r.npmModules.filter(t=>!!t&&typeof t=="object"&&typeof t.id=="string"&&typeof t.package=="string"):[]}catch{return[]}}function Vt(e){let n=V(e,".tbox-dev.local"),r=V(n,"dev-manifest.json");if(!F(r))return[];try{let t=JSON.parse(ee(r,"utf8")),i=[];for(let[o,s]of Object.entries(t.redirects??{}))typeof s!="string"||!o.startsWith("@tbox.cn/app-")||i.push({pkg:o,dir:V(n,s)});return i}catch{return[]}}function Pn(e,n){let r=[],t=[e];for(let l of["apps","packages"]){let u=V(e,l);if(F(u))try{for(let d of Le(u,{withFileTypes:!0}))d.isDirectory()&&t.push(V(u,d.name))}catch{}}let i=new Set,o=(l,u,d)=>{let m=n?n.read(u,Tn):Tn(ee(u,"utf8"));m!=null&&r.push({dir:l,slots:m.slots,meta:m.meta,via:d})},s=V(e,"config","service-slots.json");F(s)&&o(e,s,"config-override");for(let l of t){let u=V(l,"node_modules","@tbox.cn");if(!F(u))continue;let d=[];try{d=Le(u)}catch{continue}for(let m of d){let y=V(u,m);if(i.has(y))continue;i.add(y);let R=V(y,"service-slots.json"),v=V(y,"src","service-slots.json");F(R)?o(y,R,"package"):F(v)&&o(y,v,"package")}}for(let l of t)for(let u of[V(l,"service-slots.json"),V(l,"src","service-slots.json")])F(u)&&o(l,u,"local");return r}function D(e,n){let r=[],t={providers:{},services:{},credentialTypes:{}},i={},o=[],s={},l=new Set,u=(a,g,h,w)=>{for(let p of a){let S=t.providers[p.provider]??={},b=S[p.implementation];b?b.services.includes(p.service)||b.services.push(p.service):(S[p.implementation]={provider:p.provider,implementation:p.implementation,credentialType:p.credentialType,owner:g,...w?.name?{name:w.name}:{},...w?.description?{description:w.description}:{},...p.local?{local:!0}:{},...p.configSchema?{configSchema:p.configSchema}:{},...p.credentialSchema?{credentialSchema:p.credentialSchema}:{},services:[p.service]},t.credentialTypes[p.credentialType]??={owner:g,packageDir:h,...p.credentialSchema?{credentialSchema:p.credentialSchema}:{}});let c=`${p.provider}\0${p.service}`;i[c]||(i[c]={...p.configSchema?{configSchema:p.configSchema}:{},...p.credentialSchema?{credentialSchema:p.credentialSchema}:{},packageDir:h})}},d=a=>a.kind==="strict"?{name:a.descriptor.name,description:a.descriptor.description}:void 0,m=(a,g)=>{for(let h of a){let w=s[h];w===void 0?s[h]=g:w!==g&&o.push({severity:"error",code:"OWNERSHIP_CONFLICT",module:g,message:`服务 ${h} 归属冲突:${w} 与 ${g} 均声明 owns(先声明 ${w} 胜出)——修正 manifest declare.owns 互斥`})}},y=(a,g)=>{a.kind==="legacy"&&o.push({severity:"error",code:"OLD_MANIFEST_KEY",module:g,message:`${g}:${a.detail}`})},R=a=>a.kind==="strict"||a.kind==="loose"?a.declare:null,v=(a,g)=>{let h=a.optional!==!1,w=a.defaults??[],p=t.services[a.service];if(p){p.optional=p.optional&&h;let S=new Set(p.defaults.map(b=>`${b.provider}\0${b.implementation}`));for(let b of w){let c=`${b.provider}\0${b.implementation}`;S.has(c)||(p.defaults.push(b),S.add(c))}p.owners.includes(g)||p.owners.push(g);return}t.services[a.service]={optional:h,defaults:[...w],...a.name?{name:a.name}:{},...a.description?{description:a.description}:{},owners:[g]}};for(let a of Pt(e)){if(l.has(a.id))continue;let g=V(e,"packages",a.id),h=V(e,"node_modules",...a.package.split("/")),w=we(V(g,"tbox.module.json"),n)??we(V(h,"tbox.module.json"),n);if(w?.kind==="legacy"){y(w,a.id),l.add(a.id);continue}if(!w)continue;l.add(a.id);let p=F(V(g,"tbox.module.json"))?g:h,S=R(w);w.kind==="strict"&&r.push({id:a.id,dir:p,pkg:a.mode==="sdk"?a.package:`@app/${a.id}`,descriptor:w.descriptor});let b=S?.providers?.slots??[];b.length&&u(b,a.package,p,d(w));let c=S?.consumes??[];for(let E of c)v(E,a.package);let I=w.kind==="strict"?w.descriptor.declare.owns:[];I.length&&m(I.map(E=>E.service),a.id)}for(let{pkg:a,dir:g}of Vt(e)){let h=we(V(g,"tbox.module.json"),n);if(h?.kind==="legacy"){y(h,a);continue}if(!h?.id||l.has(h.id))continue;l.add(h.id);let w=R(h),p=w?.providers?.slots??[];p.length&&u(p,a,g,d(h));let S=w?.consumes??[];for(let c of S)v(c,a);let b=h.kind==="strict"?h.descriptor.declare.owns:[];b.length&&m(b.map(c=>c.service),h.id)}let A=V(e,"packages");if(F(A)){let a=[];try{a=Le(A,{withFileTypes:!0}).filter(g=>g.isDirectory()).map(g=>g.name)}catch{}for(let g of a){if(l.has(g))continue;let h=V(A,g),w=we(V(h,"tbox.module.json"),n);if(w?.kind==="legacy"){y(w,g),l.add(g);continue}if(!w)continue;let p=w.id??g;if(l.has(p))continue;l.add(p);let S=R(w);w.kind==="strict"&&r.push({id:p,dir:h,pkg:`@app/${p}`,descriptor:w.descriptor});let b=S?.providers?.slots??[];b.length&&u(b,`@app/${p}`,h,d(w));let c=S?.consumes??[];for(let E of c)v(E,`@app/${p}`);let I=w.kind==="strict"?w.descriptor.declare.owns:[];I.length&&m(I.map(E=>E.service),p)}}let O=new Set,f={};for(let a of Pn(e,n)){for(let g of a.slots)O.add(g);for(let[g,h]of Object.entries(a.meta))f[g]===void 0&&(f[g]=h)}return{modules:r,catalog:t,serviceSchemas:i,vocabulary:[...O].sort(),slotMeta:f,ownership:s,declarationIssues:o}}function Nn(e,n,r){let t=V(e,"src",n,"index.ts");if(!F(t))return!1;try{let i=ee(t,"utf8");return new RegExp(`export\\s+const\\s+${r}\\b`).test(i)}catch{return!1}}function Dt(e){let n=V(e,"src","server","index.ts");if(!F(n))return"";try{return ee(n,"utf8")}catch{return""}}function Vn(e){return e.match(/declaration\s*:\s*\{[\s\S]*?moduleId\s*:\s*['"]([^'"]+)['"]/)?.[1]}function Ft(e){let n=[],r=D(e),t=$e(e),i=new Map;for(let o of t?.npmModules??[])i.set(o.id,o.mode);for(let o of r.modules){let s=i.get(o.id)??"local",l=Nn(o.dir,"server","serverModule"),u=o.descriptor.declare;n.push({id:o.id,pkg:s==="sdk"?o.pkg:`@app/${o.id}`,mode:s,hasServerEntry:l,hasClientEntry:Nn(o.dir,"client","clientModule"),hasCards:(u.cards?.length??0)>0,...l?{moduleId:Vn(Dt(o.dir))}:{}})}return n.sort((o,s)=>o.id.localeCompare(s.id))}function _t(e){return D(e).ownership}function L(e,n){let r=e?.modules?.[n]?.provider;if(typeof r=="string"&&r.length>0)return{provider:r,layer:"module"};let t=e?.provider;return typeof t=="string"&&t.length>0?{provider:t,layer:"app"}:{provider:null,layer:null}}function G(e,n){let r=(n.descriptor.declare.owns??[]).map(t=>t.service).sort();return r.length===0?{writable:!1,reason:"zero-ownership",ownedServices:[]}:{writable:!0,ownedServices:r}}function We(e,n){return[...new Set(Object.values(e.providers[n]??{}).flatMap(r=>r.services))].sort()}function H(e){if(!e||typeof e!="object")return!1;let n=Object.keys(e),r=new Set(["provider","credentialType","configSchema"]);if(!n.every(i=>r.has(i)))return!1;let t=e;return typeof t.provider=="string"&&t.provider.length>0&&typeof t.credentialType=="string"&&t.credentialType.length>0&&(t.configSchema===void 0||typeof t.configSchema=="string")}function Dn(e,n,r){return e==="*"||r.has(e)?null:{severity:"error",code:"INSTANCE_KEY_NOT_REGISTERED",instance:e,message:`integrations: ${n} 键 ${e} 不在 malls 白名单内(${[...r].join(", ")})`}}function Be(e,n){let r=new Set(n),t=[],i=(o,s)=>{let l=Dn(o,s,r);l&&t.push(l)};for(let o of Object.keys(e.configByInstance??{}))i(o,"configByInstance");for(let o of Object.keys(e.credentialRefByInstance??{}))i(o,"credentialRefByInstance");for(let[o,s]of Object.entries(e.services??{}))for(let l of Object.keys(s.instances??{}))i(l,`services.${o}.instances`);return t}function ne(e){let n=[],r=e.contracts,{integrations:t,suppliedProviders:i,demandedServices:o,supplies:s,malls:l,credentialSchemaMissing:u,vendorConfigKeys:d,vendorGlobalConfigKeys:m,vendorConfigSchemaMissing:y,credentialFileMissing:R,credentialFileType:v,realmSwitchHints:A,moduleResourceNeeds:O,ownership:f,installedModuleIds:a}=e,g=l?new Set(l):void 0;for(let c of A??[])n.push({severity:"warning",code:"REALM_SWITCH_HINT",message:c});let h=new Set(Object.keys(i).map(c=>c.slice(0,c.indexOf("\0"))).filter(c=>c.length>0)),w=(c,I,E,C)=>{if(typeof E?.provider=="string"&&typeof E.implementation=="string"&&E.provider&&E.implementation)return i[ce(E.provider,E.implementation)]?.credentialType;if(typeof I.provider=="string"&&typeof I.implementation=="string")return i[ce(I.provider,I.implementation)]?.credentialType;let M=I.provider?.credentialType;if(typeof M=="string")return M;if(!s)return;let N=C??Object.keys(I.instances??{})[0]??"",j=r.resolveEffectiveService(t,c,N,s,f);if(!(j.status!=="ok"||typeof j.effective.provider!="string"))return i[ce(j.effective.provider,j.effective.implementation)]?.credentialType};if(R||v)for(let[c,I]of Object.entries(t.services))for(let[E,C]of Object.entries(I.instances??{})){if(C.enabled===!1)continue;let M=C.credentialRef??I.credentialRef??t.credentialRefByInstance?.[E]??t.credentialRef;if(typeof M!="string"||!M.startsWith("secret://"))continue;let N=M.slice(9);R?.[N]===!0&&n.push({severity:"error",code:"CREDENTIAL_FILE_MISSING",service:c,instance:E,message:`integrations: 凭据文件缺失 ${N}(${c}@${E} effective ref=${M};档内 config/credentials/ 无此文件)`});let j=v?.[N];if(j){let P=w(c,I,C,E);P&&j!==P&&n.push({severity:"error",code:"CREDENTIAL_TYPE_MISMATCH",service:c,instance:E,message:`integrations: 凭据文件 ${N}.json type=${j} 与绑定 credentialType ${P} 不一致(${c}@${E}——transport 创建期将按 type 选策略)`})}}let p=(c,I)=>{if(!g)return;let E=Dn(c,I,g);E&&n.push(E)};for(let[c]of Object.entries(t.configByInstance??{}))p(c,"configByInstance");for(let[c]of Object.entries(t.credentialRefByInstance??{}))p(c,"credentialRefByInstance");let S=Object.entries(t.services).filter(([,c])=>c.instances==null||c.instances["*"]!=null).map(([c])=>c);if(S.length>0){let c=Object.entries(t.services).filter(([,I])=>I.instances!=null&&I.instances["*"]==null).map(([I])=>I);c.length>0&&n.push({severity:"warning",code:"WILDCARD_ALIGNMENT",message:`integrations: 激活形态不对称(通配:${S.join(", ")};显式键集:${c.join(", ")})——动态 mallId 将在显式键集槽上 INSTANCE_NOT_FOUND(provider 业务限制表达位),确认是否齐步`})}let b=r.normalizeInstances({instances:t.instances,defaultInstanceId:t.defaultInstanceId});b.instances.length>=2&&b.defaultInstanceId===null&&n.push({severity:"warning",code:"MULTI_INSTANCE_NO_DEFAULT",message:`integrations: ${b.instances.length} 个部署实例(${b.instances.map(c=>c.id).join(", ")})均无 defaultInstanceId——无 scope 参数访问将落全局会话(默认商圈不注入)`});for(let[c,I]of Object.entries(t.services)){if(!o[c]&&f?.[c]===void 0&&n.push({severity:"warning",code:"SLOT_NOT_DECLARED",service:c,message:`integrations: 服务槽 ${c} 无消费方声明(拼写错误或需求方未安装)——若为拆分前旧槽位词汇(member.main/parking.main/promotion.read/shopping-guide.main),参照 cookbook·app-config 槽位迁移配方展开为新槽`}),typeof I.provider=="string"?typeof I.implementation=="string"&&!i[ce(I.provider,I.implementation)]&&n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:c,message:`integrations: provider ${I.provider}/${I.implementation} 未命中已装供给(${c} 槽级)——装对应 provider 包或改绑`}):I.provider!==void 0&&!H(I.provider)&&n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:c,message:`integrations: 内联 provider 超受控形状(${c} 槽级;允许键 provider/credentialType/configSchema)`}),u){let C=w(c,I);C&&u[C]===!0&&n.push({severity:"error",code:"SCHEMA_FILE_MISSING",service:c,message:`integrations: credentialType ${C} 的 schema 引用不存在(${c};manifest 声明指向缺失文件)`})}typeof I.provider=="object"&&typeof I.implementation!="string"&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:c,message:`integrations: 内联厂商声明必须同时提供 implementation(${c} 槽级)`});for(let[C,M]of Object.entries(I.instances??{})){p(C,`services.${c}.instances`);let N=M.provider!==void 0,j=M.implementation!==void 0;if(j&&!N&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:c,instance:C,message:`integrations: 实例级 implementation 需伴随 provider(${c}@${C}——impl-only 禁止,provider 是绑定组头)`}),N&&j){let P=M.provider,W=M.implementation;typeof P=="string"&&typeof W=="string"?i[ce(P,W)]||n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:c,instance:C,message:`integrations: 实例级 provider 覆盖 ${P}/${W} 未命中已装供给(${c}@${C})`}):H(P)||n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:c,instance:C,message:`integrations: 实例级内联 provider 超受控形状(${c}@${C})`})}}}for(let[c,I]of[["root",t.provider],...Object.entries(t.modules??{}).map(([E,C])=>[`modules.${E}`,C?.provider])])typeof I!="string"||I.length===0||h.has(I)||n.push({severity:"error",code:"VENDOR_NOT_INSTALLED",module:c.startsWith("modules.")?c.slice(8):void 0,message:`integrations: ${c} provider ${I} 未命中已装供给——装对应 provider 包或 provider use 改绑`});if(s)for(let[c,I]of Object.entries(t.services)){let E=I.instances?Object.keys(I.instances):[""];for(let C of E){let M=r.resolveEffectiveService(t,c,C,s,f);M.status==="binding-unresolved"&&n.push({severity:"error",code:"BINDING_UNRESOLVED",service:c,instance:C||void 0,message:`integrations: ${M.message}`})}}for(let[c,I]of Object.entries(t.services))I.implementation!==void 0&&I.provider===void 0&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:c,message:`integrations: 槽级 implementation 需伴随 provider(${c}——impl-only 禁止,provider 是绑定组头)`});for(let[c,I]of Object.entries(t.modules??{})){if(!(I?.provider!==void 0||I?.config!==void 0))continue;let C=a?!a.has(c):!1,M=0;if(f)for(let j of Object.values(f))j===c&&(M+=1);if(C||!(f===void 0)&&M===0){let j=C?"未安装(键 = install id)":"未声明任何 owns(无模块级配置位)";n.push({severity:"error",code:"MODULE_CONFIG_DEAD",module:c,message:`integrations: modules.${c} 携带 provider/config 但模块${j}(MODULE_CONFIG_DEAD——模块级集成位作用于 declare.owns 服务,改 declare.owns 或删除该节点)`})}}if(d){let c=new Set,I=!1,E=C=>{typeof C!="string"||C.length===0||(d[C]&&c.add(C),!d[C]&&!y?.[C]&&(I=!0),y?.[C]&&(I=!0))};E(t.provider);for(let C of Object.values(t.modules??{}))E(C?.provider);for(let C of Object.values(t.services)){let M=C.provider;E(typeof C.provider=="string"?C.provider:M?.provider)}if(c.size>0&&!I){let C=new Set;for(let j of c)for(let P of d[j]??[])C.add(P);let M=new Set;for(let j of c)for(let P of m?.[j]??[])M.add(P);let N=(j,P,W,q)=>{for(let[Q]of Object.entries(j??{}))(W??C).has(Q)?q&&q.size>0&&!q.has(Q)&&n.push({severity:"warning",code:"GLOBAL_FIELD_UNDECLARED",message:`integrations: ${P} 键 ${Q} 过 schema 校验但未声明 x-tbox-global(不进应用/模块全局表单;已配置值照常生效——如需全局编辑请在 provider schema 标记)`}):n.push({severity:"error",code:"DOMAIN_CONFIG_INVALID",message:`integrations: ${P} 键 ${Q} 不在引用厂商(${[...c].join("/")})任何槽 schema properties 内(死配置)`})};N(t.config,"root.config",void 0,M);for(let[j,P]of Object.entries(t.configByInstance??{}))N(P,`root.configByInstance[${j}]`,void 0,M);for(let[j,P]of Object.entries(t.modules??{})){if(!P?.config)continue;let W=L(t,j).provider??void 0;if(W===void 0){N(P.config,`modules.${j}.config`,void 0,M);continue}let q=d[W];if(!q||y?.[W])continue;let Q=m?.[W];N(P.config,`modules.${j}.config`,new Set(q),Q)}}}for(let[c,I]of Object.entries(o)){let E=t.services[c];if(!E){n.push({severity:"warning",code:"SLOT_NOT_CONFIGURED",service:c,message:`integrations: 服务槽 ${c}(需求方 ${I.owners.join(", ")})未配置${I.optional?"(可选槽)":"(必需槽——模块将走降级链)"}`});continue}let C=Object.entries(E.instances??{}).filter(([,M])=>M.enabled===!1).map(([M])=>M);C.length>0&&n.push({severity:"warning",code:"INSTANCE_DISABLED",service:c,instance:C.join(", "),message:`integrations: ${c} 实例禁用(${C.join(", ")})`})}for(let[c,I]of Object.entries(t.modules??{})){let E=O?.[c];O&&!(c in O)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:c,message:`integrations: modules.${c} 未命中已装模块(键 = install id——检查 .tbox/app.json entry.id / packages/ 目录名)`});for(let[C,M]of Object.entries(I?.resources??{})){let N=M?.type;(typeof N!="string"||!r.RESOURCE_TYPE_IDS.includes(N))&&n.push({severity:"error",code:"RESOURCE_TYPE_UNKNOWN",module:c,message:`integrations: modules.${c}.resources.${C} type 非法(${String(N)};词汇表 = ${r.RESOURCE_TYPE_IDS.join("/")})`}),E&&E.size>0&&!E.has(C)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:c,message:`integrations: modules.${c}.resources.${C} 未被模块 manifest declare.resources 声明`})}}return n}function ce(e,n){return`${e}\0${n}`}import{existsSync as Ue,readFileSync as $t,readdirSync as Lt}from"fs";import{join as he}from"path";function _n(e){return e.replaceAll("-","_").toUpperCase()}function Fn(e){if(!Ue(e))return null;try{let n=JSON.parse($t(e,"utf8"));return n&&typeof n=="object"?n:null}catch{return null}}function Wt(e){let n=new Set,r=e.properties;if(r&&typeof r=="object"&&!Array.isArray(r))for(let t of Object.keys(r))n.add(t);return n}function de(e,n,r,t=process.env){let i={};for(let[p,S]of Object.entries(n.catalog.providers))for(let[b,c]of Object.entries(S))i[`${p}\0${b}`]={services:[...c.services],owner:c.owner,credentialType:c.credentialType};let o={};for(let[p,S]of Object.entries(n.catalog.services))o[p]={optional:S.optional,owners:[...S.owners]};let s={},l={},u={},d={},m={};for(let p of n.modules){m[p.id]=new Set((p.descriptor.declare.resources??[]).map(S=>S.id));for(let S of p.descriptor.declare.providers?.slots??[]){if(S.configSchema){let b=Fn(he(p.dir,S.configSchema));if(b){let c=s[S.provider]??=new Set,I=l[S.provider]??=new Set;for(let C of Wt(b))c.add(C);let E=b.properties;if(E&&typeof E=="object"&&!Array.isArray(E))for(let[C,M]of Object.entries(E))M&&typeof M=="object"&&M["x-tbox-global"]===!0&&I.add(C)}else u[S.provider]=!0}S.credentialSchema&&!Ue(he(p.dir,S.credentialSchema))&&(d[S.credentialType]=!0)}}let y={},R=new Set,v=he(e,"config","credentials");if(Ue(v))for(let p of Lt(v)){if(!p.endsWith(".json"))continue;let S=p.slice(0,-5);R.add(S);let b=Fn(he(v,p));b&&typeof b.type=="string"&&(y[S]=b.type)}let A=r,O=[],f=p=>{typeof p=="string"&&p.startsWith("secret://")&&O.push(p)};for(let p of Object.values(A.services??{}))if(p&&typeof p=="object"){f(p.credentialRef);for(let S of Object.values(p.instances??{}))S&&typeof S=="object"&&f(S.credentialRef)}for(let p of Object.values(A.credentialRefByInstance??{}))f(p);f(A.credentialRef);let a={};for(let p of O){let S=p.slice(9);t[_n(S)]===void 0&&(R.has(S)||(a[S]=!0))}let g=[];for(let[p,S]of Object.entries(A.services??{})){let b=S&&typeof S=="object"&&typeof S.provider=="string"?S.provider:void 0;for(let[c,I]of Object.entries((S&&typeof S=="object"?S.instances:void 0)??{})){let E=I&&typeof I=="object"&&typeof I.provider=="string"?I.provider:void 0;b&&E&&E!==b&&g.push(`integrations: ${p}@${c} 实现覆盖跨厂商(${b} → ${E})——凭据域切换,确认该 mall 对应凭据在场`)}}let w=((Array.isArray(A.instances)?A.instances:void 0)??[]).map(p=>p&&typeof p=="object"&&typeof p.id=="string"?p.id:void 0).filter(p=>typeof p=="string");return{suppliedProviders:i,demandedServices:o,credentialFileMissing:a,credentialFileType:y,credentialSchemaMissing:d,vendorConfigKeys:s,vendorGlobalConfigKeys:l,vendorConfigSchemaMissing:u,realmSwitchHints:g,moduleResourceNeeds:m,...w.length>0?{malls:w}:{},ownership:n.ownership,installedModuleIds:new Set([...n.modules.map(p=>p.id),...new Set(Object.values(n.ownership))])}}import{existsSync as ti,readFileSync as ri}from"fs";import{join as oi,resolve as si}from"path";function Ke(e){return D(e).catalog}function Re(e){let n=D(e).catalog,r={};for(let[o,s]of Object.entries(n.providers)){r[o]={};for(let[l,u]of Object.entries(s))r[o][l]={provider:u.provider,implementation:u.implementation,credentialType:u.credentialType,owner:u.owner,...u.local?{local:!0}:{},...u.configSchema?{configSchema:u.configSchema}:{},...u.credentialSchema?{credentialSchema:u.credentialSchema}:{},services:[...u.services]}}let t={};for(let[o,s]of Object.entries(n.services))t[o]={optional:s.optional,defaults:s.defaults.map(l=>({...l})),owners:[...s.owners]};let i={};for(let[o,s]of Object.entries(n.credentialTypes))i[o]={owner:s.owner,...s.credentialSchema?{credentialSchema:s.credentialSchema}:{}};return{providers:r,services:t,credentialTypes:i}}async function ze(e,n,r,t=process.env){let i=r.module,o=D(e),s=i.buildSupplyLookup(Re(e)),l=de(e,o,n,t);return ne({contracts:i,integrations:n,supplies:s,...l})}import{existsSync as Ht,rmSync as Yt}from"fs";import{join as Zt}from"path";import{existsSync as Bt,readFileSync as Ut}from"fs";import{join as $n}from"path";var Kt=$n("config","integrations.json");function B(e,n){let r=$n(e,Kt),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!Bt(r))return null;try{return t(Ut(r,"utf8"))}catch{return null}}async function Ln(e,n){let r=await T(e),t=B(e,n);if(t===null)return{config:null,strict:!1,contracts:r};if(r.strictValidation&&r.module.parseIntegrationsConfig)try{return{config:r.module.parseIntegrationsConfig(t),strict:!0,contracts:r}}catch(i){if(i instanceof Error&&Array.isArray(i.issues)){let o=i.issues.filter(s=>Array.isArray(s.path)).map(s=>s.path.map(String).join(".")).filter(s=>s.length>0);throw new x("VALIDATION_FAILED",400,"integrations.json 校验失败",o.length>0?o:void 0)}throw new x("VALIDATION_FAILED",400,i instanceof Error?i.message:String(i))}return{config:t,strict:!1,contracts:r}}function le(e,n,r,t){return e.includes(r)||n.includes(r)||t.includes(r)}import{readdirSync as zt,existsSync as Ie,readFileSync as Jt}from"fs";import{join as ke}from"path";function Wn(e,n,r){let t=[];if(n){let i=X({provider:e});t.push({stem:i,ref:`secret://${i}`,input:n})}for(let[i,o]of Object.entries(r??{})){let s=X({provider:e,instanceId:i});t.push({instanceId:i,stem:s,ref:`secret://${s}`,input:o})}return t}function Bn(e,n,r,t,i){let o=[];if(t){let s=X({provider:e,service:n});o.push({stem:s,ref:`secret://${s}`,input:t})}for(let[s,l]of Object.entries(i??{})){let u=X({provider:e,instanceId:s,domain:r});o.push({instanceId:s,stem:u,ref:`secret://${u}`,input:l})}return o}function Ge(e,n,r){return n.map(t=>({stem:t.stem,ref:t.ref,overwrote:r?Ie(ke(e,_(t.stem))):_e(e,t.stem,t.input)}))}function Gt(e,n){return Ie(ke(e,_(n)))}function Je(e,n){if(typeof e=="string"){e.startsWith("secret://")&&n.add(e.slice(9));return}if(Array.isArray(e)){for(let r of e)Je(r,n);return}if(e&&typeof e=="object")for(let r of Object.values(e))Je(r,n)}function te(e){let n=ke(e,"config","credentials"),r=new Set,t=ke(e,"config","integrations.json");if(Ie(t))try{Je(JSON.parse(Jt(t,"utf8")),r)}catch{}let i=[];if(!Ie(n))return i;let o=[];try{o=zt(n).filter(s=>s.endsWith(".json")).map(s=>s.slice(0,-5))}catch{return i}for(let s of o.sort()){if(r.has(s))continue;let l=ae(e,s);i.push({severity:"warning",code:"ORPHANED_CREDENTIAL",message:`${_(s)} 不再被引用(凭据文件保留,可手动清理)`})}return i}function be(e){if(typeof e=="string")return e.length>0?e:void 0;if(e&&typeof e=="object"&&H(e)){let n=e.provider;return n.length>0?n:void 0}}async function qt(e){let n=Zt(e,"config","integrations.json"),r=B(e);if(r===null)return{removed:[],orphanCredentials:[],skipped:"not-configured"};let t=await T(e);if(!t.strictValidation)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};let i;try{let v=Fe(JSON.stringify(r),process.env);if(v.missing.length>0||v.text===void 0)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};i=JSON.parse(v.text)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let o;try{o=await ze(e,i,t,process.env)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let s=D(e),l=new Set(Object.keys(s.catalog.providers)),u=s.ownership,d=structuredClone(r);d.services??={};let m=[];for(let v of o)if(v.severity==="error"){if(v.code==="VENDOR_NOT_INSTALLED")if(v.module){let O=(d.modules??{})[v.module];O?.provider&&(m.push(`modules.${v.module}.provider=${String(O.provider)}`),delete O.provider,Object.keys(O).length===0&&delete d.modules[v.module])}else d.provider&&(m.push(`root.provider=${d.provider}`),delete d.provider);else if(v.code==="MODULE_CONFIG_DEAD"&&v.module){let A=d.modules??{};if(A[v.module]){let O=A[v.module],f=[O.provider!==void 0?"provider":void 0,O.config!==void 0?"config":void 0,O.resources!==void 0?"resources":void 0].filter(Boolean);m.push(`modules.${v.module}(${f.join("+")} 整节点)`),delete d.modules[v.module]}}else if(v.code==="BINDING_UNRESOLVED"&&v.service){let A=d.services[v.service];if(!A)continue;let O=u[v.service];if([v.instance?be(A.instances?.[v.instance]?.provider):void 0,be(A.provider),O!==void 0?be(d.modules?.[O]?.provider):void 0,be(d.provider)].filter(a=>typeof a=="string").some(a=>l.has(a)))continue;if(v.instance){let a=A.instances;if(!a||!(v.instance in a))continue;delete a[v.instance],m.push(`services.${v.service}.instances.${v.instance}`),Object.keys(a).length===0&&delete A.instances,Object.keys(A).length===0&&delete d.services[v.service]}else delete d.services[v.service],m.push(`services.${v.service}`)}}if(Object.keys(d.services).length===0&&delete d.services,m.length===0)return{removed:m,orphanCredentials:[]};let y=!d.provider&&Object.keys(d.services??{}).length===0&&Object.keys(d.config??{}).length===0&&Object.keys(d.configByInstance??{}).length===0&&!d.credentialRef&&Object.keys(d.credentialRefByInstance??{}).length===0&&(d.instances??[]).length===0&&d.defaultInstanceId==null&&Object.keys(d.modules??{}).length===0;if(!y&&(d.services??={},typeof t.module.parseIntegrationsConfig=="function"))try{t.module.parseIntegrationsConfig(d)}catch{return{removed:[],orphanCredentials:[],skipped:"validation-failed"}}let R=[];return y?Ht(n)&&Yt(n,{force:!0}):$(n,`${JSON.stringify(d,null,2)}
4
+ `),R=te(e).map(v=>v.message),{removed:m,orphanCredentials:R}}function Ce(e,n){let r=e.modules.find(i=>i.id===n);if(r)return r;let t=e.modules.filter(i=>(i.descriptor.name??i.descriptor.id)===n);if(t.length===1)return t[0];throw t.length>1?new x("MODULE_NOT_FOUND",404,`模块展示名「${n}」命中多个模块:${t.map(i=>`${i.descriptor.name}(id=${i.id})`).join(" / ")}——请改用模块 id 寻址`):new x("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块(id / 展示名均未命中)`)}function Y(e,n,r){let t=new Set;for(let s of Object.values(e.catalog.providers))for(let l of Object.values(s))for(let u of l.services)t.add(u);if(e.vocabulary.includes(r)||Object.hasOwn(e.catalog.services,r)||t.has(r)||n.includes(r)||Object.hasOwn(e.ownership,r))return r;let i=[],o=s=>{i.includes(s)||i.push(s)};for(let s of e.vocabulary)(e.slotMeta[s]?.name??e.catalog.services[s]?.name)===r&&o(s);for(let[s,l]of Object.entries(e.catalog.services))l.name===r&&o(s);if(i.length===1)return i[0];throw i.length>1?new x("SERVICE_NOT_FOUND",404,`服务展示名「${r}」命中多个服务:${i.join(" / ")}——请改用服务 id 寻址`):new x("SERVICE_NOT_FOUND",404,`服务 ${r} 不在服务词汇(已装契约包 ∪ 已配置)`)}import{existsSync as zn,readFileSync as Jn}from"fs";import{join as re,resolve as Qt}from"path";import Xt from"ajv";var ue=["provider","config","configByInstance","credentialRef","credentialRefByInstance","instances","defaultInstanceId"],pe=["provider","config"];var Z=re("config","integrations.json");function ie(e,n){if(e===n)return!0;if(Array.isArray(e)&&Array.isArray(n))return e.length!==n.length?!1:e.every((r,t)=>ie(r,n[t]));if(e&&n&&typeof e=="object"&&typeof n=="object"){let r=Object.keys(e),t=Object.keys(n);return r.length!==t.length?!1:r.every(i=>ie(e[i],n[i]))}return!1}function Oe(e,n){if(typeof e!="string"&&e&&typeof e=="object")for(let[r,t]of Object.entries(e)){if((r==="provider"||r==="instanceId")&&typeof t=="string"&&!z.test(t))throw new x("VALIDATION_FAILED",400,`${r} 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`${n}.${r}`]);Oe(t,`${n}.${r}`)}}function Ae(e,n,r){if(!(!e||typeof e!="object"||Array.isArray(e))){for(let t of Object.keys(e))if(!(r&&(t==="*"||t==="**"))&&!z.test(t))throw new x("VALIDATION_FAILED",400,`${n} 键 ${t} 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)——进凭据 stem 派生,防路径逃逸`,[n])}}function Un(e,n,r){if(r==="root"){let t=e.instances;Array.isArray(t)&&t.forEach((i,o)=>{let s=i&&typeof i=="object"?i.id:void 0;if(typeof s=="string"&&!z.test(s))throw new x("VALIDATION_FAILED",400,`instances[${o}].id 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`root.instances[${o}].id`])}),Ae(e.configByInstance,"root.configByInstance",!1),Ae(e.credentialRefByInstance,"root.credentialRefByInstance",!1)}else Ae(e.instances,"services.instances",!0);Ae(n.credentialsByInstance,"credentialsByInstance",!1)}function Ee(e,n){let r=re(e,Z),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!zn(r))return null;try{return t(Jn(r,"utf8"))}catch{return null}}function He(e){let n=(e.instances??[]).map(r=>r.id);return n.length===0?[]:Be(e,n)}function er(e,n,r,t){let{catalog:i}=D(e,t),o=i.providers[n];if(!o)return;let s=new Set;for(let l of Object.values(o))(r===void 0||l.services.includes(r))&&s.add(l.credentialType);return s.size===1?[...s][0]:void 0}function Kn(e,n,r,t,i,o){if(typeof t.type!="string"||t.type.length===0)throw new x("VALIDATION_FAILED",400,"凭据 type 缺失或为空字符串",["credentials.type"]);let s=i??er(e,n,r,o);if(s!==void 0&&s!=="-"&&t.type!==s)throw new x("VALIDATION_FAILED",400,`凭据 type=${t.type} 与绑定 credentialType ${s} 不一致`,["credentials.type"]);if(r===void 0)return;let{serviceSchemas:l}=D(e,o),u=l[`${n}\0${r}`];if(!u?.credentialSchema)return;let d=Qt(u.packageDir,u.credentialSchema);if(zn(d))try{let y=new Xt({allErrors:!0}).compile(JSON.parse(Jn(d,"utf8")));if(!y({type:t.type,...t.values})){let R=(y.errors??[]).map(v=>`credentials.values.${String(v.instancePath||v.params?.missingProperty||"").replace(/^\//,"")}`);throw new x("VALIDATION_FAILED",400,"凭据字段校验失败(ajv 字段级)",R)}}catch(m){if(m instanceof x)throw m}}function Ye(e,n={}){let{onApplied:r,cache:t}=n;function i(d,m,y,R){let v=d!==null,A=m.length>0,O=!R&&v,f=!R&&A;O&&($(re(e,Z),`${JSON.stringify(d,null,2)}
5
+ `),t?.invalidate([re(e,Z)]));let a=O||f;a&&y.push(...te(e));let g=a&&r!==void 0;g&&r?.();let h=[];return v&&h.push(Z),A&&h.push(...m.map(w=>_(w.stem))),{written:a,restartScheduled:g,files:h,credentials:m,issues:y}}let o;async function s(){o=await T(e)}function l(d,m){return d.filter(y=>Array.isArray(y.path)).map(y=>{let R=y.path.map(String).join(".");return m!==""&&R.startsWith(m)&&R.length>m.length?R.slice(m.length):R}).filter(y=>y.length>0)}function u(d,m,y){let R=o;if(!R||!R.strictValidation||!R.module.parseIntegrationsConfig)throw new x("CONTRACTS_NOT_RESOLVED",503,"contracts 严格校验面不可用(需 ≥0.9)——写路径门控失败(工厂边缘断言应先行拦截)");try{R.module.parseIntegrationsConfig(d)}catch(v){throw v instanceof Error&&Array.isArray(v.issues)?new x("VALIDATION_FAILED",400,"节点 schema 校验失败",l(v.issues,y)):new x("VALIDATION_FAILED",400,v instanceof Error?v.message:String(v))}}return{warmup:s,applyApp(d,m={}){Oe(d,"root"),Un(d,m,"root");let y=[],R=Ee(e,t),v=R??{services:{}};R===null&&y.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let A={...v};for(let S of ue)S in d||delete A[S];for(let[S,b]of Object.entries(d))A[S]=b;let O=typeof A.provider=="string"?A.provider:"app",f=Wn(O,m.credentials,m.credentialsByInstance);for(let S of f)Kn(e,O,void 0,S.input,void 0,t);let a=f.find(S=>S.instanceId===void 0);if(m.credentials&&a&&(A.credentialRef=a.ref),m.credentialsByInstance){let S={...A.credentialRefByInstance??{}};for(let b of f)b.instanceId!==void 0&&(S[b.instanceId]=b.ref);A.credentialRefByInstance=S}let g=m.credentials!==void 0||m.credentialsByInstance!==void 0,h=ie(R,A);if(h&&!g)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:y};u(A,y,"");let w=m.dryRun===!0,p=Ge(e,f,w);return y.push(...He(A)),i(h?null:A,p,y,m.dryRun)},applyModule(d,m,y={}){Oe(m,"root");let{modules:R,catalog:v,ownership:A}=D(e,t),O=R.find(c=>c.id===d);if(!O)throw new x("MODULE_NOT_FOUND",404,`模块 ${d} 非已装模块`);if(!G({modules:R,catalog:v,ownership:A},O).writable)throw new x("VALIDATION_FAILED",400,`模块 ${d} 未声明任何 declare.owns——无模块级配置位(模块级 provider/config 作用于归属服务)`);let a=[],g=Ee(e,t);if(g===null&&Object.keys(m).length===0)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:a};g===null&&a.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let h=g??{services:{}},w={...h.modules??{}},p={...w[d]??{}};for(let c of Object.keys(m))if(!pe.includes(c))throw new x("VALIDATION_FAILED",400,`模块集成位仅接受 ${pe.join("/")} 键(收到 ${c})`,[c]);let S={...p};for(let c of pe){let I=m[c];I==null||I===""||typeof I=="object"&&!Array.isArray(I)&&Object.keys(I).length===0?delete S[c]:S[c]=I}Object.keys(S).length===0?delete w[d]:w[d]=S;let b={...h,modules:w};return ie(g,b)?{written:!1,restartScheduled:!1,files:[],credentials:[],issues:a}:(u(b,a,`modules.${d}.`),a.push(...He(b)),i(b,[],a,y.dryRun))},applyService(d,m,y={}){Oe(m,"root"),Un(m,y,"slot");let R=[],v=Ee(e,t),A=D(e,t);if(!le(A.vocabulary,Object.keys(v?.services??{}),d,Object.keys(A.ownership)))throw new x("SERVICE_NOT_FOUND",404,`服务 ${d} 不在服务词汇(已装契约包 ∪ 已配置 ∪ 归属)`);v===null&&R.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let O=v??{services:{}},f={...O.services??{}},a={...O,services:f};f[d]={...m};let g=m.provider,h=g!==null&&typeof g=="object"?g:void 0,w=typeof g=="string"?g:typeof h?.provider=="string"?h.provider:"app",p=d.includes(".")?d.slice(0,d.indexOf(".")):d,S=Bn(w,d,p,y.credentials,y.credentialsByInstance);for(let N of S)Kn(e,w,d,N.input,typeof h?.credentialType=="string"?h.credentialType:void 0,t);let b=f[d],c=S.find(N=>N.instanceId===void 0);if(y.credentials&&c&&(b.credentialRef=c.ref),y.credentialsByInstance){let N={...b.instances??{}};for(let j of S){if(j.instanceId===void 0)continue;let P={...N[j.instanceId]??{}};P.credentialRef=j.ref,N[j.instanceId]=P}b.instances=N}let I=y.credentials!==void 0||y.credentialsByInstance!==void 0,E=ie(v,a);if(E&&!I)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:R};u(a,R,`services.${d}.`);let C=y.dryRun===!0,M=Ge(e,S,C);return R.push(...He(a)),i(E?null:a,M,R,y.dryRun)},deleteService(d){let m=[],y=Ee(e,t),R=D(e,t);if(!le(R.vocabulary,Object.keys(y?.services??{}),d,Object.keys(R.ownership)))throw new x("SERVICE_NOT_FOUND",404,`服务 ${d} 不在服务词汇(已装契约包 ∪ 已配置 ∪ 归属)`);let v={...y?.services??{}};if(!(d in v))return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:m};delete v[d];let A={...y??{services:{}},services:v};$(re(e,Z),`${JSON.stringify(A,null,2)}
6
+ `),t?.invalidate([re(e,Z)]),m.push(...te(e));let O=r!==void 0;return O&&r?.(),{written:!0,restartScheduled:O,files:[Z],credentials:[],issues:m}}}}import{existsSync as nr}from"fs";import{join as tr}from"path";function Ze(e){let n=tr(e,"config","integrations.json");if(nr(n))return{generated:!1,reason:"in-place",services:[]};let r=[];for(let o of D(e).modules)for(let s of o.descriptor.declare.providers?.slots??[])s.local===!0&&r.push({service:s.service,provider:s.provider,implementation:s.implementation});if(r.length===0)return{generated:!1,reason:"no-local-slots",services:[]};let t={},i=new Set(r.map(o=>o.provider));if(i.size===1){let[o]=i;for(let s of r)t[s.service]={};$(n,`${JSON.stringify({provider:o,services:t},null,2)}
7
7
  `)}else{for(let o of r)t[o.service]={provider:o.provider,implementation:o.implementation};$(n,`${JSON.stringify({services:t},null,2)}
8
- `)}return{generated:!0,reason:"generated",services:r.map(o=>o.service).sort()}}import{existsSync as rr,readFileSync as ir}from"fs";import{join as Zn}from"path";function Gn(e,n){let r=V(e.appDir,e.cache),t=B(e.appDir,e.cache);return{appDir:e.appDir,walk:r,catalog:r.catalog,integrations:t,contracts:n,...e.cache?{cache:e.cache}:{}}}function Hn(e){let n=new Set;for(let r of e.modules){for(let t of r.descriptor.declare.owns??[])n.add(t.service);for(let t of r.descriptor.declare.consumes??[])n.add(t.service);for(let t of r.descriptor.declare.providers?.slots??[])n.add(t.service)}return n}function xe(e,n,r){let t=e.providers[n];return t?Object.values(t).some(i=>i.services.includes(r)):!1}function Yn(e,n){let r=[];for(let[t,i]of Object.entries(e.providers))Object.values(i).some(o=>o.services.includes(n))&&r.push(t);return r.sort()}function U(e,n){let r=e.slotMeta[n],t=e.catalog.services[n],i=r?.name??t?.name??n,o=r?.description??t?.description;return{name:i,...o!==void 0?{description:o}:{}}}var or=Zn("config","knowledge.json");function sr(e,n,r){let i=r[n]?.resources;if(!i||typeof i!="object"||Array.isArray(i))return null;let o=Zn(e.appDir,or),s={};if(rr(o))try{s=(e.cache?.read(o,c=>JSON.parse(c))??JSON.parse(ir(o,"utf8"))).knowledge_bases??{}}catch{s={}}let l={};for(let[p,c]of Object.entries(i)){if(!c||typeof c!="object"||Array.isArray(c))continue;let m=c,I=m.type==="knowledge"?"knowledge":String(m.type??"knowledge"),h=typeof m.datasetId=="string"&&m.datasetId!==""?m.datasetId:void 0,v=typeof m.ref=="string"&&m.ref!==""?m.ref:void 0,A=h??(v!==void 0&&typeof s[v]?.datasetId=="string"?s[v].datasetId:null),O={type:I,...h!==void 0?{datasetId:h}:{},...v!==void 0?{ref:v}:{},resolvedDatasetId:A,...typeof m.topK=="number"?{topK:m.topK}:{},...typeof m.scoreThreshold=="number"?{scoreThreshold:m.scoreThreshold}:{}};l[p]=O}return Object.keys(l).length>0?l:null}function qn(e){return e.replace(/^@tbox\.cn\/app-/,"").replace(/^@[^/]+\//,"")}function ar(e){return qn(e.id).startsWith("provider-")||qn(e.pkg).startsWith("provider-")}function Ze(e,n={}){return{modules:e.walk.modules.filter(t=>!ar(t)).filter(t=>n.includeHidden===!0||t.descriptor.hidden!==!0).map(t=>({id:t.id,name:t.descriptor.name??t.descriptor.id,description:t.descriptor.description??"",...t.descriptor.hidden===!0?{hidden:!0}:{}})).sort((t,i)=>t.id.localeCompare(i.id))}}function Qe(e,n){let r=e.walk.modules.find(c=>c.id===n);if(!r)throw new x("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块`);let t=(r.descriptor.declare.consumes??[]).map(c=>{let m=U(e.walk,c.service);return{service:c.service,name:m.name,...m.description!==void 0?{description:m.description}:{},required:c.optional===!1}}),i=G(e.walk,r),o=e.integrations?.modules??{},s=o[n],l=s?{...typeof s.provider=="string"?{provider:s.provider}:{},...s.config&&typeof s.config=="object"&&!Array.isArray(s.config)?{config:s.config}:{}}:null,p=L(e.integrations,n);return{name:r.descriptor.name??r.descriptor.id,description:r.descriptor.description??"",...r.descriptor.hidden===!0?{hidden:!0}:{},ownedServices:i.ownedServices,integration:l,resources:sr(e,n,o),binding:{provider:p.provider,layer:p.layer},configEditable:i.writable,services:t}}function Xe(e){let n=Hn(e.walk),r=e.walk.vocabulary.filter(o=>!n.has(o)).map(o=>{let s=U(e.walk,o);return{service:o,name:s.name,...s.description!==void 0?{description:s.description}:{},required:!1}}),t=e.integrations,i=null;if(t){let o={};for(let s of ue)s in t&&(o[s]=t[s]);i=o}return{services:r,integration:i}}function en(e,n){let r=e.integrations?.services??{},t=e.catalog.services[n];if(!le(e.walk.vocabulary,Object.keys(r),n))throw new x("SERVICE_NOT_FOUND",404,`服务 ${n} 不在服务词汇(已装契约包 ∪ 已配置)`);let i=r[n]??null,o=U(e.walk,n);return{service:n,name:o.name,...o.description!==void 0?{description:o.description}:{},required:t?!t.optional:!1,defaults:t?t.defaults.map(s=>({...s})):[],integration:i,suppliedBy:Yn(e.catalog,n)}}import{existsSync as et,readFileSync as nt,realpathSync as Qn}from"fs";import{isAbsolute as cr,join as dr,relative as lr,resolve as Xn,sep as ur}from"path";function nn(e){let n=[];for(let[r,t]of Object.entries(e.catalog.providers)){let i=Object.values(t);i.length!==0&&n.push({provider:r,local:i.every(o=>o.local===!0),owner:i[0].owner,...i[0].name?{name:i[0].name}:{},...i[0].description?{description:i[0].description}:{}})}return{providers:n.sort((r,t)=>r.provider.localeCompare(t.provider))}}function tn(e,n,r){let t=e.catalog.providers[n];if(!t)throw new x("PROVIDER_NOT_FOUND",404,`厂商 ${n} 不 ∈ catalog(内联声明厂商无包级档案——身份与表单经组合端点暴露)`);let i={};for(let s of Object.values(t))for(let l of s.services)(i[l]??={implementations:[]}).implementations.push({implementation:s.implementation,credentialType:s.credentialType});for(let[s,l]of Object.entries(i)){let p=U(e.walk,s);l.name=p.name,p.description!==void 0&&(l.description=p.description)}if(r?.has("integrationSchemas"))for(let[s,l]of Object.entries(i))l.integrationSchemas={configSchema:K(e,n,s)};let o=Object.values(t);return{provider:n,local:o.every(s=>s.local===!0),owner:o[0].owner,...o[0].name?{name:o[0].name}:{},...o[0].description?{description:o[0].description}:{},services:i}}function rn(e,n,r){let t=e.catalog.providers[n],i=e.integrations?.services??{},o=[];if(t)for(let c of Object.values(t))c.services.includes(r)&&o.push({implementation:c.implementation,credentialType:c.credentialType});let s=i[r]?.provider,l=s&&typeof s=="object"&&s.provider===n?s:void 0;if(o.length===0&&!l)throw t?new x("SUPPLY_NOT_FOUND",404,`厂商 ${n} 未供给服务 ${r}(AI 帮我实现流:PUT 显式绑定后实施)`):new x("PROVIDER_NOT_FOUND",404,`厂商 ${n} 完全未知(不 ∈ catalog 且无任何内联声明)`);o.length===0&&l&&o.push({implementation:i[r]?.implementation??`${n}-inline@1`,credentialType:l.credentialType});let p=K(e,n,r,l?s?.configSchema:void 0);return{provider:n,service:r,implementations:o,integrationSchemas:{configSchema:p}}}function K(e,n,r,t){let i=e.walk.serviceSchemas[`${n}\0${r}`];return i?on(e.appDir,i.packageDir,i.configSchema):typeof t=="string"?pr(e.appDir,t):null}function on(e,n,r){if(!r)return null;let t=dr(n,r);if(!et(t))return null;try{return JSON.parse(nt(t,"utf8"))}catch{return null}}function pr(e,n){let r=Xn(e,"config","schemas"),t=Xn(e,n),i=lr(r,t);if(i===""||i.startsWith("..")||cr(i))throw new x("VALIDATION_FAILED",400,"configSchema 引用必须落在 config/schemas/ 内(禁路径逃逸)",["provider.configSchema"]);if(!et(t))return null;let o,s;try{o=Qn(r),s=Qn(t)}catch{return null}if(s!==o&&!s.startsWith(o+ur))throw new x("VALIDATION_FAILED",400,"configSchema 引用经 symlink 逃逸出 config/schemas/(realpath 复核拒绝)",["provider.configSchema"]);try{return JSON.parse(nt(t,"utf8"))}catch{return null}}function Me(e){return{version:e.version,evaluation:e.evaluation,strictValidation:e.strictValidation,notes:[...e.notes]}}function tt(e,n,r){let t=e.integrations,i=t?.services?.[n],o=i?.instances?.[r]??i?.instances?.["*"];if(o&&o.provider!==void 0)return"instance";if(i?.provider!==void 0)return"service";let s=e.walk.ownership[n];return s!==void 0&&L(e.integrations,s).layer==="module"?"module":typeof t?.provider=="string"&&t.provider.length>0?"app":null}function rt(e,n,r,t,i){let o=n.resolveEffectiveService(e.integrations,r,t,i,e.walk.ownership);if(o.status==="ok"&&o.effective){let s=o.effective.provider,l=typeof s=="string"?s:String(s?.provider??"");return{status:"ok",provider:l,implementation:o.effective.implementation,effective:{provider:l,implementation:o.effective.implementation,...o.effective.config!==void 0?{config:{...o.effective.config}}:{},...o.effective.credentialRef!==void 0?{credentialRef:o.effective.credentialRef}:{},layer:tt(e,r,t)??"app"}}}return o.status==="binding-unresolved"?{status:"binding-unresolved",statusMessage:o.message}:{status:o.status}}function it(e){let n=e.contracts.module;if(!n.resolveEffectiveService||!n.normalizeInstances)throw new x("CONTRACTS_NOT_RESOLVED",503,"contracts 求值面缺席(契约包形态异常)——重新安装或升级应用 @tbox.cn/app-contracts 后重试");return n}function sn(e,n){let r=it(n),{integrations:t,catalog:i}=n,o=r.buildSupplyLookup(i),s=t,p=r.normalizeInstances({instances:s?.instances,defaultInstanceId:s?.defaultInstanceId}).defaultInstanceId??"*",c=rt(n,r,e,p,o),m=tt(n,e,p),I=n.integrations?.services?.[e]?.provider,h=c.provider??(typeof I=="string"?I:typeof I=="object"&&I?String(I.provider):void 0),v=new Set(Object.keys(n.catalog.providers)),A=h!==void 0&&v.has(h)?fr(n.catalog,h,e):void 0,O=i.services[e],f=O!==void 0?!O.optional:void 0,a=O?.owners[0];return{status:c.status,...c.statusMessage?{statusMessage:c.statusMessage}:{},...h!==void 0?{provider:h}:{},...h!==void 0&&m!==null?{layer:m}:{},...A!==void 0?{supplied:A}:{},...a!==void 0?{module:a}:{},...f!==void 0?{required:f}:{}}}function fr(e,n,r){return xe(e,n,r)}function ot(e){let n=new Set([...e.walk.vocabulary,...Object.keys(e.catalog.services)]),r=e.integrations?.services??{};for(let t of Object.keys(r))n.add(t);return[...n].sort()}function fe(e,n,r){let t={};for(let i of ot(e))r&&!r.includes(i)||(t[i]=sn(i,e));return{contracts:Me(e.contracts),resolutions:t,issues:n}}function an(e,n,r){let t=it(n),i=t.buildSupplyLookup(n.catalog),o=n.integrations,s=t.normalizeInstances({instances:o?.instances,defaultInstanceId:o?.defaultInstanceId}),l=s.instances.map(O=>O.id),p=n.integrations?.services?.[e],c=p?.instances?Object.keys(p.instances):void 0,I=st(c,l).map(O=>{let f=rt(n,t,e,O,i);return{instanceId:O,status:f.status,...f.statusMessage?{statusMessage:f.statusMessage}:{},...f.effective?{effective:f.effective}:{}}}),h=at(n,e,s.defaultInstanceId??"*"),A={...sn(e,n),instances:I,inheritance:h};return{contracts:Me(n.contracts),resolution:A,issues:r.filter(O=>O.service===e)}}function st(e,n){if(n.length>0){let r=[...n];return e?.includes("*")&&r.push("*"),r}return e!==void 0&&e.length>0?e.includes("*")?["*"]:e:[]}function at(e,n,r){let t=e.integrations,i=t?.services?.[n],o=i?.instances?.[r]??i?.instances?.["*"],s=e.walk.ownership[n],l=s!==void 0?L(t,s):{provider:null,layer:null};return[{layer:"app",...t?.provider?{provider:t.provider}:{}},{layer:"module",...l.layer==="module"&&l.provider?{provider:l.provider}:{}},{layer:"service",...typeof i?.provider=="string"?{provider:i.provider}:{},...i?.implementation?{implementation:i.implementation}:{}},{layer:"instance",...o?.provider?{provider:o.provider}:{},...o?.implementation?{implementation:o.implementation}:{}}]}function ge(e){return e.evaluation&&e.strictValidation&&e.ownershipBindingV6}function ct(e,n,r){let t=e.catalog.services[n];return{status:"evaluation-unavailable",statusMessage:r,...t?.owners[0]!==void 0?{module:t.owners[0]}:{},...t!==void 0?{required:!t.optional}:{}}}function je(e,n,r){let t=J(n),i={};for(let o of ot(e))r&&!r.includes(o)||(i[o]=ct(e,o,t));return{contracts:Me(n),resolutions:i,issues:[]}}function dt(e,n,r){let t=J(r),i={...ct(n,e,t),instances:gr(n,e),inheritance:at(n,e,mr(n))};return{contracts:Me(r),resolution:i,issues:[]}}function gr(e,n){let r=e.integrations?.services?.[n],t=e.integrations,i=Array.isArray(t?.instances)?t.instances.map(s=>s&&typeof s=="object"?s.id:void 0).filter(s=>typeof s=="string"):[],o=r?.instances?Object.keys(r.instances):void 0;return st(o,i).map(s=>({instanceId:s,status:"evaluation-unavailable"}))}function mr(e){let n=e.integrations;return typeof n?.defaultInstanceId=="string"&&n.defaultInstanceId.length>0?n.defaultInstanceId:"*"}function cn(e,n,r){if(n===null)return null;let t={};for(let i of r)t[i]={configSchema:K(e,n,i)};return{provider:n,services:t}}function oe(e){return e===null||typeof e!="object"?JSON.stringify(e??null):Array.isArray(e)?`[${e.map(oe).join(",")}]`:`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${oe(e[r])}`).join(",")}}`}var vr="\0no-enum";function yr(e){let n=e.enum;return Array.isArray(n)?`[${[...new Set(n.map(oe))].sort().join(",")}]`:vr}function Sr(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e.type;return n===void 0?null:oe(n)}function wr(e){let n=e.map(t=>Sr(t.subschema));if(n.some(t=>t===null)||new Set(n).size>1)return null;if(n[0]==='"object"'){let t=oe(e[0].subschema);return e.every(i=>oe(i.subschema)===t)?e[0].subschema:null}return new Set(e.map(t=>yr(t.subschema))).size===1?e[0].subschema:null}function Te(e,n){let r=[],t=!0,i=new Map;for(let[s,l]of Object.entries(e.services)){let p=l.configSchema;if(p===null){r.push(s);continue}if(!p||typeof p!="object"||Array.isArray(p))continue;let c=p;c.additionalProperties===!1&&(t=!1);let m=c.properties;if(!m||typeof m!="object"||Array.isArray(m))continue;let I=Array.isArray(c.required)?c.required:[];for(let h of Object.keys(m)){let v=i.get(h)??[];v.push({service:s,subschema:m[h],required:I.includes(h)}),i.set(h,v)}}let o=[];for(let[s,l]of i)o.push({key:s,schema:wr(l),sources:l.map(({service:p,required:c})=>({service:p,required:c})),global:l.some(p=>!!p.subschema&&typeof p.subschema=="object"&&p.subschema["x-tbox-global"]===!0)});return{provider:e.provider,schemaless:r,unsupplied:[...n?.unsupplied??[]],additionalPropertiesAllowed:t,fields:o}}function dn(e,n,r,t){let i=typeof t=="string"&&t.length>0?t:void 0;if(e==="app"){if(i!==void 0)return i;let l=n.integrations?.provider;return typeof l=="string"&&l.length>0?l:null}let o=n.walk.modules.find(l=>l.id===r);return!o||!G(n.walk,o).writable?null:i!==void 0?i:L(n.integrations,o.id).provider}var lt={integrationSchemas:null,integrationFieldRegistry:null};function ut(e){return{...e,fields:e.fields.filter(n=>n.global)}}function ln(e,n){let r=dn("app",e,void 0,n);if(r===null)return lt;let t=cn(e,r,We(e.catalog,r));return{integrationSchemas:t,integrationFieldRegistry:ut(Te(t))}}function un(e,n,r){let t=dn("module",e,n,r),i=e.walk.modules.find(p=>p.id===n);if(t===null||!i)return lt;let o=(i.descriptor.declare.owns??[]).map(p=>p.service),s=p=>xe(e.catalog,t,p),l=cn(e,t,o.filter(s));return{integrationSchemas:l,integrationFieldRegistry:ut(Te(l,{unsupplied:[...new Set(o.filter(p=>!s(p)))]}))}}function hr(e){return ln(e).integrationSchemas}function Rr(e,n){return un(e,n).integrationSchemas}function Ir(e,n){let r=e.walk.ownership[n];if(r!==void 0)return L(e.integrations,r).provider;let t=e.integrations?.provider;return typeof t=="string"&&t.length>0?t:null}function Ne(e,n,r){let t=typeof r=="string"&&r.length>0?r:void 0;if(t!==void 0)return{provider:t,configSchema:K(e,t,n)};let i=e.integrations?.services?.[n]?.provider;if(i===void 0||i===""){let o=Ir(e,n);return o===null?null:{provider:o,configSchema:K(e,o,n)}}if(typeof i=="string")return{provider:i,configSchema:K(e,i,n)};if(H(i)){let o=i;return{provider:o.provider,configSchema:K(e,o.provider,n,o.configSchema)}}return null}function pn(e,n,r){let t=Ne(e,n,r);if(t===null)return null;let i={provider:t.provider,services:{[n]:{configSchema:t.configSchema}}};return Te(i)}function me(e,n){if(n===void 0||!n.startsWith("secret://"))return;let r=n.slice(9),t=ae(e,r);if(t)return{type:t.type,ref:n,file:_(r),masked:ve(t.values)}}function fn(e){let n=e.integrations,r={credential:me(e.appDir,typeof n?.credentialRef=="string"?n.credentialRef:void 0)??null,byInstance:{}};for(let{id:i}of n?.instances??[]){let o=n?.credentialRefByInstance?.[i];o!==void 0&&(r.byInstance[i]=me(e.appDir,o)??null)}let t={};for(let[i,o]of Object.entries(n?.services??{})){let s={credential:me(e.appDir,o.credentialRef)??null,byInstance:{}};for(let[l,p]of Object.entries(o.instances??{}))s.byInstance[l]=me(e.appDir,p.credentialRef)??null;t[i]=s}return{app:r,services:t}}function gn(e,n){return{types:(n===void 0?Object.keys(e.catalog.credentialTypes):[...new Set(Object.values(e.catalog.providers[n]??{}).map(t=>t.credentialType))]).sort().map(t=>{let i=e.catalog.credentialTypes[t];return{credentialType:t,owner:i?.owner??"",credentialSchema:i?on(e.appDir,i.packageDir,i.credentialSchema):null}})}}import kr from"path";var br={app:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],module:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],provider:["integrationSchemas"],service:["integrationSchemas","integrationFieldRegistry"]};function Pe(e,n){if(!n||n.length===0)return new Set;let r=br[e],t=[...new Set(n)].filter(i=>!r.includes(i));if(t.length>0)throw new x("VALIDATION_FAILED",400,`include 含未知或不适用于本端点的键:${t.join("、")}(白名单:${r.join("、")})`,["include"]);return new Set(n)}var pt=["integrationSchemas","integrationFieldRegistry"];function mn(e,n,r){if(!(typeof n!="string"||n.length===0)&&!pt.some(t=>r.has(t)))throw new x("VALIDATION_FAILED",400,`参数 ${e} 需与表单 include 键(${pt.join("、")})同现——轴参仅重定向表单层双投影`,[e])}function Cr(e,n={}){let r=Ve(),t=Promise.resolve(),i={appDir:e,cache:r};function o(f){if(!f.strictValidation)throw new x("CONTRACTS_NOT_RESOLVED",503,J(f));if(!f.ownershipBindingV6)throw new x("CONTRACTS_NOT_RESOLVED",503,J(f))}function s(f){return Gn(i,f)}function l(f){let a=f.integrations?.services;return a&&typeof a=="object"?Object.keys(a):[]}async function p(){let f=await T(e),a=s(f),g=a.integrations;if(g===null)return[];let w={resolveEffectiveService:c(f.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:c(f.module.buildSupplyLookup,"buildSupplyLookup"),normalizeInstances:c(f.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:f.module.RESOURCE_TYPE_IDS??[]},S=de(e,a.walk,g,process.env);return ne({contracts:w,integrations:g,supplies:w.buildSupplyLookup(a.catalog),...S})}function c(f,a){if(typeof f!="function")throw new x("CONTRACTS_NOT_RESOLVED",503,`contracts 求值面 ${a} 缺席(形态异常)`);return f}function m(f){let a=t.then(f,f);return t=a.catch(()=>{}),a}let I={async loadModules(f){let a=await T(e);return Ze(s(a),f)},async loadModule(f,a){let g=Pe("module",a?.include);mn("moduleProvider",a?.moduleProvider,g);let w=await T(e),S=s(w),u=Ce(S.walk,f),y=Qe(S,u.id);if(g.has("serviceResolutions")&&(y.serviceResolutions=ge(w)?await p().then(b=>fe(S,b,y.services.map(d=>d.service))):je(S,w,y.services.map(b=>b.service))),g.has("integrationSchemas")||g.has("integrationFieldRegistry")){let b=un(S,u.id,a?.moduleProvider);g.has("integrationSchemas")&&(y.integrationSchemas=b.integrationSchemas),g.has("integrationFieldRegistry")&&(y.integrationFieldRegistry=b.integrationFieldRegistry)}return y},async loadApp(f){let a=Pe("app",f?.include);mn("appProvider",f?.appProvider,a);let g=await T(e),w=s(g),S=Xe(w);if(a.has("serviceResolutions")&&(S.serviceResolutions=ge(g)?await p().then(u=>fe(w,u)):je(w,g)),a.has("integrationSchemas")||a.has("integrationFieldRegistry")){let u=ln(w,f?.appProvider);a.has("integrationSchemas")&&(S.integrationSchemas=u.integrationSchemas),a.has("integrationFieldRegistry")&&(S.integrationFieldRegistry=u.integrationFieldRegistry)}return S},async loadService(f,a){let g=Pe("service",a?.include);mn("serviceProvider",a?.serviceProvider,g);let w=await T(e),S=s(w),u=Y(S.walk,l(S),f),y=en(S,u);return g.has("integrationSchemas")&&(y.integrationSchemas=Ne(S,u,a?.serviceProvider)),g.has("integrationFieldRegistry")&&(y.integrationFieldRegistry=pn(S,u,a?.serviceProvider)),y},async loadServiceResolutions(f){let a=await T(e),g=s(a);if(!ge(a))return je(g,a,f);let w=await p();return fe(g,w,f)},async loadServiceResolution(f){let a=await T(e),g=s(a),w=Y(g.walk,l(g),f);if(!ge(a))return dt(w,g,a);let S=await p();return an(w,g,S)},async loadProviders(){let f=await T(e);return nn(s(f))},async loadProvider(f,a){let g=Pe("provider",a?.include),w=await T(e);return tn(s(w),f,g)},async loadProviderService(f,a){let g=await T(e),w=s(g),S=Y(w.walk,l(w),a);return rn(w,f,S)},async loadCredentials(){let f=await T(e);return fn(s(f))},async loadCredentialTypes(f){let a=await T(e);return gn(s(a),f)}},h=Ye(e,{onApplied:n.onApplied,cache:r}),v={async writeAppIntegration(f,a){await h.warmup();let g=await T(e);return o(g),m(()=>h.applyApp(f,a))},async writeModuleIntegration(f,a,g){await h.warmup();let w=await T(e);return o(w),m(()=>{let S=Ce(s(w).walk,f);return h.applyModule(S.id,a,g)})},async writeServiceIntegration(f,a,g){await h.warmup();let w=await T(e);return o(w),m(()=>{let S=s(w),u=Y(S.walk,l(S),f);return h.applyService(u,a,g)})},async deleteServiceIntegration(f){await h.warmup();let a=await T(e);return o(a),m(()=>{let g=s(a),w=Y(g.walk,l(g),f);return h.deleteService(w)})}},A={invalidate(){r.invalidate(),De(e)},async resolveContracts(){return T(e)},walkManifests(){return O(e)},parseModuleDescriptor(f){return se(f)},loadProviderCatalogRaw(){return Ke(e)},async readIntegrationsConfig(){return B(e,r)},async writeIntegrationsConfig(f){await h.warmup();let a=await T(e);return o(a),m(()=>Ar(e,f,r))},async ensureMockBindings(){await h.warmup();let f=await T(e);return o(f),m(()=>qe(e))},async evaluateIntegrationServices(f){await h.warmup();let a=await T(e);o(a);let g={resolveEffectiveService:c(a.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:c(a.module.buildSupplyLookup,"buildSupplyLookup"),normalizeInstances:c(a.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:a.module.RESOURCE_TYPE_IDS??[]};return ne({...f,contracts:g})}};function O(f){return V(f,r)}return{...I,...v,...A}}function Ar(e,n,r){let t=kr.join(e,"config","integrations.json");$(t,`${JSON.stringify(n,null,2)}
9
- `),r.invalidate([t])}export{ue as APP_INTEGRATION_NODE_KEYS,x as AppToolkitError,pe as MODULE_INTEGRATION_NODE_KEYS,z as SAFE_NAME_PATTERN,Nt as assertValidModuleId,Te as buildIntegrationFieldRegistry,_t as buildOwnershipMap,de as buildPredicateAssembly,Be as checkInstanceKeys,Ft as collectDeclaredModules,J as contractsNotResolvedMessage,Cr as createAppToolkit,Ve as createFileCache,Ye as createWriteCore,Gt as credentialArtifactExists,ie as deepEqual,X as deriveStem,Pn as discoverContractPackages,me as echoForRef,En as ensureDir,qe as ensureMockBindings,ze as evaluateAppIntegrationIssues,ne as evaluateIntegrationServices,Fe as expandEnvVars,Vn as extractModuleIdFromSource,dn as formProviderOf,De as invalidateContractsResolver,H as isControlledInlineProvider,jn as isValidModuleId,hr as loadAppIntegrationSchemas,Xe as loadAppView,gn as loadCredentialTypesView,fn as loadCredentialsView,Qe as loadModuleDetailView,Rr as loadModuleIntegrationSchemas,Ze as loadModulesView,Re as loadProviderCatalog,Ke as loadProviderCatalogRaw,tn as loadProviderDetailView,rn as loadProviderServiceDetailView,nn as loadProvidersView,en as loadServiceDetailView,pn as loadServiceFieldRegistry,Ne as loadServiceIntegrationSchemas,an as loadServiceResolutionDetail,fe as loadServiceResolutionsView,Se as manifestPath,ve as maskCredentialValues,Sn as moduleDependencySchema,kn as moduleDescriptorSchema,G as moduleOwnershipWritable,vn as pageContribSchema,se as parseModuleDescriptor,We as providerFootprint,wn as providerSlotContribSchema,Zt as pruneIntegrationBindings,Mn as readAppManifest,$e as readAppManifestFull,ae as readCredentialFile,B as readIntegrationsConfig,Ln as readIntegrationsStrict,te as reconcileOrphanCredentials,_n as refToEnvKey,Mt as removeNpmModule,T as resolveContractsForApp,T as resolveContractsForAppExport,cn as resolveLayerIntegrationSchemas,L as resolveModuleBinding,Ce as resolveModuleKey,Y as resolveServiceKey,sn as resolveServiceSummary,In as resourceNeedContribSchema,hn as serviceConsumeContribSchema,Rn as serviceOwnContribSchema,_ as stemToFilePath,ht as stemToRef,yn as tabContribSchema,Tt as updateNpmModule,jt as upsertMiniappContainer,xt as upsertNpmModule,V as walkManifests,Ot as writeAppManifest,$ as writeAtomic,_e as writeCredentialFile};
8
+ `)}return{generated:!0,reason:"generated",services:r.map(o=>o.service).sort()}}import{existsSync as rr,readFileSync as ir}from"fs";import{join as qn}from"path";function Gn(e,n){let r=D(e.appDir,e.cache),t=B(e.appDir,e.cache);return{appDir:e.appDir,walk:r,catalog:r.catalog,integrations:t,contracts:n,...e.cache?{cache:e.cache}:{}}}function Hn(e){let n=new Set;for(let r of e.modules){for(let t of r.descriptor.declare.owns??[])n.add(t.service);for(let t of r.descriptor.declare.consumes??[])n.add(t.service);for(let t of r.descriptor.declare.providers?.slots??[])n.add(t.service)}return n}function xe(e,n,r){let t=e.providers[n];return t?Object.values(t).some(i=>i.services.includes(r)):!1}function Yn(e,n){let r=[];for(let[t,i]of Object.entries(e.providers))Object.values(i).some(o=>o.services.includes(n))&&r.push(t);return r.sort()}function U(e,n){let r=e.slotMeta[n],t=e.catalog.services[n],i=r?.name??t?.name??n,o=r?.description??t?.description;return{name:i,...o!==void 0?{description:o}:{}}}var or=qn("config","knowledge.json");function sr(e,n,r){let i=r[n]?.resources;if(!i||typeof i!="object"||Array.isArray(i))return null;let o=qn(e.appDir,or),s={};if(rr(o))try{s=(e.cache?.read(o,d=>JSON.parse(d))??JSON.parse(ir(o,"utf8"))).knowledge_bases??{}}catch{s={}}let l={};for(let[u,d]of Object.entries(i)){if(!d||typeof d!="object"||Array.isArray(d))continue;let m=d,y=m.type==="knowledge"?"knowledge":String(m.type??"knowledge"),R=typeof m.datasetId=="string"&&m.datasetId!==""?m.datasetId:void 0,v=typeof m.ref=="string"&&m.ref!==""?m.ref:void 0,A=R??(v!==void 0&&typeof s[v]?.datasetId=="string"?s[v].datasetId:null),O={type:y,...R!==void 0?{datasetId:R}:{},...v!==void 0?{ref:v}:{},resolvedDatasetId:A,...typeof m.topK=="number"?{topK:m.topK}:{},...typeof m.scoreThreshold=="number"?{scoreThreshold:m.scoreThreshold}:{}};l[u]=O}return Object.keys(l).length>0?l:null}function Zn(e){return e.replace(/^@tbox\.cn\/app-/,"").replace(/^@[^/]+\//,"")}function ar(e){return Zn(e.id).startsWith("provider-")||Zn(e.pkg).startsWith("provider-")}function qe(e,n={}){return{modules:e.walk.modules.filter(t=>!ar(t)).filter(t=>n.includeHidden===!0||t.descriptor.hidden!==!0).map(t=>({id:t.id,name:t.descriptor.name??t.descriptor.id,description:t.descriptor.description??"",...t.descriptor.hidden===!0?{hidden:!0}:{}})).sort((t,i)=>t.id.localeCompare(i.id))}}function Qe(e,n){let r=e.walk.modules.find(y=>y.id===n);if(!r)throw new x("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块`);let t=G(e.walk,r),i=new Set((r.descriptor.declare.consumes??[]).map(y=>y.service)),o=(y,R)=>{let v=U(e.walk,y);return{service:y,name:v.name,...v.description!==void 0?{description:v.description}:{},required:R}},s=[...(r.descriptor.declare.consumes??[]).map(y=>o(y.service,y.optional===!1)),...[...new Set(t.ownedServices)].filter(y=>!i.has(y)).map(y=>o(y,!1))],l=e.integrations?.modules??{},u=l[n],d=u?{...typeof u.provider=="string"?{provider:u.provider}:{},...u.config&&typeof u.config=="object"&&!Array.isArray(u.config)?{config:u.config}:{}}:null,m=L(e.integrations,n);return{name:r.descriptor.name??r.descriptor.id,description:r.descriptor.description??"",...r.descriptor.hidden===!0?{hidden:!0}:{},ownedServices:t.ownedServices,integration:d,resources:sr(e,n,l),binding:{provider:m.provider,layer:m.layer},configEditable:t.writable,services:s}}function Xe(e){let n=Hn(e.walk),r=e.walk.vocabulary.filter(o=>!n.has(o)).map(o=>{let s=U(e.walk,o);return{service:o,name:s.name,...s.description!==void 0?{description:s.description}:{},required:!1}}),t=e.integrations,i=null;if(t){let o={};for(let s of ue)s in t&&(o[s]=t[s]);i=o}return{services:r,integration:i}}function en(e,n){let r=e.integrations?.services??{},t=e.catalog.services[n];if(!le(e.walk.vocabulary,Object.keys(r),n,Object.keys(e.walk.ownership)))throw new x("SERVICE_NOT_FOUND",404,`服务 ${n} 不在服务词汇(已装契约包 ∪ 已配置 ∪ 归属)`);let i=r[n]??null,o=U(e.walk,n);return{service:n,name:o.name,...o.description!==void 0?{description:o.description}:{},required:t?!t.optional:!1,defaults:t?t.defaults.map(s=>({...s})):[],integration:i,suppliedBy:Yn(e.catalog,n)}}import{existsSync as et,readFileSync as nt,realpathSync as Qn}from"fs";import{isAbsolute as cr,join as dr,relative as lr,resolve as Xn,sep as ur}from"path";function nn(e){let n=[];for(let[r,t]of Object.entries(e.catalog.providers)){let i=Object.values(t);i.length!==0&&n.push({provider:r,local:i.every(o=>o.local===!0),owner:i[0].owner,...i[0].name?{name:i[0].name}:{},...i[0].description?{description:i[0].description}:{}})}return{providers:n.sort((r,t)=>r.provider.localeCompare(t.provider))}}function tn(e,n,r){let t=e.catalog.providers[n];if(!t)throw new x("PROVIDER_NOT_FOUND",404,`厂商 ${n} 不 ∈ catalog(内联声明厂商无包级档案——身份与表单经组合端点暴露)`);let i={};for(let s of Object.values(t))for(let l of s.services)(i[l]??={implementations:[]}).implementations.push({implementation:s.implementation,credentialType:s.credentialType});for(let[s,l]of Object.entries(i)){let u=U(e.walk,s);l.name=u.name,u.description!==void 0&&(l.description=u.description)}if(r?.has("integrationSchemas"))for(let[s,l]of Object.entries(i))l.integrationSchemas={configSchema:K(e,n,s)};let o=Object.values(t);return{provider:n,local:o.every(s=>s.local===!0),owner:o[0].owner,...o[0].name?{name:o[0].name}:{},...o[0].description?{description:o[0].description}:{},services:i}}function rn(e,n,r){let t=e.catalog.providers[n],i=e.integrations?.services??{},o=[];if(t)for(let d of Object.values(t))d.services.includes(r)&&o.push({implementation:d.implementation,credentialType:d.credentialType});let s=i[r]?.provider,l=s&&typeof s=="object"&&s.provider===n?s:void 0;if(o.length===0&&!l)throw t?new x("SUPPLY_NOT_FOUND",404,`厂商 ${n} 未供给服务 ${r}(AI 帮我实现流:PUT 显式绑定后实施)`):new x("PROVIDER_NOT_FOUND",404,`厂商 ${n} 完全未知(不 ∈ catalog 且无任何内联声明)`);o.length===0&&l&&o.push({implementation:i[r]?.implementation??`${n}-inline@1`,credentialType:l.credentialType});let u=K(e,n,r,l?s?.configSchema:void 0);return{provider:n,service:r,implementations:o,integrationSchemas:{configSchema:u}}}function K(e,n,r,t){let i=e.walk.serviceSchemas[`${n}\0${r}`];return i?on(e.appDir,i.packageDir,i.configSchema):typeof t=="string"?pr(e.appDir,t):null}function on(e,n,r){if(!r)return null;let t=dr(n,r);if(!et(t))return null;try{return JSON.parse(nt(t,"utf8"))}catch{return null}}function pr(e,n){let r=Xn(e,"config","schemas"),t=Xn(e,n),i=lr(r,t);if(i===""||i.startsWith("..")||cr(i))throw new x("VALIDATION_FAILED",400,"configSchema 引用必须落在 config/schemas/ 内(禁路径逃逸)",["provider.configSchema"]);if(!et(t))return null;let o,s;try{o=Qn(r),s=Qn(t)}catch{return null}if(s!==o&&!s.startsWith(o+ur))throw new x("VALIDATION_FAILED",400,"configSchema 引用经 symlink 逃逸出 config/schemas/(realpath 复核拒绝)",["provider.configSchema"]);try{return JSON.parse(nt(t,"utf8"))}catch{return null}}function Me(e){return{version:e.version,evaluation:e.evaluation,strictValidation:e.strictValidation,notes:[...e.notes]}}function tt(e,n,r){let t=e.integrations,i=t?.services?.[n],o=i?.instances?.[r]??i?.instances?.["*"];if(o&&o.provider!==void 0)return"instance";if(i?.provider!==void 0)return"service";let s=e.walk.ownership[n];return s!==void 0&&L(e.integrations,s).layer==="module"?"module":typeof t?.provider=="string"&&t.provider.length>0?"app":null}function rt(e,n,r,t,i){let o=n.resolveEffectiveService(e.integrations,r,t,i,e.walk.ownership);if(o.status==="ok"&&o.effective){let s=o.effective.provider,l=typeof s=="string"?s:String(s?.provider??"");return{status:"ok",provider:l,implementation:o.effective.implementation,effective:{provider:l,implementation:o.effective.implementation,...o.effective.config!==void 0?{config:{...o.effective.config}}:{},...o.effective.credentialRef!==void 0?{credentialRef:o.effective.credentialRef}:{},layer:tt(e,r,t)??"app"}}}return o.status==="binding-unresolved"?{status:"binding-unresolved",statusMessage:o.message}:{status:o.status}}function it(e){let n=e.contracts.module;if(!n.resolveEffectiveService||!n.normalizeInstances)throw new x("CONTRACTS_NOT_RESOLVED",503,"contracts 求值面缺席(契约包形态异常)——重新安装或升级应用 @tbox.cn/app-contracts 后重试");return n}function sn(e,n){let r=it(n),{integrations:t,catalog:i}=n,o=r.buildSupplyLookup(i),s=t,u=r.normalizeInstances({instances:s?.instances,defaultInstanceId:s?.defaultInstanceId}).defaultInstanceId??"*",d=rt(n,r,e,u,o),m=tt(n,e,u),y=n.integrations?.services?.[e]?.provider,R=d.provider??(typeof y=="string"?y:typeof y=="object"&&y?String(y.provider):void 0),v=new Set(Object.keys(n.catalog.providers)),A=R!==void 0&&v.has(R)?fr(n.catalog,R,e):void 0,O=i.services[e],f=O!==void 0?!O.optional:void 0,a=n.walk.ownership[e];return{status:d.status,...d.statusMessage?{statusMessage:d.statusMessage}:{},...R!==void 0?{provider:R}:{},...R!==void 0&&m!==null?{layer:m}:{},...A!==void 0?{supplied:A}:{},...a!==void 0?{module:a}:{},...f!==void 0?{required:f}:{}}}function fr(e,n,r){return xe(e,n,r)}function ot(e){let n=new Set([...e.walk.vocabulary,...Object.keys(e.catalog.services),...Object.keys(e.walk.ownership)]),r=e.integrations?.services??{};for(let t of Object.keys(r))n.add(t);return[...n].sort()}function fe(e,n,r){let t={};for(let i of ot(e))r&&!r.includes(i)||(t[i]=sn(i,e));return{contracts:Me(e.contracts),resolutions:t,issues:n}}function an(e,n,r){let t=it(n),i=t.buildSupplyLookup(n.catalog),o=n.integrations,s=t.normalizeInstances({instances:o?.instances,defaultInstanceId:o?.defaultInstanceId}),l=s.instances.map(O=>O.id),u=n.integrations?.services?.[e],d=u?.instances?Object.keys(u.instances):void 0,y=st(d,l).map(O=>{let f=rt(n,t,e,O,i);return{instanceId:O,status:f.status,...f.statusMessage?{statusMessage:f.statusMessage}:{},...f.effective?{effective:f.effective}:{}}}),R=at(n,e,s.defaultInstanceId??"*"),A={...sn(e,n),instances:y,inheritance:R};return{contracts:Me(n.contracts),resolution:A,issues:r.filter(O=>O.service===e)}}function st(e,n){if(n.length>0){let r=[...n];return e?.includes("*")&&r.push("*"),r}return e!==void 0&&e.length>0?e.includes("*")?["*"]:e:[]}function at(e,n,r){let t=e.integrations,i=t?.services?.[n],o=i?.instances?.[r]??i?.instances?.["*"],s=e.walk.ownership[n],l=s!==void 0?L(t,s):{provider:null,layer:null};return[{layer:"app",...t?.provider?{provider:t.provider}:{}},{layer:"module",...l.layer==="module"&&l.provider?{provider:l.provider}:{}},{layer:"service",...typeof i?.provider=="string"?{provider:i.provider}:{},...i?.implementation?{implementation:i.implementation}:{}},{layer:"instance",...o?.provider?{provider:o.provider}:{},...o?.implementation?{implementation:o.implementation}:{}}]}function ge(e){return e.evaluation&&e.strictValidation&&e.ownershipBindingV6}function ct(e,n,r){let t=e.catalog.services[n],i=e.walk.ownership[n];return{status:"evaluation-unavailable",statusMessage:r,...i!==void 0?{module:i}:{},...t!==void 0?{required:!t.optional}:{}}}function je(e,n,r){let t=J(n),i={};for(let o of ot(e))r&&!r.includes(o)||(i[o]=ct(e,o,t));return{contracts:Me(n),resolutions:i,issues:[]}}function dt(e,n,r){let t=J(r),i={...ct(n,e,t),instances:gr(n,e),inheritance:at(n,e,mr(n))};return{contracts:Me(r),resolution:i,issues:[]}}function gr(e,n){let r=e.integrations?.services?.[n],t=e.integrations,i=Array.isArray(t?.instances)?t.instances.map(s=>s&&typeof s=="object"?s.id:void 0).filter(s=>typeof s=="string"):[],o=r?.instances?Object.keys(r.instances):void 0;return st(o,i).map(s=>({instanceId:s,status:"evaluation-unavailable"}))}function mr(e){let n=e.integrations;return typeof n?.defaultInstanceId=="string"&&n.defaultInstanceId.length>0?n.defaultInstanceId:"*"}function cn(e,n,r){if(n===null)return null;let t={};for(let i of r)t[i]={configSchema:K(e,n,i)};return{provider:n,services:t}}function oe(e){return e===null||typeof e!="object"?JSON.stringify(e??null):Array.isArray(e)?`[${e.map(oe).join(",")}]`:`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${oe(e[r])}`).join(",")}}`}var vr="\0no-enum";function yr(e){let n=e.enum;return Array.isArray(n)?`[${[...new Set(n.map(oe))].sort().join(",")}]`:vr}function Sr(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e.type;return n===void 0?null:oe(n)}function wr(e){let n=e.map(t=>Sr(t.subschema));if(n.some(t=>t===null)||new Set(n).size>1)return null;if(n[0]==='"object"'){let t=oe(e[0].subschema);return e.every(i=>oe(i.subschema)===t)?e[0].subschema:null}return new Set(e.map(t=>yr(t.subschema))).size===1?e[0].subschema:null}function Te(e,n){let r=[],t=!0,i=new Map;for(let[s,l]of Object.entries(e.services)){let u=l.configSchema;if(u===null){r.push(s);continue}if(!u||typeof u!="object"||Array.isArray(u))continue;let d=u;d.additionalProperties===!1&&(t=!1);let m=d.properties;if(!m||typeof m!="object"||Array.isArray(m))continue;let y=Array.isArray(d.required)?d.required:[];for(let R of Object.keys(m)){let v=i.get(R)??[];v.push({service:s,subschema:m[R],required:y.includes(R)}),i.set(R,v)}}let o=[];for(let[s,l]of i)o.push({key:s,schema:wr(l),sources:l.map(({service:u,required:d})=>({service:u,required:d})),global:l.some(u=>!!u.subschema&&typeof u.subschema=="object"&&u.subschema["x-tbox-global"]===!0)});return{provider:e.provider,schemaless:r,unsupplied:[...n?.unsupplied??[]],additionalPropertiesAllowed:t,fields:o}}function dn(e,n,r,t){let i=typeof t=="string"&&t.length>0?t:void 0;if(e==="app"){if(i!==void 0)return i;let l=n.integrations?.provider;return typeof l=="string"&&l.length>0?l:null}let o=n.walk.modules.find(l=>l.id===r);return!o||!G(n.walk,o).writable?null:i!==void 0?i:L(n.integrations,o.id).provider}var lt={integrationSchemas:null,integrationFieldRegistry:null};function ut(e){return{...e,fields:e.fields.filter(n=>n.global)}}function ln(e,n){let r=dn("app",e,void 0,n);if(r===null)return lt;let t=cn(e,r,We(e.catalog,r));return{integrationSchemas:t,integrationFieldRegistry:ut(Te(t))}}function un(e,n,r){let t=dn("module",e,n,r),i=e.walk.modules.find(u=>u.id===n);if(t===null||!i)return lt;let o=(i.descriptor.declare.owns??[]).map(u=>u.service),s=u=>xe(e.catalog,t,u),l=cn(e,t,o.filter(s));return{integrationSchemas:l,integrationFieldRegistry:ut(Te(l,{unsupplied:[...new Set(o.filter(u=>!s(u)))]}))}}function hr(e){return ln(e).integrationSchemas}function Rr(e,n){return un(e,n).integrationSchemas}function Ir(e,n){let r=e.walk.ownership[n];if(r!==void 0)return L(e.integrations,r).provider;let t=e.integrations?.provider;return typeof t=="string"&&t.length>0?t:null}function Ne(e,n,r){let t=typeof r=="string"&&r.length>0?r:void 0;if(t!==void 0)return{provider:t,configSchema:K(e,t,n)};let i=e.integrations?.services?.[n]?.provider;if(i===void 0||i===""){let o=Ir(e,n);return o===null?null:{provider:o,configSchema:K(e,o,n)}}if(typeof i=="string")return{provider:i,configSchema:K(e,i,n)};if(H(i)){let o=i;return{provider:o.provider,configSchema:K(e,o.provider,n,o.configSchema)}}return null}function pn(e,n,r){let t=Ne(e,n,r);if(t===null)return null;let i={provider:t.provider,services:{[n]:{configSchema:t.configSchema}}};return Te(i)}function me(e,n){if(n===void 0||!n.startsWith("secret://"))return;let r=n.slice(9),t=ae(e,r);if(t)return{type:t.type,ref:n,file:_(r),masked:ve(t.values)}}function fn(e){let n=e.integrations,r={credential:me(e.appDir,typeof n?.credentialRef=="string"?n.credentialRef:void 0)??null,byInstance:{}};for(let{id:i}of n?.instances??[]){let o=n?.credentialRefByInstance?.[i];o!==void 0&&(r.byInstance[i]=me(e.appDir,o)??null)}let t={};for(let[i,o]of Object.entries(n?.services??{})){let s={credential:me(e.appDir,o.credentialRef)??null,byInstance:{}};for(let[l,u]of Object.entries(o.instances??{}))s.byInstance[l]=me(e.appDir,u.credentialRef)??null;t[i]=s}return{app:r,services:t}}function gn(e,n){return{types:(n===void 0?Object.keys(e.catalog.credentialTypes):[...new Set(Object.values(e.catalog.providers[n]??{}).map(t=>t.credentialType))]).sort().map(t=>{let i=e.catalog.credentialTypes[t];return{credentialType:t,owner:i?.owner??"",credentialSchema:i?on(e.appDir,i.packageDir,i.credentialSchema):null}})}}import kr from"path";var br={app:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],module:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],provider:["integrationSchemas"],service:["integrationSchemas","integrationFieldRegistry"]};function Pe(e,n){if(!n||n.length===0)return new Set;let r=br[e],t=[...new Set(n)].filter(i=>!r.includes(i));if(t.length>0)throw new x("VALIDATION_FAILED",400,`include 含未知或不适用于本端点的键:${t.join("、")}(白名单:${r.join("、")})`,["include"]);return new Set(n)}var pt=["integrationSchemas","integrationFieldRegistry"];function mn(e,n,r){if(!(typeof n!="string"||n.length===0)&&!pt.some(t=>r.has(t)))throw new x("VALIDATION_FAILED",400,`参数 ${e} 需与表单 include 键(${pt.join("、")})同现——轴参仅重定向表单层双投影`,[e])}function Cr(e,n={}){let r=Ve(),t=Promise.resolve(),i={appDir:e,cache:r};function o(f){if(!f.strictValidation)throw new x("CONTRACTS_NOT_RESOLVED",503,J(f));if(!f.ownershipBindingV6)throw new x("CONTRACTS_NOT_RESOLVED",503,J(f))}function s(f){return Gn(i,f)}function l(f){let a=f.integrations?.services;return a&&typeof a=="object"?Object.keys(a):[]}async function u(){let f=await T(e),a=s(f),g=a.integrations;if(g===null)return[];let h={resolveEffectiveService:d(f.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:d(f.module.buildSupplyLookup,"buildSupplyLookup"),normalizeInstances:d(f.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:f.module.RESOURCE_TYPE_IDS??[]},w=de(e,a.walk,g,process.env);return ne({contracts:h,integrations:g,supplies:h.buildSupplyLookup(a.catalog),...w})}function d(f,a){if(typeof f!="function")throw new x("CONTRACTS_NOT_RESOLVED",503,`contracts 求值面 ${a} 缺席(形态异常)`);return f}function m(f){let a=t.then(f,f);return t=a.catch(()=>{}),a}let y={async loadModules(f){let a=await T(e);return qe(s(a),f)},async loadModule(f,a){let g=Pe("module",a?.include);mn("moduleProvider",a?.moduleProvider,g);let h=await T(e),w=s(h),p=Ce(w.walk,f),S=Qe(w,p.id);if(g.has("serviceResolutions")){let b=[...new Set([...S.ownedServices,...S.services.map(c=>c.service)])];S.serviceResolutions=ge(h)?await u().then(c=>fe(w,c,b)):je(w,h,b)}if(g.has("integrationSchemas")||g.has("integrationFieldRegistry")){let b=un(w,p.id,a?.moduleProvider);g.has("integrationSchemas")&&(S.integrationSchemas=b.integrationSchemas),g.has("integrationFieldRegistry")&&(S.integrationFieldRegistry=b.integrationFieldRegistry)}return S},async loadApp(f){let a=Pe("app",f?.include);mn("appProvider",f?.appProvider,a);let g=await T(e),h=s(g),w=Xe(h);if(a.has("serviceResolutions")&&(w.serviceResolutions=ge(g)?await u().then(p=>fe(h,p)):je(h,g)),a.has("integrationSchemas")||a.has("integrationFieldRegistry")){let p=ln(h,f?.appProvider);a.has("integrationSchemas")&&(w.integrationSchemas=p.integrationSchemas),a.has("integrationFieldRegistry")&&(w.integrationFieldRegistry=p.integrationFieldRegistry)}return w},async loadService(f,a){let g=Pe("service",a?.include);mn("serviceProvider",a?.serviceProvider,g);let h=await T(e),w=s(h),p=Y(w.walk,l(w),f),S=en(w,p);return g.has("integrationSchemas")&&(S.integrationSchemas=Ne(w,p,a?.serviceProvider)),g.has("integrationFieldRegistry")&&(S.integrationFieldRegistry=pn(w,p,a?.serviceProvider)),S},async loadServiceResolutions(f){let a=await T(e),g=s(a);if(!ge(a))return je(g,a,f);let h=await u();return fe(g,h,f)},async loadServiceResolution(f){let a=await T(e),g=s(a),h=Y(g.walk,l(g),f);if(!ge(a))return dt(h,g,a);let w=await u();return an(h,g,w)},async loadProviders(){let f=await T(e);return nn(s(f))},async loadProvider(f,a){let g=Pe("provider",a?.include),h=await T(e);return tn(s(h),f,g)},async loadProviderService(f,a){let g=await T(e),h=s(g),w=Y(h.walk,l(h),a);return rn(h,f,w)},async loadCredentials(){let f=await T(e);return fn(s(f))},async loadCredentialTypes(f){let a=await T(e);return gn(s(a),f)}},R=Ye(e,{onApplied:n.onApplied,cache:r}),v={async writeAppIntegration(f,a){await R.warmup();let g=await T(e);return o(g),m(()=>R.applyApp(f,a))},async writeModuleIntegration(f,a,g){await R.warmup();let h=await T(e);return o(h),m(()=>{let w=Ce(s(h).walk,f);return R.applyModule(w.id,a,g)})},async writeServiceIntegration(f,a,g){await R.warmup();let h=await T(e);return o(h),m(()=>{let w=s(h),p=Y(w.walk,l(w),f);return R.applyService(p,a,g)})},async deleteServiceIntegration(f){await R.warmup();let a=await T(e);return o(a),m(()=>{let g=s(a),h=Y(g.walk,l(g),f);return R.deleteService(h)})}},A={invalidate(){r.invalidate(),De(e)},async resolveContracts(){return T(e)},walkManifests(){return O(e)},parseModuleDescriptor(f){return se(f)},loadProviderCatalogRaw(){return Ke(e)},async readIntegrationsConfig(){return B(e,r)},async writeIntegrationsConfig(f){await R.warmup();let a=await T(e);return o(a),m(()=>Ar(e,f,r))},async ensureMockBindings(){await R.warmup();let f=await T(e);return o(f),m(()=>Ze(e))},async evaluateIntegrationServices(f){await R.warmup();let a=await T(e);o(a);let g={resolveEffectiveService:d(a.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:d(a.module.buildSupplyLookup,"buildSupplyLookup"),normalizeInstances:d(a.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:a.module.RESOURCE_TYPE_IDS??[]};return ne({...f,contracts:g})}};function O(f){return D(f,r)}return{...y,...v,...A}}function Ar(e,n,r){let t=kr.join(e,"config","integrations.json");$(t,`${JSON.stringify(n,null,2)}
9
+ `),r.invalidate([t])}export{ue as APP_INTEGRATION_NODE_KEYS,x as AppToolkitError,pe as MODULE_INTEGRATION_NODE_KEYS,z as SAFE_NAME_PATTERN,Nt as assertValidModuleId,Te as buildIntegrationFieldRegistry,_t as buildOwnershipMap,de as buildPredicateAssembly,Be as checkInstanceKeys,Ft as collectDeclaredModules,J as contractsNotResolvedMessage,Cr as createAppToolkit,Ve as createFileCache,Ye as createWriteCore,Gt as credentialArtifactExists,ie as deepEqual,X as deriveStem,Pn as discoverContractPackages,me as echoForRef,En as ensureDir,Ze as ensureMockBindings,ze as evaluateAppIntegrationIssues,ne as evaluateIntegrationServices,Fe as expandEnvVars,Vn as extractModuleIdFromSource,dn as formProviderOf,De as invalidateContractsResolver,H as isControlledInlineProvider,jn as isValidModuleId,hr as loadAppIntegrationSchemas,Xe as loadAppView,gn as loadCredentialTypesView,fn as loadCredentialsView,Qe as loadModuleDetailView,Rr as loadModuleIntegrationSchemas,qe as loadModulesView,Re as loadProviderCatalog,Ke as loadProviderCatalogRaw,tn as loadProviderDetailView,rn as loadProviderServiceDetailView,nn as loadProvidersView,en as loadServiceDetailView,pn as loadServiceFieldRegistry,Ne as loadServiceIntegrationSchemas,an as loadServiceResolutionDetail,fe as loadServiceResolutionsView,Se as manifestPath,ve as maskCredentialValues,Sn as moduleDependencySchema,kn as moduleDescriptorSchema,G as moduleOwnershipWritable,vn as pageContribSchema,se as parseModuleDescriptor,We as providerFootprint,wn as providerSlotContribSchema,qt as pruneIntegrationBindings,Mn as readAppManifest,$e as readAppManifestFull,ae as readCredentialFile,B as readIntegrationsConfig,Ln as readIntegrationsStrict,te as reconcileOrphanCredentials,_n as refToEnvKey,Mt as removeNpmModule,T as resolveContractsForApp,T as resolveContractsForAppExport,cn as resolveLayerIntegrationSchemas,L as resolveModuleBinding,Ce as resolveModuleKey,Y as resolveServiceKey,sn as resolveServiceSummary,In as resourceNeedContribSchema,hn as serviceConsumeContribSchema,Rn as serviceOwnContribSchema,_ as stemToFilePath,ht as stemToRef,yn as tabContribSchema,Tt as updateNpmModule,jt as upsertMiniappContainer,xt as upsertNpmModule,D as walkManifests,Ot as writeAppManifest,$ as writeAtomic,_e as writeCredentialFile};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tbox.cn/app-toolkit",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "type": "module",
5
5
  "description": "tbox 应用工具面(运行面/工具面对仗:app-sdk 给运行的应用用,app-toolkit 给操作应用的工具用)——模块解析、集成配置求值/校验/写入内核,contracts 经应用侧动态解析(沙箱与目标应用版本解耦)。",
6
6
  "exports": {
@@ -18,7 +18,7 @@
18
18
  "zod": "3.25.76"
19
19
  },
20
20
  "devDependencies": {
21
- "@tbox.cn/app-contracts": "0.12.0",
21
+ "@tbox.cn/app-contracts": "0.12.1",
22
22
  "typescript": "5.9.3",
23
23
  "tsup": "8.5.1",
24
24
  "vitest": "4.1.10",
@@ -28,9 +28,10 @@ export function resolveModuleKey(walk: WalkManifestsResult, key: string): WalkMo
28
28
  throw new AppToolkitError('MODULE_NOT_FOUND', 404, `模块 ${key} 非已装模块(id / 展示名均未命中)`);
29
29
  }
30
30
 
31
- /** 服务双键解析 → 真实 service id:服务键集(词汇 ∪ demand ∪ 供给足迹 ∪ configuredKeys
31
+ /** 服务双键解析 → 真实 service id:服务键集(词汇 ∪ demand ∪ 供给足迹 ∪ configuredKeys ∪ 归属)
32
32
  * 精确命中 → 展示名(slotMeta.name ?? catalog.services[].name)唯一命中 → 404。
33
- * configuredKeys = 当前集成配置 services 节键集(调用方注入)。 */
33
+ * configuredKeys = 当前集成配置 services 节键集(调用方注入)。
34
+ * v6.1 += 归属键(walk.ownership——纯归属无词汇/demand/供给的 owns 合法,O6 对称)。 */
34
35
  export function resolveServiceKey(
35
36
  walk: WalkManifestsResult,
36
37
  configuredKeys: readonly string[],
@@ -50,6 +51,7 @@ export function resolveServiceKey(
50
51
  || Object.hasOwn(walk.catalog.services, key)
51
52
  || supplied.has(key)
52
53
  || configuredKeys.includes(key)
54
+ || Object.hasOwn(walk.ownership, key)
53
55
  ) {
54
56
  return key;
55
57
  }
package/src/dto.ts CHANGED
@@ -47,13 +47,15 @@ export interface ModuleDeclaration {
47
47
  hidden?: boolean;
48
48
  }
49
49
 
50
- /** 服务需求声明(模块 demand 单元 / 平台服务条目——v4.4 D29 双端点同型;defaults 唯一落位 ServiceDetail) */
50
+ /** 服务需求声明(模块 demand 单元 / 平台服务条目 / owned-not-consumed 投影条目——
51
+ * v4.4 D29 双端点同型;defaults 唯一落位 ServiceDetail) */
51
52
  export interface ServiceDemand {
52
53
  service: string;
53
54
  /** manifest demand meta(v7 title→name);缺席 UI 回退 service id */
54
55
  name?: string;
55
56
  description?: string;
56
- /** demand optional === false(多模块 OR 聚合见 resolution echo;平台服务条目恒 false) */
57
+ /** demand optional === false(多模块 OR 聚合见 resolution echo;平台服务条目与 owned
58
+ * 投影条目恒 false——无 demand 源) */
57
59
  required: boolean;
58
60
  }
59
61
 
@@ -81,9 +83,11 @@ export interface ModuleDetailView {
81
83
  binding: ModuleBinding | null;
82
84
  /** v6:owns.length > 0(moduleOwnershipWritable 单源——读标志与写守卫共用) */
83
85
  configEditable: boolean;
84
- /** 本模块 demand(declare.consumes;卡片展开 + 编辑器静态上下文自足) */
86
+ /** 本模块服务面 = demand owned 去重投影(2026-09-21 服务面投影批——通用合并无 consumes
87
+ * 空判特例:consume 条目胜出[声明序原样、required = optional === false];owned-not-consumed
88
+ * 追加[ownedServices 排序序、Set 去重,required 恒 false]。卡片展开 + 编辑器静态上下文自足) */
85
89
  services: ServiceDemand[];
86
- /** v4.4 D31:include=serviceResolutions 内嵌(demand 服务过滤 ≡ 批量 ?service= 语义;<0.9/形态异常 → null——永不 503) */
90
+ /** v4.4 D31:include=serviceResolutions 内嵌(v6.1 键集 = owned ∪ demand 服务过滤 ≡ 批量 ?service= 语义;<0.9/形态异常 → null——永不 503) */
87
91
  serviceResolutions?: ServiceResolutionsView | null;
88
92
  /** v4.4 D32:include=integrationSchemas 层级富化(零归属/未绑定 → null) */
89
93
  integrationSchemas?: LayerIntegrationSchemas | null;
@@ -115,7 +119,8 @@ export interface IntegrationFieldRegistryView {
115
119
  provider: string;
116
120
  /** 作用域内 configSchema === null 的服务(UI「未提供参数模板」提示行) */
117
121
  schemaless: string[];
118
- /** module 轴 = demand − 该厂商供给(Set 去重保序);app 轴恒 [](结构性:足迹 ⊆ 供给) */
122
+ /** module 轴 = ownedServices − 该厂商供给(v6.1 scope 随归属——loadModuleFormViews 单源,
123
+ * Set 去重保序);app 轴恒 [](结构性:足迹 ⊆ 供给) */
119
124
  unsupplied: string[];
120
125
  /** 作用域内全部非 null schema 的 additionalProperties 均 ≠ false(聚合;空真) */
121
126
  additionalPropertiesAllowed: boolean;
@@ -182,7 +187,7 @@ export interface ServiceIntegrationSchemas {
182
187
  export interface ServiceResolutionsView {
183
188
  /** P6 contracts echo(仅求值轴两端点携带) */
184
189
  contracts: ContractsResolution;
185
- /** 键集 = 服务词汇 ∪ 已配置(模块/平台/孤儿全量) */
190
+ /** 键集 = 服务词汇 ∪ 已配置 ∪ 归属(v6.1 += 归属——owned 服务恒可求值;模块/平台/孤儿全量) */
186
191
  resolutions: Record<string, ServiceResolutionEntry>;
187
192
  /** 谓词全量(doctor 同源;恒全量——subset 消费方客户端过滤) */
188
193
  issues: IntegrationIssue[];
@@ -200,7 +205,8 @@ export interface ServiceResolutionEntry {
200
205
  layer?: BindingLayer;
201
206
  /** provider 在场时在场:(provider, service) ∈ 供给关系 */
202
207
  supplied?: boolean;
203
- /** owner 模块 install id;平台服务/孤儿缺席 */
208
+ /** owner 模块 install id(v6.1 = walk.ownership 归属单源——install id 轴,与模块清单 id 恒可 join;
209
+ * 旧实现 demand owners[0] 为包名/@app 轴且漏 owned-not-consumed,已退役);平台服务/孤儿缺席 */
204
210
  module?: string;
205
211
  /** demand echo(OR 聚合);平台/孤儿恒 false;集成就绪判定单源(§7) */
206
212
  required?: boolean;
package/src/factory.ts CHANGED
@@ -270,10 +270,12 @@ export function createAppToolkit(appDir: string, options: AppToolkitOptions = {}
270
270
  if (include.has('serviceResolutions')) {
271
271
  // v7:三条件门 + 内嵌轴同步降级(P14 (b) 四面统一骨架——D31 null 分支退役:
272
272
  // include 请求了即恒返回视图;老消费方 null 分支保留为兼容死码)
273
+ // 过滤键 = owned ∪ demand(v6.1——v4.4 demand-only 遗留;owned 服务是模块页
274
+ // 集成面一半,mall-core 形态 owns>0/consumes=0 时 demand-only 内嵌恒空)
275
+ const resolutionFilter = [...new Set([...view.ownedServices, ...view.services.map((s) => s.service)])];
273
276
  view.serviceResolutions = contractsEvaluable(contracts)
274
- ? await predicateIssues().then((issues) =>
275
- loadServiceResolutionsView(snap, issues, view.services.map((s) => s.service)))
276
- : loadServiceResolutionsDegradeView(snap, contracts, view.services.map((s) => s.service)); // module = demand 服务过滤(≡ 批量 ?service= 语义)
277
+ ? await predicateIssues().then((issues) => loadServiceResolutionsView(snap, issues, resolutionFilter))
278
+ : loadServiceResolutionsDegradeView(snap, contracts, resolutionFilter); // owned ∪ demand 服务过滤(≡ 批量 ?service= 语义)
277
279
  }
278
280
  if (include.has('integrationSchemas') || include.has('integrationFieldRegistry')) {
279
281
  // v4.6 D37:表单层双投影同源一次计算(双取单算 + I1——假想重定向天然同步)
@@ -9,7 +9,8 @@
9
9
  * **code 枚举单源 = 本文件头映射表(additive-only;api.md §5 表与本表同步)**:
10
10
  * CREDENTIAL_FILE_MISSING #1 error effective credentialRef 引用凭据文件不在场
11
11
  * CREDENTIAL_TYPE_MISMATCH #2 error 凭据文件 .type 与绑定 credentialType 不一致
12
- * SLOT_NOT_DECLARED #3 warning 服务槽无消费方声明(拼写/需求方未安装/旧槽位词汇)
12
+ * SLOT_NOT_DECLARED #3 warning 服务槽无消费方声明(拼写/需求方未安装/旧槽位词汇;
13
+ * v6.1 归属豁免——owned 服务不报)
13
14
  * SLOT_NOT_CONFIGURED #4 warning 需求方缺口(服务槽未配置)
14
15
  * INSTANCE_SUPPLY_UNMATCHED #5 error 绑定未命中已装供给(槽级/实例级覆盖)
15
16
  * IMPL_WITHOUT_PROVIDER #5/#13 error impl-only(implementation 缺 provider 绑定组头)
@@ -333,9 +334,11 @@ export function evaluateIntegrationServices(
333
334
  }
334
335
 
335
336
  for (const [serviceId, service] of Object.entries(integrations.services)) {
336
- // 1. 槽未知(不在任何 manifest 需求声明,也非已知供给域)
337
+ // 1. 槽未知(不在任何 manifest 需求声明,也非已知归属/供给域)——v6.1 += 归属豁免:
338
+ // owned+已配置+无人 consume(mall-core 形态)非「无消费方声明」,误报退役;
339
+ // ownership 缺席 = 面信息未喂(谓词纯函数)→ 恒查(与 MODULE_CONFIG_DEAD 防御模式同律)
337
340
  const demanded = demandedServices[serviceId];
338
- if (!demanded) {
341
+ if (!demanded && ownership?.[serviceId] === undefined) {
339
342
  issues.push({
340
343
  severity: 'warning',
341
344
  code: 'SLOT_NOT_DECLARED',
@@ -66,8 +66,15 @@ export async function readIntegrationsStrict(
66
66
  return { config: raw, strict: false, contracts };
67
67
  }
68
68
 
69
- /** P9 服务身份判据单源(A2):GET/PUT/DELETE 共用「词汇 ∪ 已配置」——service-detail 判据逐字冻结
70
- * api.md P9 的「demanded 退化」口径为文档层 nuance,现行实现与 GET 均不含 demanded——冻结现状即单源) */
71
- export function isKnownService(vocabulary: readonly string[], configuredKeys: readonly string[], service: string): boolean {
72
- return vocabulary.includes(service) || configuredKeys.includes(service);
69
+ /** P9 服务身份判据单源(A2):GET/PUT/DELETE 共用「词汇 ∪ 已配置 ∪ 归属」——service-detail 判据
70
+ * 逐字冻结(api.md P9 的「demanded 退化」口径为文档层 nuance,现行实现与 GET 均不含 demanded——冻结现状即单源)。
71
+ * v6.1 += 归属键(O6 对称——纯归属无词汇/demand/配置的 owns 合法,resolveServiceKey 供给足迹先例):
72
+ * 求值轴可见(resolutionKeys 同批接入)而静态/写轴 404 会造死锁(诊断指引的编辑被拒)。 */
73
+ export function isKnownService(
74
+ vocabulary: readonly string[],
75
+ configuredKeys: readonly string[],
76
+ service: string,
77
+ ownedKeys: readonly string[],
78
+ ): boolean {
79
+ return vocabulary.includes(service) || configuredKeys.includes(service) || ownedKeys.includes(service);
73
80
  }
@@ -449,9 +449,12 @@ export function createWriteCore(appDir: string, opts: WriteCoreOptions = {}): Wr
449
449
  assertSafeInstanceKeys(node, writeOpts, 'slot');
450
450
  const issues: IntegrationServiceIssue[] = [];
451
451
  const current = loadConfig(appDir, cache);
452
- // P9 服务身份判据单源(A2):写入集 = 词汇 ∪ 已配置——未知服务(含 typo)404(api.md §5
453
- if (!isKnownService(walkManifests(appDir, cache).vocabulary, Object.keys((current?.services as Record<string, unknown> | undefined) ?? {}), service)) {
454
- throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${service} 不在服务词汇(已装契约包 ∪ 已配置)`);
452
+ // P9 服务身份判据单源(A2):写入集 = 词汇 ∪ 已配置 ∪ 归属——未知服务(含 typo)404(api.md §5
453
+ // v6.1 += 归属键——owned 词汇服务可配置,与求值轴 resolutionKeys 同批接入)。
454
+ // walkManifests 单次调用(目录枚举零缓存——双调 = 每写多一整轮遍历)
455
+ const walk = walkManifests(appDir, cache);
456
+ if (!isKnownService(walk.vocabulary, Object.keys((current?.services as Record<string, unknown> | undefined) ?? {}), service, Object.keys(walk.ownership))) {
457
+ throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${service} 不在服务词汇(已装契约包 ∪ 已配置 ∪ 归属)`);
455
458
  }
456
459
  if (current === null) {
457
460
  issues.push({
@@ -505,8 +508,10 @@ export function createWriteCore(appDir: string, opts: WriteCoreOptions = {}): Wr
505
508
  const issues: IntegrationServiceIssue[] = [];
506
509
  const current = loadConfig(appDir, cache);
507
510
  // P9 服务身份判据单源(A2):判据外未知服务 404;判据内缺席节点维持幂等 written:false
508
- if (!isKnownService(walkManifests(appDir, cache).vocabulary, Object.keys((current?.services as Record<string, unknown> | undefined) ?? {}), service)) {
509
- throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${service} 不在服务词汇(已装契约包 ∪ 已配置)`);
511
+ // (v6.1 判据 += 归属键——同 applyService;walkManifests 单次调用)
512
+ const walk = walkManifests(appDir, cache);
513
+ if (!isKnownService(walk.vocabulary, Object.keys((current?.services as Record<string, unknown> | undefined) ?? {}), service, Object.keys(walk.ownership))) {
514
+ throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${service} 不在服务词汇(已装契约包 ∪ 已配置 ∪ 归属)`);
510
515
  }
511
516
  const services = { ...((current?.services as Record<string, unknown>) ?? {}) };
512
517
  if (!(service in services)) {
@@ -14,6 +14,8 @@ import { resolveServiceDisplay, type ViewSnapshot } from './context.js';
14
14
  * v5 domainKeys/providerBindings 退役。
15
15
  * 2026-09-16 双缺陷批:loadModulesView 排除 provider 家族包(供给/实施载体非可配置
16
16
  * 业务模块)——walk 声明集与 loadModuleDetailView 不变(装包仍合法,详情保持 200)。
17
+ * 2026-09-21 服务面投影批:loadModuleDetailView.services = demand ∪ owned 去重
18
+ * (consume 胜出 + owned-not-consumed 追加,required 恒 false)——demand-only 恒空收口。
17
19
  */
18
20
 
19
21
  /** knowledge.json 台账路径(与 toolkit readIntegrationsConfig 同源锚定 appDir/config/——
@@ -106,17 +108,28 @@ export function loadModuleDetailView(snapshot: ViewSnapshot, moduleId: string):
106
108
  if (!mod) {
107
109
  throw new AppToolkitError('MODULE_NOT_FOUND', 404, `模块 ${moduleId} 非已装模块`);
108
110
  }
109
- const services: ServiceDemand[] = (mod.descriptor.declare.consumes ?? []).map((need) => {
111
+ const w = moduleOwnershipWritable(snapshot.walk, mod);
112
+ // 服务面投影(owned ∪ demand 去重——通用合并,无 consumes 空判特例):consume 条目胜出
113
+ // (声明序原样——required = optional === false、demand meta);owned-not-consumed 追加
114
+ // (ownedServices 排序序、Set 去重——owns 重复声明不出重复行;required 恒 false——无
115
+ // demand 源)。consume 侧保持 1:1 现状(重复 consumes 声明本就双行,此处不去重)。
116
+ // 动机 = demand-only 恒空缺陷(mall-core 形态 owns>0/consumes=0 → 面板服务行
117
+ // `services × serviceResolutions` join 零行);键集对齐 v6.1 serviceResolutions 过滤(owned ∪ demand)。
118
+ const consumed = new Set((mod.descriptor.declare.consumes ?? []).map((need) => need.service));
119
+ const toDemand = (service: string, required: boolean): ServiceDemand => {
110
120
  // 展示名单源走链(B1):词汇 meta > demand meta > id——词汇主源防 manifest demand 漂移
111
- const display = resolveServiceDisplay(snapshot.walk, need.service);
121
+ const display = resolveServiceDisplay(snapshot.walk, service);
112
122
  return {
113
- service: need.service,
123
+ service,
114
124
  name: display.name,
115
125
  ...(display.description !== undefined ? { description: display.description } : {}),
116
- required: need.optional === false,
126
+ required,
117
127
  };
118
- });
119
- const w = moduleOwnershipWritable(snapshot.walk, mod);
128
+ };
129
+ const services: ServiceDemand[] = [
130
+ ...(mod.descriptor.declare.consumes ?? []).map((need) => toDemand(need.service, need.optional === false)),
131
+ ...[...new Set(w.ownedServices)].filter((service) => !consumed.has(service)).map((service) => toDemand(service, false)),
132
+ ];
120
133
  const modulesNode = (snapshot.integrations as { modules?: Record<string, unknown> } | null)?.modules ?? {};
121
134
  // integration = modules[install id] 集成位投影(D21 编辑预填源;provider/config 两键——
122
135
  // resources 不投影不写,N2);未配置 = null
@@ -11,9 +11,10 @@ import { resolveServiceDisplay, suppliedByVendors, type ViewSnapshot } from './c
11
11
  export function loadServiceDetailView(snapshot: ViewSnapshot, service: string): ServiceDetail {
12
12
  const configured = (snapshot.integrations as { services?: Record<string, unknown> } | null)?.services ?? {};
13
13
  const demand = snapshot.catalog.services[service];
14
- // 404 判据与写路径单源(P9——A2 isKnownService;词汇成员零 demand/供给/config 仍 200
15
- if (!isKnownService(snapshot.walk.vocabulary, Object.keys(configured), service)) {
16
- throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${service} 不在服务词汇(已装契约包 ∪ 已配置)`);
14
+ // 404 判据与写路径单源(P9——A2 isKnownService;词汇成员零 demand/供给/config 仍 200
15
+ // v6.1 += 归属键——owned ∖ 词汇服务静态单体可达,与求值/写轴同批接入)
16
+ if (!isKnownService(snapshot.walk.vocabulary, Object.keys(configured), service, Object.keys(snapshot.walk.ownership))) {
17
+ throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${service} 不在服务词汇(已装契约包 ∪ 已配置 ∪ 归属)`);
17
18
  }
18
19
  // integration = 文件 services[s] 逐字原值(编辑预填源 D21);无声明 = null
19
20
  const integration = (configured[service] as ServiceDetail['integration'] | undefined) ?? null;
@@ -192,8 +192,9 @@ export function resolveServiceSummary(
192
192
  const demand = catalog.services[service];
193
193
  const required = demand !== undefined ? !demand.optional : undefined;
194
194
 
195
- // module = owner 模块(demand owners 首);平台/孤儿缺席
196
- const module = demand?.owners[0];
195
+ // module = owner 模块(v6 归属单源 walk.ownership——install id 轴;平台/孤儿缺席)。
196
+ // demand owners 是消费方集合且键轴为包名/@app 形态,不作归因源(与模块清单 id 恒可 join)
197
+ const module = snapshot.walk.ownership[service];
197
198
 
198
199
  return {
199
200
  status: evaluation.status,
@@ -210,15 +211,21 @@ function isSuppliedCheck(catalog: WalkCatalog, provider: string, service: string
210
211
  return isSupplied(catalog, provider, service);
211
212
  }
212
213
 
213
- /** 批量键集(求值轴/降级轴共用单源:服务词汇 ∪ 需求侧 ∪ 已配置) */
214
+ /** 批量键集(求值轴/降级轴共用单源:服务词汇 ∪ 需求侧 ∪ 已配置 ∪ 归属)。
215
+ * v6.1 += 归属键——owned 服务恒可求值(embed 自足前置:迭代基不是 filter,
216
+ * 缺此键则 owned ∖ 词汇服务在内嵌轴静默丢键,fail-visible 破功)。 */
214
217
  function resolutionKeys(snapshot: ViewSnapshot): string[] {
215
- const keys = new Set<string>([...snapshot.walk.vocabulary, ...Object.keys(snapshot.catalog.services)]);
218
+ const keys = new Set<string>([
219
+ ...snapshot.walk.vocabulary,
220
+ ...Object.keys(snapshot.catalog.services),
221
+ ...Object.keys(snapshot.walk.ownership),
222
+ ]);
216
223
  const configured = (snapshot.integrations as { services?: Record<string, unknown> } | null)?.services ?? {};
217
224
  for (const k of Object.keys(configured)) keys.add(k);
218
225
  return [...keys].sort();
219
226
  }
220
227
 
221
- /** 批量求值(键集 = 服务词汇已配置;?service= 过滤语义——未知键缺席;issues 恒全量) */
228
+ /** 批量求值(键集 = resolutionKeys 单源:词汇 需求侧 ∪ 已配置 ∪ 归属;?service= 过滤语义——未知键缺席;issues 恒全量) */
222
229
  export function loadServiceResolutionsView(
223
230
  snapshot: ViewSnapshot,
224
231
  issues: IntegrationIssue[],
@@ -348,14 +355,15 @@ export function contractsEvaluable(contracts: ResolvedContracts): boolean {
348
355
  return contracts.evaluation && contracts.strictValidation && contracts.ownershipBindingV6;
349
356
  }
350
357
 
351
- /** 降级单条目(静态可算字段:module = owners / required = OR 聚合;provider/layer 不投——
352
- * 保持「求值产物」语义纯净,layer 单独在场违 D31 孤儿层口径) */
358
+ /** 降级单条目(静态可算字段:module = walk.ownership(v6 归属单源,install id 轴)/
359
+ * required = OR 聚合;provider/layer 不投——保持「求值产物」语义纯净,layer 单独在场违 D31 孤儿层口径) */
353
360
  function degradeEntry(snapshot: ViewSnapshot, service: string, message: string): ServiceResolutionEntry {
354
361
  const demand = snapshot.catalog.services[service];
362
+ const owner = snapshot.walk.ownership[service];
355
363
  return {
356
364
  status: 'evaluation-unavailable',
357
365
  statusMessage: message,
358
- ...(demand?.owners[0] !== undefined ? { module: demand.owners[0] } : {}),
366
+ ...(owner !== undefined ? { module: owner } : {}),
359
367
  ...(demand !== undefined ? { required: !demand.optional } : {}),
360
368
  };
361
369
  }
@@ -770,8 +770,8 @@ describe('A2 错误面(P-4 notes 优先 / P-5 畸形包 503)', () => {
770
770
  const entry = batch.resolutions['parking.query'];
771
771
  expect(entry.status).toBe('evaluation-unavailable');
772
772
  expect(entry.statusMessage).toMatch(/未安装/);
773
- // 静态可算字段:module = demand owners 首(与求值轴同源);required = OR 聚合
774
- expect(entry.module).toBe('@app/module-parking');
773
+ // 静态可算字段:module = walk.ownership(v6 归属单源,install id 轴——v6.1 起非 demand owners 包名轴);required = OR 聚合
774
+ expect(entry.module).toBe('module-parking');
775
775
  expect(entry.required).toBe(true);
776
776
  expect(batch.issues).toEqual([]);
777
777
  // 单体:声明实例枚举(原始数据投影——root instances[].id)逐实例同标记;
@@ -947,6 +947,194 @@ describe('v6 所有权族(D34 多域钉死退役 → ownedServices/binding 单
947
947
  app.dispose();
948
948
  });
949
949
 
950
+ it('D5 v6.1 归属三副本修复:owned-not-consumed(mall-core 形态)批量归因 + 内嵌键集 + 谓词豁免', async () => {
951
+ const app = createTempApp('tbox-d5-');
952
+ invalidateContractsResolver();
953
+ const store = joinStore(app.appDir, 'contracts');
954
+ writeFakeContractsPackage(store, {
955
+ version: '0.9.0',
956
+ slots: ['auth.alipay-login', 'mall.info', 'mall.info-cache'],
957
+ });
958
+ linkContracts(app.appDir, store, { subdir: 'apps/server' });
959
+ // owns 3 / consumes 0(mall-core 形态——owns ⊄ consumes 的修复靶形态)
960
+ writeAppFile(
961
+ app.appDir,
962
+ 'packages/module-mall/tbox.module.json',
963
+ JSON.stringify({
964
+ schemaVersion: 1,
965
+ id: 'module-mall',
966
+ version: '0.1.0',
967
+ kind: 'business',
968
+ declare: {
969
+ owns: [{ service: 'auth.alipay-login' }, { service: 'mall.info' }, { service: 'mall.info-cache' }],
970
+ consumes: [],
971
+ },
972
+ dependencies: { modules: [] },
973
+ env: [],
974
+ }),
975
+ );
976
+ writeAppFile(
977
+ app.appDir,
978
+ 'config/integrations.json',
979
+ JSON.stringify({
980
+ provider: 'mock',
981
+ services: { 'mall.info': { provider: 'mock' }, 'orphan.svc': { provider: 'mock' } },
982
+ }),
983
+ );
984
+ const tk = createAppToolkit(app.appDir);
985
+ const batch = await tk.loadServiceResolutions();
986
+ // (a) 批量归因 = walk.ownership(install id 轴);required 缺席(demand echo——无人 consume)
987
+ expect(batch.resolutions['mall.info']).toMatchObject({ module: 'module-mall' });
988
+ expect(batch.resolutions['mall.info']?.required).toBeUndefined();
989
+ expect(batch.resolutions['auth.alipay-login']).toMatchObject({ module: 'module-mall' });
990
+ expect(batch.resolutions['mall.info-cache']).toMatchObject({ module: 'module-mall' });
991
+ // (d) 谓词 #3 豁免:owned+已配置不再误报「无消费方声明」;真孤儿仍报(语义收窄锁)
992
+ const slotNotDeclared = batch.issues.filter((i) => i.code === 'SLOT_NOT_DECLARED');
993
+ expect(slotNotDeclared.map((i) => i.service)).toEqual(['orphan.svc']);
994
+ // (a) 内嵌键集 = owned ∪ demand = owned(consumes 空——demand-only 过滤恒空缺陷回归锁)
995
+ const mod = await tk.loadModule('module-mall', { include: ['serviceResolutions'] });
996
+ expect(Object.keys(mod.serviceResolutions!.resolutions).sort()).toEqual([
997
+ 'auth.alipay-login',
998
+ 'mall.info',
999
+ 'mall.info-cache',
1000
+ ]);
1001
+ // 服务面投影(owned ∪ demand 去重):consumes 空 → services = ownedServices 投影
1002
+ // (fixture 词汇无 meta——id 兜底、description 键缺席;required 恒 false)
1003
+ expect(mod.services).toEqual([
1004
+ { service: 'auth.alipay-login', name: 'auth.alipay-login', required: false },
1005
+ { service: 'mall.info', name: 'mall.info', required: false },
1006
+ { service: 'mall.info-cache', name: 'mall.info-cache', required: false },
1007
+ ]);
1008
+ // owned 服务不落平台条目(moduleOccupiedServices 含 owns——AppView.services 排除不变)
1009
+ const appView = await tk.loadApp();
1010
+ expect(appView.services.map((s) => s.service)).not.toContain('mall.info');
1011
+ app.dispose();
1012
+ });
1013
+
1014
+ it('D8 服务面投影(owned ∪ demand 去重——通用合并):consume 胜出 + owned-not-consumed 追加 + 重复 owns 去重 + 词汇外 id 兜底', async () => {
1015
+ const app = createTempApp('tbox-d8-');
1016
+ invalidateContractsResolver();
1017
+ const store = joinStore(app.appDir, 'contracts');
1018
+ writeFakeContractsPackage(store, {
1019
+ version: '0.9.0',
1020
+ slots: ['member.account', 'member.snapshot'],
1021
+ meta: { 'member.account': { name: '会员账户', description: '登录与入会状态' } },
1022
+ });
1023
+ linkContracts(app.appDir, store, { subdir: 'apps/server' });
1024
+ writeAppFile(
1025
+ app.appDir,
1026
+ 'packages/module-member/tbox.module.json',
1027
+ JSON.stringify({
1028
+ schemaVersion: 1,
1029
+ id: 'module-member',
1030
+ version: '0.1.0',
1031
+ kind: 'business',
1032
+ declare: {
1033
+ // member.account:owns + consumes 双声明(consume 胜出——不出双行、required=true 保留);
1034
+ // member.snapshot:owned-not-consumed(追加 required=false)+ 重复 owns 声明(Set 去重单行)
1035
+ owns: [{ service: 'member.account' }, { service: 'member.snapshot' }, { service: 'member.snapshot' }],
1036
+ consumes: [{ service: 'member.account', optional: false }],
1037
+ },
1038
+ dependencies: { modules: [] },
1039
+ env: [],
1040
+ }),
1041
+ );
1042
+ writeAppFile(
1043
+ app.appDir,
1044
+ 'packages/module-x/tbox.module.json',
1045
+ JSON.stringify({
1046
+ schemaVersion: 1,
1047
+ id: 'module-x',
1048
+ version: '0.1.0',
1049
+ kind: 'business',
1050
+ declare: { owns: [{ service: 'ghost.owned' }], consumes: [] },
1051
+ dependencies: { modules: [] },
1052
+ env: [],
1053
+ }),
1054
+ );
1055
+ const tk = createAppToolkit(app.appDir);
1056
+ const member = await tk.loadModule('module-member');
1057
+ // consume 条目声明序在前(词汇 meta 压过 demand meta、required=true 保留);
1058
+ // owned-not-consumed 追加(snapshot 无 meta——id 兜底、description 键缺席、required=false)
1059
+ expect(member.services).toEqual([
1060
+ { service: 'member.account', name: '会员账户', description: '登录与入会状态', required: true },
1061
+ { service: 'member.snapshot', name: 'member.snapshot', required: false },
1062
+ ]);
1063
+ // 词汇外 owned(D7 ghost.owned 形态合法)id 兜底入服务面
1064
+ const x = await tk.loadModule('module-x');
1065
+ expect(x.services).toEqual([{ service: 'ghost.owned', name: 'ghost.owned', required: false }]);
1066
+ app.dispose();
1067
+ });
1068
+
1069
+ it('D6 v6.1 通道 1 键轴:npmModules 归因 = entry.id(install id,与模块清单可 join)≠ entry.package(demand owners 旧轴)', async () => {
1070
+ const app = createTempApp('tbox-d6-');
1071
+ invalidateContractsResolver();
1072
+ const store = joinStore(app.appDir, 'contracts');
1073
+ writeFakeContractsPackage(store, { version: '0.9.0', slots: ['mall.info'] });
1074
+ linkContracts(app.appDir, store, { subdir: 'apps/server' });
1075
+ writeAppFile(
1076
+ app.appDir,
1077
+ '.tbox/app.json',
1078
+ JSON.stringify({
1079
+ templateVersion: 'test',
1080
+ npmModules: [{ id: 'module-mall', package: '@tbox.cn/app-module-mall', version: '0.1.0', mode: 'sdk' }],
1081
+ }),
1082
+ );
1083
+ writeAppFile(
1084
+ app.appDir,
1085
+ 'packages/module-mall/tbox.module.json',
1086
+ JSON.stringify({
1087
+ schemaVersion: 1,
1088
+ id: 'module-mall',
1089
+ version: '0.1.0',
1090
+ kind: 'business',
1091
+ declare: { owns: [{ service: 'mall.info' }], consumes: [] },
1092
+ dependencies: { modules: [] },
1093
+ env: [],
1094
+ }),
1095
+ );
1096
+ const tk = createAppToolkit(app.appDir);
1097
+ const batch = await tk.loadServiceResolutions();
1098
+ expect(batch.resolutions['mall.info']?.module).toBe('module-mall');
1099
+ expect(batch.resolutions['mall.info']?.module).not.toBe('@tbox.cn/app-module-mall');
1100
+ app.dispose();
1101
+ });
1102
+
1103
+ it('D7 v6.1 归属键集全轴联动:owned ∖ 词汇 fail-visible(求值可见 + 静态 200 + 双键直击 + PUT 放行)', async () => {
1104
+ const app = createTempApp('tbox-d7-');
1105
+ invalidateContractsResolver();
1106
+ const store = joinStore(app.appDir, 'contracts');
1107
+ writeFakeContractsPackage(store, { version: '0.9.0' }); // 词汇空——ghost.owned 纯归属形态
1108
+ linkContracts(app.appDir, store, { subdir: 'apps/server' });
1109
+ writeAppFile(
1110
+ app.appDir,
1111
+ 'packages/module-x/tbox.module.json',
1112
+ JSON.stringify({
1113
+ schemaVersion: 1,
1114
+ id: 'module-x',
1115
+ version: '0.1.0',
1116
+ kind: 'business',
1117
+ declare: { owns: [{ service: 'ghost.owned' }], consumes: [] },
1118
+ dependencies: { modules: [] },
1119
+ env: [],
1120
+ }),
1121
+ );
1122
+ const tk = createAppToolkit(app.appDir);
1123
+ // 求值轴可见(resolutionKeys += 归属):module 归因 + 未配置态
1124
+ const batch = await tk.loadServiceResolutions();
1125
+ expect(batch.resolutions['ghost.owned']).toMatchObject({ module: 'module-x', status: 'service-not-configured' });
1126
+ // 静态单体可达(isKnownService += 归属——修复前 404 死锁)
1127
+ const svc = await tk.loadService('ghost.owned');
1128
+ expect(svc.service).toBe('ghost.owned');
1129
+ // 双键寻址直击(resolveServiceKey += 归属)
1130
+ const detail = await tk.loadServiceResolution('ghost.owned');
1131
+ expect(detail.resolution.module).toBe('module-x');
1132
+ // 写闸放行(P9 判据 += 归属——诊断指引的编辑不再被拒)
1133
+ const put = await tk.writeServiceIntegration('ghost.owned', { provider: 'mock' });
1134
+ expect(put.written).toBe(true);
1135
+ app.dispose();
1136
+ });
1137
+
950
1138
  it('D6 偏斜态分级(P1 标记门 v7):v5 contracts 假件 + v6 toolkit → 写端点 503 保留;读求值轴降级骨架(503 退役)', async () => {
951
1139
  const app = createTempApp('tbox-d6-');
952
1140
  invalidateContractsResolver();