@tbox.cn/app-template-agent 0.10.20 → 0.10.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -8,12 +8,12 @@
8
8
  |---|---|
9
9
  | `apps/server` | Express + WS 装配入口,HTTP 路由,TTS 代理;业务工具/卡片由模块自注册(自注册闭环) |
10
10
  | `apps/client` | React/Vite 装配入口,业务页面/组件/adapters/bridge(家页 MallHome 由 mall-core 模块经 home 槽供给) |
11
- | `packages/` | 模块目录(`tbox-app new module <name>` 或 `module add` 生成 `@app/<id>` 成员;出厂预装 `provider-custom`(自定义 API 实施落点)、`agent-ui-kit`(组件库)与 `contracts-mall` shim) |
11
+ | `packages/` | 模块目录(`npx --yes @tbox.cn/app-cli new module <name>` 或 `module add` 生成 `@app/<id>` 成员;出厂预装 `provider-custom`(自定义 API 实施落点)、`agent-ui-kit`(组件库)与 `contracts-mall` shim) |
12
12
  | `profiles/` | 创建期画像(`--profile` 加装计划;应用内不再消费,可忽略) |
13
13
 
14
14
  ## 模块开发(双端自注册闭环,逐行同构)
15
15
 
16
- `packages/module-*`(经 `tbox-app module add` 生成)是双端单包,两端入口导出**模块描述对象**并自注册:
16
+ `packages/module-*`(经 `npx --yes @tbox.cn/app-cli module add` 生成)是双端单包,两端入口导出**模块描述对象**并自注册:
17
17
 
18
18
  - server 入口 `src/server/index.ts`:`export const serverModule = { cards, register(ctx) {...} } satisfies ServerModule`;
19
19
  `register` 内经 `ctx.tools/cards.registerMap/handlers/routes/services/bus` 自注册;只注册不解析(resolveService 仅 handle/事件回调内)。
@@ -21,7 +21,7 @@
21
21
  `register` 内经 `ctx.cards.registerMap(cards)` 注册卡片组件。
22
22
  - `cards` map 的 **key 约定 = meta.cardType**(server 端 meta 的 cardType;doctor 会校验),无卡片模块写 `cards: {}`;
23
23
  模块对象必须用 `satisfies`(不能 `: ServerModule` 标注——标注会把 cards 泛化导致类型推导失效)。
24
- - 每个模块根目录有 `tbox.module.json`(schema v1)声明 contributes(tools/cards/handlers/routes/pages/tabs)。
24
+ - 每个模块根目录有 `tbox.module.json`(schema v1)声明 `declare`(tools/cards/handlers/routes/pages/tabs + `owns`/`consumes` 服务面)。
25
25
  跨模块写操作走 `ctx.services.register/resolve` + 类型化事件总线,业务代码只 import `@tbox.cn/app-contracts`(或领域契约包),不 import `apps/*`。
26
26
 
27
27
  ## 装配文件(双锚点,双端逐行同构)
@@ -46,25 +46,37 @@ apps/client/src/business/App.tsx # 业务应用入口
46
46
  apps/client/src/platform/AgentChatApp.tsx # 默认对话运行时
47
47
  apps/client/src/modules.ts # 客户端模块装配(与 server 端同构)
48
48
  apps/client/src/cards/registry.ts # 卡片注册表快照(CardType → CardComponent)
49
- apps/server/src/index.ts # 服务端入口(HTTP + WS + Vite middleware + createServerContext + createEngineFromContext)
49
+ apps/server/src/index.ts # 服务端入口(静态产物 HTTP + WS;vite dev 链 = src/dev.ts)
50
50
  apps/server/src/modules.ts # 服务端模块装配(registerAll)
51
51
  apps/server/src/module-ports.ts # 模块 ports 动态装配(LinkedPanel/bumpin 数据源;契约派生 + 漂移守卫)
52
- packages/provider-custom/src/server/index.ts # 自定义 API adapter 实施落点(指引见 packages/provider-custom/INTEGRATION.md)
53
- config/ # chat/model/plugin 配置
52
+ packages/provider-custom/src/server/index.ts # 自定义 API adapter 实施落点(指引:npx --yes @tbox.cn/app-cli skills get provider-custom)
53
+ config/ # 应用配置面(integrations/chat/agent 等,见 config/README.md)
54
54
  ```
55
55
 
56
56
  ## 运行与验证(平台沙箱)
57
57
 
58
58
  应用构建与运行在平台沙箱中,启动/停止/重启由平台负责——不要运行 `pnpm dev`、`pnpm start`
59
- 等长驻进程命令(沙箱规则 `config/rules/no-persistent-process.md`);`scripts/` 下生命周期
60
- 脚本(prepare/dev/start/stop/build)同样由平台调用。你只改代码与配置,用一次性命令验证:
59
+ 等长驻进程命令;`scripts/` 下生命周期脚本(prepare/dev/start/stop/build)同样由平台调用。
60
+ 验证走三级回路,按改动面选最小充分集:
61
+
62
+ | 改动 | 验证 | 命令 |
63
+ |---|---|---|
64
+ | 代码(类型/契约) | 静态 | `pnpm typecheck`(单模块 `pnpm --filter <pkg> typecheck` 秒级) |
65
+ | 集成/配置/新增模块 | 一次性运行时 | `pnpm smoke`(boot + browser 登录 + `/api/auth/me`,随机端口) |
66
+ | 看运行效果 | 8000 活体 | `curl -s http://127.0.0.1:8000/api/health` |
67
+
68
+ - **编译验证 = typecheck + smoke**;`pnpm smoke` 失败时先读尾部日志(fail-soft 配置降级在此可见)。
69
+ - **不要运行 `pnpm build` / `pnpm verify`**:冷构建超过沙箱命令时限(必超时),且 dev/smoke 不消费 `dist`;产物构建归平台生命周期脚本。
70
+ - `pnpm verify:fast` = typecheck + test + verify:generated + check(提交前静态收口)。
71
+ - `curl` 连接被拒绝 ≠ 应用损坏:平台在轮末自启服务,8000 空窗属正常态。
72
+ - 长驻进程纪律:不要用 `&`/`nohup` 方式自行拉起 server;一次性验证只允许 `pnpm smoke`(自带进程组清理)。
61
73
 
62
74
  ```sh
63
75
  pnpm install # 会话开始时 node_modules 缺失先装
64
76
  pnpm typecheck
65
77
  pnpm test
66
- pnpm build
67
- pnpm verify # typecheck + test + lint + build + verify:generated + check:inspector
78
+ pnpm smoke # 一次性运行时冒烟(随机端口,自动清理)
79
+ pnpm verify:fast # 静态收口(不含 build/lint)
68
80
  pnpm verify:generated # 装配一致 + 锚点完整 + 无裸露 import
69
81
  pnpm plugin:doctor # 插件排障
70
82
  pnpm plugin:inspect <pluginId> <toolId>
@@ -74,8 +86,8 @@ pnpm plugin:inspect <pluginId> <toolId>
74
86
 
75
87
  ## tbox-app CLI(模块与装配管理)
76
88
 
77
- CLI 免安装,命令均经 `npx --yes @tbox.cn/app-cli <cmd>` 运行(下表简写 `tbox-app`;完整
78
- 命令面 `tbox-app --help`)。add/remove/sync 后需 `pnpm install`:
89
+ CLI 免安装,命令一律以 `npx --yes @tbox.cn/app-cli <cmd>` 运行(完整命令面加 `--help`)。
90
+ add/remove/sync 后需 `pnpm install`:
79
91
 
80
92
  | 命令 | 用途 |
81
93
  |---|---|
@@ -83,17 +95,21 @@ CLI 免安装,命令均经 `npx --yes @tbox.cn/app-cli <cmd>` 运行(下表
83
95
  | `module remove <id>` | 卸载模块(见「删除模块」) |
84
96
  | `module list` / `sync` / `diff` / `doctor` | 已装清单 / 增量装配 / 漂移对比 / 结构校验 |
85
97
  | `module update <module>` | 升级模块(codegen → 3-way merge) |
98
+ | `module inspect [id]` | 能力/服务绑定矩阵(`--json` 机器可读) |
86
99
  | `new <module\|provider\|theme> <name>` | 应用内脚手架(生成 `packages/<id>` 并完成装配) |
87
100
  | `provider use / bind / unbind / unuse` | 集成绑定(写 `config/integrations.json`;v8 起自定义 API 统一 `provider-custom` 字符串厂商——CLI 全覆盖三层,含 `--module` 模块级单点绑定;bind/use 整槽覆盖既有 provider) |
101
+ | `provider use <p> --activate` | 应用默认厂商 + 该厂商供给面槽位批量激活(`*.snapshot` 聚合槽除外) |
102
+ | `skills list` / `skills get <topic>` | 流程知识(integration / provider-custom / verify / miniapp-container) |
103
+ | `schema [file]` | 配置形状(`config/integrations.json` / `tbox.module.json`) |
88
104
  | `theme use <id>` / `theme list` | 主题接线 / 状态 |
89
105
  | `starter --list` / `starter --type <type>` | starter 文档查询(商圈模块清单见 `--type agent-mall`) |
90
106
 
91
107
  ## 自定义服务集成(provider-custom)
92
108
 
93
109
  自定义 API = 服务的真实后端由你自己对接。收到「为某服务/模块/应用接入自定义 API」
94
- (或「对接我的 API」「先要接口清单」等同义说法)请求时:**完整流程、任务路由与接入
95
- 材料清单规范见应用根 `INTEGRATION.md`——先读它再动手**。本节不再展开(指引真源 =
96
- INTEGRATION.md,勿在本节扩展)。
110
+ (或「对接我的 API」「先要接口清单」等同义说法)请求时:**先执行
111
+ `npx --yes @tbox.cn/app-cli skills get integration` 读取完整流程、任务路由与接入材料清单
112
+ 规范,再动手**。本节不再展开(指引真源 = CLI skills,勿在本节扩展)。
97
113
 
98
114
  ## 删除模块
99
115
 
@@ -109,12 +125,12 @@ pnpm install
109
125
  死项 + doctor 复查。
110
126
  - 被其他模块 required 依赖时会阻止并列出依赖方:先删依赖方;`--force` 仅确认知情时使用。
111
127
  - 删除后跑 `pnpm typecheck`:`CardType` 随装配自动收缩,残留消费方会编译报错——按报错
112
- 清理引用后 `pnpm verify` 收尾。
128
+ 清理引用后 `pnpm verify:fast` 收尾。
113
129
  - 提示「contracts-mall 已无依赖者」时可再 `module remove contracts-mall` 恢复 SDK shim。
114
130
 
115
131
  ## 平台基础设施
116
132
 
117
- 以下链路受保护,不得删除或绕过(守卫随 `@tbox.cn/app-sdk` 分发:`pnpm check:inspector` / `tbox-inspector-check`,已入 `pnpm verify` 链):
133
+ 以下链路受保护,不得删除或绕过(守卫随 `@tbox.cn/app-sdk` 分发:`pnpm check:inspector` / `tbox-inspector-check`,已入 `pnpm check` 静态门禁):
118
134
 
119
135
  - `@tbox.cn/app-sdk/platform` 的 `installInspector`(`@infrastructure-locked`;`apps/server/src/index.ts` 从 `@tbox.cn/app-sdk/platform` import 并调用 `installInspector(app)`)
120
136
  - `apps/client/index.html` 中的 `/__vs_inspector__.js`(`RUNTIME_PATH` 约定不变)
@@ -151,4 +167,4 @@ pnpm install
151
167
 
152
168
  修改本应用任何代码时,导出面与装配文件的注释保持**自包含短文档**(用途 + 关键约束 +
153
169
  消费视角);不引用仓库内部路径与决策编号——它们对沙箱外的读者无意义。指引类内容
154
- 不写进注释:集成指引见 `INTEGRATION.md`(真源),本文件为发现入口。
170
+ 不写进注释:集成指引用 `npx --yes @tbox.cn/app-cli skills get integration`(真源),本文件为发现入口。
package/ENV.md CHANGED
@@ -23,7 +23,7 @@
23
23
  无 `instances` 键 = 无参考表(动态形态);env 未注入 → 占位 fail-fast 显性暴露。
24
24
  - 注入形态:mallId-only(miniAppId 尽力回填——root config `miniAppId` 优先、参考表
25
25
  attributes 兜底;双缺仍注入,不阻断默认商圈)。URL 显式参数 `?mallId=` 优先级更高。
26
- - 本地 mock 链:`tbox-app module add` 装 provider-mock(0.5.0 极简零配置——开箱免集成配置;
26
+ - 本地 mock 链:`npx --yes @tbox.cn/app-cli module add` 装 provider-mock(0.5.0 极简零配置——开箱免集成配置;
27
27
  动态配置验证面 → provider-mocktest,内部档 `pnpm dev mall-mocktest`)→ 生成器派生零拓扑
28
28
  integrations.json → 裸跑免 mallId 全局会话或任意 `?mallId=` 均可演示。零拓扑形态下 provider-mock 于 register 期
29
29
  声明隐式默认单实例(mall-demo / 星河 Mock 小镇)——无 URL 参数访问时默认商圈回显照常生效
@@ -55,17 +55,18 @@
55
55
 
56
56
  ## 应用配置(config/,非 env)
57
57
 
58
- `config/` 为应用配置目录(真实值经 `tbox-app create --config-dir <目录>` 合并注入,生成应用自包含;
58
+ `config/` 为应用配置目录(真实值经 `npx --yes @tbox.cn/app-cli create --config-dir <目录>` 合并注入,生成应用自包含;
59
59
  模板内为 demo 占位形态)。配置目录由 server entry 锚定解析(`__dirname` 3 级上溯 = 应用根,
60
60
  dev/src 与 prod/dist bundle 形态恒等):
61
61
 
62
62
  - `config/integrations.json`:provider 绑定与部署拓扑唯一真源(integrations v4:绑定组
63
63
  provider+implementation 从最特异层整组继承(instance > slot > domain > root),组内
64
64
  implementation 缺席经 catalog 派生;部署拓扑 = 顶层 `instances` 注册表 + `defaultInstanceId`;
65
- 槽 `instances` 键缺席 = 通配激活)。模板不内置——`tbox-app module add` 装入 local 供给
66
- (provider-mock / provider-mocktest——local 供给双包同语义)时由 CLI mock 绑定生成器自动派生零拓扑形态(root.provider + 全 local 槽
67
- 空对象);真厂商绑定经 `tbox-app provider use/bind` 或 `--config-dir` 真实素材注入。
68
- 自定义 API 接入操作指引(任务路由/材料清单/落声明/adapter 实施)见应用根 `INTEGRATION.md`。
65
+ 槽 `instances` 键缺席 = 通配激活)。模板出厂携带 pristine 种子(仅 `$comment` 指针 + `services: {}`)——
66
+ `npx --yes @tbox.cn/app-cli module add` 装入 local 供给(provider-mock / provider-mocktest——local 供给双包同语义)时,
67
+ CLI mock 绑定生成器视同缺席自动派生零拓扑形态(root.provider + 全 local 槽空对象,种子元键保全);
68
+ 真厂商绑定经 `npx --yes @tbox.cn/app-cli provider use/bind` 或 `--config-dir` 真实素材注入。
69
+ 自定义 API 接入操作指引(任务路由/材料清单/落声明/adapter 实施):`npx --yes @tbox.cn/app-cli skills get integration`。
69
70
  - `config/integrations.json` 顶层 `modules` 节:模块资源绑定(键 = 模块 install id,如
70
71
  `module-customer-service`;`resources.<resourceId> = { type: 'knowledge', datasetId | ref, topK?, scoreThreshold? }`)。
71
72
  经 SDK `createModuleResourceResolver`(zod discriminatedUnion + 无内联密钥断言)→ `app-config` 服务
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # template-agent
2
2
 
3
3
  tbox AI Agent 全栈模板(npm 包名 `@tbox.cn/app-template-agent`,唯一模板——W4 单一模板统一化),多包 pnpm workspace:`apps/` 薄组装端 + `packages/` 模块。
4
- 缺省出厂 = 带 AI 支付体验的 chat 形态;**商圈形态经 `profiles/mall` 画像加装**(`tbox-app create --profile mall`:mall-core + 七业务模块 + 商圈配置叠加)。
4
+ 缺省出厂 = 带 AI 支付体验的 chat 形态;**商圈形态经 `profiles/mall` 画像加装**(`npx --yes @tbox.cn/app-cli create --profile mall`:mall-core + 七业务模块 + 商圈配置叠加)。
5
5
  客户端同时支持浏览器和支付宝小程序 web-view;平台能力(鉴权/会话/TTS/ASR/上传/反馈)经 `@tbox.cn/app-sdk` 统一提供(007 下沉)。
6
6
 
7
7
  创建应用时按 `.tbox/default-modules.json` 加装 AI 支付模块,源码落在 `packages/module-ai-payment`。
8
8
 
9
- 创建应用时默认使用 `@tbox.cn/app-miniapp-container-alipay@0.2.5` 生成 `apps/miniapp-container-alipay`,容器计划见 `.tbox/miniapp-containers.json`。使用前配置小程序 AppId 和 H5 地址;重复创建保留已登记的容器。
9
+ 创建应用时默认使用 `@tbox.cn/app-miniapp-container-alipay@0.2.6` 生成 `apps/miniapp-container-alipay`,容器计划见 `.tbox/miniapp-containers.json`。使用前配置小程序 AppId 和 H5 地址;重复创建保留已登记的容器。
10
10
 
11
11
  `pnpm dev` 始终启动原有 H5/server;容器已安装且 PATH 中有 `minidev` 时同时启动容器,否则跳过。容器异常退出不影响 H5/server,Ctrl+C 统一停止本次启动的进程。
12
12
 
@@ -15,16 +15,17 @@ tbox AI Agent 全栈模板(npm 包名 `@tbox.cn/app-template-agent`,唯一
15
15
  ```sh
16
16
  pnpm install
17
17
  pnpm dev # H5/server + 可选 minidev 小程序容器
18
- pnpm verify # typecheck + test + build
18
+ pnpm smoke # 一次性运行时冒烟(随机端口)
19
+ pnpm verify:fast # typecheck + test + verify:generated + check
19
20
  ```
20
21
 
21
22
  **能力加装**(已有 AI 支付体验,能力即模块;mall 全套可改用 `create --profile mall` 一步到位):
22
23
 
23
24
  ```sh
24
- tbox-app module add shopping-guide # 导购/找店/业态/客服(模块级 intents + LLM 工具 + 卡片)
25
- tbox-app module add member # 会员卡/积分/优惠券(queryPoints preTool always 身份预执行)
26
- tbox-app module add parking promotion # 停车/活动(可选)
27
- tbox-app module doctor # 26 条结构校验
25
+ npx --yes @tbox.cn/app-cli module add shopping-guide # 导购/找店/业态/客服(模块级 intents + LLM 工具 + 卡片)
26
+ npx --yes @tbox.cn/app-cli module add member # 会员卡/积分/优惠券(queryPoints preTool always 身份预执行)
27
+ npx --yes @tbox.cn/app-cli module add parking promotion # 停车/活动(可选)
28
+ npx --yes @tbox.cn/app-cli module doctor # 30 条结构校验
28
29
  ```
29
30
 
30
31
  **MallHome 服务域**(015;`--profile mall` 加装 mall-core 后生效):家页 `packages/module-mall-core` 四域开箱——导购/会员/活动优惠(promotion)/停车服务(parking);域 query 走工具与意图路由链(模块 add/remove 即增删能力,无部署级门控)。
@@ -35,7 +36,7 @@ tbox-app module doctor # 26 条结构校验
35
36
  > 生产建议在 tbox 平台页面上配置(平台托管 env,密钥不进代码仓库)。
36
37
 
37
38
  > 平台包消费(005 v0.4.0 发布态):模板通过 `@app/contracts-mall` shim 使用 `catalog:` 引用的发布包;创建时默认安装 AI 支付模块,CLI 按依赖将 shim 替换为本地源码包——
38
- > 生产(registry 已发布)直接 `pnpm install`;平台包未发布 npm 时,由 `tbox-app create --local-deps <平台 tgz 目录>`
39
+ > 生产(registry 已发布)直接 `pnpm install`;平台包未发布 npm 时,由 `npx --yes @tbox.cn/app-cli create --local-deps <平台 tgz 目录>`
39
40
  > 注入 overrides(`file:` 本地发布态产物)后 install 离线可用。
40
41
  >
41
42
  > 依赖链说明(007):`@tbox.cn/app-sdk` 新增 dependencies `@tbox-dev-js/sdk`(平台能力客户端)、`@ai-sdk/openai-compatible`(LLM)——
@@ -56,7 +57,7 @@ template-agent/
56
57
  server/ Express + WS 装配端(~120 行装配:auth 中间件 + 模块挂载 + 平台路由面/TTS/WS)
57
58
  server/skills/ 本地 Skill(SKILL.md 目录格式,随模板复制/pack)
58
59
  packages/
59
- 模块目录(空装配:能力经 `tbox-app module add` 扩展——`@app/<id>` 成员在此生成)
60
+ 模块目录(空装配:能力经 `npx --yes @tbox.cn/app-cli module add` 扩展——`@app/<id>` 成员在此生成)
60
61
  config/ chat/model/plugin 配置
61
62
  scripts/ 构建、检查和平台脚本
62
63
  pnpm-workspace.template.yaml 应用 workspace 模板(create 生成应用 pnpm-workspace.yaml 的来源)
@@ -155,7 +156,7 @@ definePreTool(findStoreTool, {
155
156
  |---|---|---|
156
157
  | `getCurrentTime` | `apps/server/src/pre-tools.ts` + `tools/clock.ts` | 零参工程化(词表命中即执行) |
157
158
  | `mall-info` | `modules/module-mall-core`(W3-1 自模板迁入;`--profile mall`/module add 后经模块声明式 preTools 通道生效) | always + mall scope 入参化(每轮背景注入;会话内 dedup 一次) |
158
- | `queryPoints` | `modules/module-member`(`tbox-app module add member` 后) | `always` 必选 + 身份门控(identity 取 userId,匿名 skip) |
159
+ | `queryPoints` | `modules/module-member`(`npx --yes @tbox.cn/app-cli module add member` 后) | `always` 必选 + 身份门控(identity 取 userId,匿名 skip) |
159
160
  | `translate` | 反例(不改代码) | 参数依赖语义抽取,不适配——保持 LLM 工具路径 |
160
161
 
161
162
  ### 冒烟
@@ -164,7 +165,7 @@ definePreTool(findStoreTool, {
164
165
  # 启动日志:timeout + 预执行工具清单
165
166
  [PRETOOL] timeoutMs=2000 preTools=getCurrentTime
166
167
  # ①"现在几点了" → 「自动查询 查询当前日期和时间」→ 作答(零参形态)
167
- # ② 安装 member 后(tbox-app module add member)"我的积分有多少" → 「自动查询」徽标(always + 身份门控)→ 积分卡
168
+ # ② 安装 member 后(npx --yes @tbox.cn/app-cli module add member)"我的积分有多少" → 「自动查询」徽标(always + 身份门控)→ 积分卡
168
169
  # ③"帮我翻译 hello" → 无「自动查询」徽标(反例:正常 LLM 工具路径)
169
170
  # ④ TBOX_PRE_TOOL_TIMEOUT_MS=0 复测① → 回退为模型调用工具两轮(对比基准)
170
171
  # ⑤ 刷新页面 → 历史消息仍显示「已自动获取」徽标(inputs.preTools 重建)
@@ -190,7 +191,7 @@ UI 表现与编排(组件/hooks/容器/样式/id 前缀约定)、业务意
190
191
 
191
192
  > **发布态消费(005 v0.4.0)**:仓库内本模板是根 workspace 成员子树(无独立 `pnpm-workspace.yaml`/lock),
192
193
  > 平台引用 `catalog:` + 根 `pnpm-workspace.yaml` `overrides: workspace:*` 回指根 `packages/` 真源;
193
- > `tbox-app create` 从模板源(目录、pack tgz 或 registry 包 `@tbox.cn/app-template-agent[@version]`)展开生成应用——
194
+ > `npx --yes @tbox.cn/app-cli create` 从模板源(目录、pack tgz 或 registry 包 `@tbox.cn/app-template-agent[@version]`)展开生成应用——
194
195
  > 生成应用**不含平台成员**,平台包经注入 overrides(`file:` 本地 tgz,验证态)或 registry(生产态)安装;
195
196
  > `pnpm-workspace.yaml` 由 `pnpm-workspace.template.yaml` 改名生成。CLI 未安装时:`pnpm add -g @tbox.cn/app-cli`。
196
197
 
@@ -3,7 +3,7 @@ import AgentChatApp from '@/platform/AgentChatApp';
3
3
  /**
4
4
  * 业务应用唯一入口。
5
5
  * mall 模板:空态首屏由 IndexPage 内 MallHome 呈现(商圈主屏),无需 landing 注入;
6
- * 业务能力经 `tbox-app module add` 扩展(shopping-guide/member 等)。
6
+ * 业务能力经 `npx --yes @tbox.cn/app-cli module add` 扩展(shopping-guide/member 等)。
7
7
  * 新应用替换本组件;需要定制首屏时组合 AgentChatApp 或改 pages/index。
8
8
  */
9
9
  export default function BusinessApp() {
@@ -1,8 +1,8 @@
1
1
  # Business application entry
2
2
 
3
- `App.tsx` 是业务应用的唯一入口。缺省出厂 = 空装配 chat 形态(`AgentChatApp` 直出对话流,无 landing 注入——014 已退役)。商圈形态经 `tbox-app create --profile mall` 加装:mall-core 模块经 home 槽供给联单式主屏(欢迎区 + 单一联单活动主卡 + 会员/停车双快览 + 四域开发测试入口),消息追加在首页内容下方,底部保留三枚快捷指令与输入区。四域开发测试入口可见性由后端开关控制(`MALL_HOME_DEV_SERVICES` env → `GET /api/m/mall-core/config`,fail-closed 缺省隐藏;详见模板 ENV.md)。会员快览严格区分登录与入会状态,仅对已入会用户展示服务端返回的真实积分。
3
+ `App.tsx` 是业务应用的唯一入口。缺省出厂 = 空装配 chat 形态(`AgentChatApp` 直出对话流,无 landing 注入——014 已退役)。商圈形态经 `npx --yes @tbox.cn/app-cli create --profile mall` 加装:mall-core 模块经 home 槽供给联单式主屏(欢迎区 + 单一联单活动主卡 + 会员/停车双快览 + 四域开发测试入口),消息追加在首页内容下方,底部保留三枚快捷指令与输入区。四域开发测试入口可见性由后端开关控制(`MALL_HOME_DEV_SERVICES` env → `GET /api/m/mall-core/config`,fail-closed 缺省隐藏;详见模板 ENV.md)。会员快览严格区分登录与入会状态,仅对已入会用户展示服务端返回的真实积分。
4
4
 
5
- 业务能力经 `tbox-app module add` 扩展(shopping-guide/member/parking/promotion/alipay-activity),安装后自动装配进双端 `modules.ts`;联单节点是支付宝活动回执的支付笔数投影(mall-core 家页面),不从会话业务卡或本地默认值派生。生成完成后运行 `pnpm verify:generated`。
5
+ 业务能力经 `npx --yes @tbox.cn/app-cli module add` 扩展(shopping-guide/member/parking/promotion/alipay-activity),安装后自动装配进双端 `modules.ts`;联单节点是支付宝活动回执的支付笔数投影(mall-core 家页面),不从会话业务卡或本地默认值派生。生成完成后运行 `pnpm verify:generated`。
6
6
 
7
7
  ## 本地交互应用
8
8
 
@@ -8,7 +8,7 @@
8
8
  import type { ClientContext, InferModuleCards } from '@tbox.cn/app-agent-sdk-client';
9
9
 
10
10
  // @tbox:imports-begin
11
- // 其余能力经 `tbox-app module add` 扩展(shopping-guide/member 等商圈模块;mall-core 经 profiles/mall)
11
+ // 其余能力经 `npx --yes @tbox.cn/app-cli module add` 扩展(shopping-guide/member 等商圈模块;mall-core 经 profiles/mall)
12
12
  // @tbox:imports-end
13
13
 
14
14
  // @tbox:register-begin
@@ -15,7 +15,7 @@ import { serverModule as providerCustom } from '@app/provider-custom/server';
15
15
 
16
16
  // @tbox:register-begin
17
17
  // 单一模板统一化:缺省出厂 = 空装配(仅 provider-custom 自定义 API 落点 + contracts-mall shim)——
18
- // mall 能力(mall-core + 业务模块)经 profiles/mall 加装(tbox-app create --profile mall, 接线)
18
+ // mall 能力(mall-core + 业务模块)经 profiles/mall 加装(npx --yes @tbox.cn/app-cli create --profile mall, 接线)
19
19
  // footer `] as const` 为空数组类型锚(CLI 增删模块时保留变体)
20
20
  const modules = [
21
21
  providerCustom,
@@ -37,9 +37,11 @@ describe('工具 / 卡片 registry 一致性(自注册闭环)', () => {
37
37
  });
38
38
 
39
39
  it('插件装配读取根目录 config/plugins.json', () => {
40
+ // 断言面边界:plugins 是配置形状(恒真面);warnings 是用户配置衍生的 advisory 运行态
41
+ // (合法配置也可能产生),只断形状不断空值(testing/2026-10-20-template-shipped-test-boundary.md)。
40
42
  expect(createPluginIntegration().readConfig()).toMatchObject({
41
43
  plugins: expect.any(Array),
42
- warnings: [],
44
+ warnings: expect.any(Array),
43
45
  });
44
46
  });
45
47
  });
@@ -0,0 +1,20 @@
1
+ # config/ —— 应用配置面
2
+
3
+ | 文件 | 用途 | 加载失败 |
4
+ |---|---|---|
5
+ | `integrations.json` | 服务绑定/激活/实例/凭据引用 | **boot-fatal**(strict zod;拼错键启动即报) |
6
+ | `chat.json` | 对话运行时参数 | fail-soft(静默降级) |
7
+ | `llm_provider.json` | 模型与 provider | fail-soft |
8
+ | `plugins.json` | 插件清单 | fail-soft |
9
+ | `agent.jsonc` | Agent 提示词/画像(JSONC,允许注释与尾逗号;mall 画像按需生成) | fail-soft |
10
+ | `knowledge.json` | 知识库资源(按需生成) | fail-soft |
11
+ | `service-slots.json` | 服务词汇引导快照(create 按需生成;可由 module sync 重算) | fail-soft |
12
+
13
+ - 形状查询:`npx --yes @tbox.cn/app-cli schema config/integrations.json`
14
+ - 全部配置面:`npx --yes @tbox.cn/app-cli schema`
15
+ - 流程知识:`npx --yes @tbox.cn/app-cli skills get integration` / `skills get provider-custom`
16
+ - 校验:`npx --yes @tbox.cn/app-cli module doctor`(㉙ config-schema)
17
+ - 密钥真值只放平台凭据/环境变量,**不要写进本目录的 `config.*` 字段**。
18
+
19
+ 元键 `$comment` / `$schema` 仅作为文档指针,行为惰性;`agent.jsonc` 与 `plugins.json`
20
+ 不写入元键(前者 strict 形状、后者由外部插件 loader 解释)。
@@ -0,0 +1,4 @@
1
+ {
2
+ "$comment": "配置形状: npx --yes @tbox.cn/app-cli schema config/integrations.json;接入流程: npx --yes @tbox.cn/app-cli skills get integration",
3
+ "services": {}
4
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tbox.cn/app-template-agent",
3
- "version": "0.10.20",
4
- "description": "tbox AI Agent 全栈模板(多包 pnpm workspace):apps/client + apps/server。唯一模板(W4 单一模板统一化:缺省带 AI 支付体验的 chat 形态;mall 能力经 profiles/mall 加装),能力经 tbox-app module add 模块扩展(shopping-guide/member 等)。",
3
+ "version": "0.10.22",
4
+ "description": "tbox AI Agent 全栈模板(多包 pnpm workspace):apps/client + apps/server。唯一模板(W4 单一模板统一化:缺省带 AI 支付体验的 chat 形态;mall 能力经 profiles/mall 加装),能力经 CLI module add 模块扩展(shopping-guide/member 等)。",
5
5
  "engines": {
6
6
  "node": ">=24.0.0 <25.0.0"
7
7
  },
@@ -22,7 +22,6 @@
22
22
  ".gitignore",
23
23
  ".nvmrc",
24
24
  "AGENTS.md",
25
- "INTEGRATION.md",
26
25
  "ENV.md",
27
26
  "LEGAL.md",
28
27
  "README.md",
@@ -50,7 +49,9 @@
50
49
  "typecheck": "pnpm -r --filter \"./{apps,packages}/*\" typecheck",
51
50
  "test": "pnpm -r --filter \"./{apps,packages}/*\" test",
52
51
  "lint": "eslint apps $(find packages -mindepth 1 -maxdepth 1 -type d -print -quit 2>/dev/null | grep -q . && echo packages)",
53
- "verify": "pnpm typecheck && pnpm test && pnpm lint && pnpm build && pnpm verify:generated && pnpm check:inspector",
52
+ "smoke": "node scripts/smoke.mjs",
53
+ "verify": "pnpm typecheck && pnpm test && pnpm lint && pnpm build && pnpm smoke --self-test && pnpm verify:generated && pnpm check:inspector",
54
+ "verify:fast": "pnpm typecheck && pnpm test && pnpm verify:generated && pnpm check",
54
55
  "verify:generated": "node scripts/verify-generated.mjs",
55
56
  "check": "pnpm check:workspace && pnpm check:inspector",
56
57
  "check:workspace": "node scripts/check-workspace.mjs",
@@ -1,41 +1,27 @@
1
1
  # provider-custom —— 自定义 API 实施落点(AI 集成指引)
2
2
 
3
- 本包是**自定义 API(内联声明)的 adapter 代码落点**:某服务槽在 `config/integrations.json`
4
- 保存内联声明(provider 为对象 + implementation 字面量)而 adapter 未实施时,服务调用报
5
- `PROVIDER_NOT_IMPLEMENTED`——按指引实施并注册命中后即恢复。
3
+ 本包是自定义 API 的 adapter 代码落点:某服务槽声明 `provider-custom` 而 adapter 未实施时,
4
+ 服务调用报 `PROVIDER_NOT_IMPLEMENTED`——按指引实施并注册命中后即恢复。
6
5
 
7
- 收到接入请求或需要实施排障时:**完整实施指引(实施三步 / 声明形态对照 / 可复制 JSON
8
- 片段 / 代码骨架 / provider 名三处一致 / 认证与凭据 / 完成判据)见本包 `INTEGRATION.md`
9
- ——先读它再动手**。接入材料清单规范与任务路由见应用根 `INTEGRATION.md`。
6
+ **先读流程知识(随 CLI 发布,无需安装)**:
10
7
 
11
- ## 实施三步
8
+ ```sh
9
+ npx --yes @tbox.cn/app-cli skills get provider-custom # 实施三步/声明形态/代码骨架/注册/凭据
10
+ npx --yes @tbox.cn/app-cli skills get integration # 接入材料清单与任务路由
11
+ ```
12
12
 
13
- 见本包 `INTEGRATION.md`「实施三步」。
14
-
15
- ## 声明形态 ⇔ 实现落点(先选对形态再动手)
16
-
17
- 见本包 `INTEGRATION.md`「声明形态 ⇔ 实现落点」。
18
-
19
- ## 内联声明 JSON 片段(可复制形态)
20
-
21
- 见本包 `INTEGRATION.md`「内联声明 JSON 片段」。
22
-
23
- ## 最小代码骨架
24
-
25
- 见本包 `INTEGRATION.md`「最小代码骨架」。
13
+ 代码骨架、参数模板、注册形态与凭据见 `npx --yes @tbox.cn/app-cli skills get provider-custom`;
14
+ 模板出厂形态另含完整未接线参考实现 `src/server/example-adapter.ts`(registry 安装形态无此文件——
15
+ 以上述骨架为准)。
26
16
 
27
17
  ## provider 名三处一致
28
18
 
29
- 见本包 `INTEGRATION.md`「provider 名三处一致」(全仓唯一真源在本节对应处)。
19
+ 声明侧(`config/integrations.json`)、注册侧(`src/server/index.ts` 的
20
+ `registerAdapter` 第一参)、凭据侧(`config/credentials/<provider>-<service>.json` stem)
21
+ 必须同名。完整规则见 `npx --yes @tbox.cn/app-cli skills get provider-custom`。
30
22
 
31
23
  ## 认证与凭据
32
24
 
33
- 见本包 `INTEGRATION.md`「认证与凭据」(含 config/configSchema/凭据数据可见性边界表)。
34
-
35
- ## 完成判据
36
-
37
- 见本包 `INTEGRATION.md`「完成判据」。
38
-
39
- ## 真实厂商接入
40
-
41
- 见本包 `INTEGRATION.md`「真实厂商接入」。
25
+ 凭据真值只进 `config/credentials/<stem>.json` 嵌套形或平台 env;禁止写入 prompt、源码或
26
+ `integrations.json` 的 `config.*`。完整形态(static-headers-v1 / 自定义策略 /
27
+ 数据可见性边界)见 `npx --yes @tbox.cn/app-cli skills get provider-custom`「认证与凭据」。
@@ -1,8 +1,9 @@
1
1
  # @tbox.cn/app-provider-custom
2
2
 
3
- 自定义厂商实施落点空包(与 provider-mock / provider-mocktest 并列的中立空壳):manifest contributes 全空(零贡献
3
+ 自定义厂商实施落点空包(与 provider-mock / provider-mocktest 并列的中立空壳):manifest declare 全空(零贡献
4
4
  合法——descriptor zod 全 default),出厂无任何供给/需求/卡片声明,纯为 AI 实施自定义 API
5
5
  adapter 提供**有形代码落点**。闭环机制见 AGENTS.md(SDK 零改动——registerAdapter 命中即转 ok)。
6
6
 
7
- 单包多厂商:多个自定义 API 的 adapter 均在此包注册。依赖精确裁剪 = app-sdk + app-contracts
8
- (不消费领域 Port 类型,无 contracts-mall);无 client 入口;无 peerDependencies。
7
+ 单包多厂商:多个自定义 API 的 adapter 均在此包注册。运行依赖精确裁剪 = app-sdk + app-contracts;
8
+ 领域 Port 仅以 `import type` 出现在模板镜像的 `src/server/example-adapter.ts`(devDependency
9
+ `@app/contracts-mall`,零运行依赖);无 client 入口;无 peerDependencies。
@@ -29,7 +29,8 @@
29
29
  "@types/node": "24.13.3",
30
30
  "typescript": "5.9.3",
31
31
  "vitest": "4.1.10",
32
- "tsup": "8.5.1"
32
+ "tsup": "8.5.1",
33
+ "@app/contracts-mall": "workspace:*"
33
34
  },
34
35
  "files": [
35
36
  "dist",
@@ -39,7 +40,6 @@
39
40
  "tsconfig.json",
40
41
  "tsup.config.ts",
41
42
  "AGENTS.md",
42
- "INTEGRATION.md",
43
43
  "README.md",
44
44
  "LICENSE"
45
45
  ],
@@ -0,0 +1,58 @@
1
+ /**
2
+ * 完整参考实现(未接线——复制改造我)。
3
+ *
4
+ * 形态:字符串厂商 `provider-custom` 的多服务分支 factory。真实接入步骤见
5
+ * `npx --yes @tbox.cn/app-cli skills get provider-custom`:
6
+ * 1. 在 tbox.module.json `declare.providers.slots` 声明供给槽(消费 config 键的槽同步声明
7
+ * configSchema 参数模板——见 `skills get provider-custom`「参数模板声明」);
8
+ * 2. 复制本文件为 `<你的服务>.ts`,替换 Port 类型与方法实现;
9
+ * 3. 在 index.ts register 中 `ctx.integrations?.registerAdapter('provider-custom', '<implementation>', factory)`;
10
+ * 4. 绑定并验证:`provider bind <slot> provider-custom` + `pnpm smoke` +
11
+ * `npx --yes @tbox.cn/app-cli module doctor`。
12
+ *
13
+ * 本文件不注册、不声明槽位——零行为,仅作为可复制模板。
14
+ */
15
+ import type { ServiceAdapterFactory } from '@tbox.cn/app-agent-sdk-server';
16
+ import type { MallInfo, MallInfoPort } from '@app/contracts-mall';
17
+
18
+ interface MallInfoResponse {
19
+ name?: unknown;
20
+ address?: unknown;
21
+ latitude?: unknown;
22
+ longitude?: unknown;
23
+ cityId?: unknown;
24
+ }
25
+
26
+ export const mallInfoExampleFactory: ServiceAdapterFactory = (input) => {
27
+ // 多服务单键:按 input.service 分支返回各 Port 实现。
28
+ if (input.service === 'mall.info') {
29
+ const port: MallInfoPort = {
30
+ async getMallInfo(mallId: string): Promise<MallInfo | undefined> {
31
+ // 实现方负责形状守卫(防 path 注入进上游 URL)。
32
+ if (!/^[A-Za-z0-9_-]+$/.test(mallId)) return undefined;
33
+ // 惰性凭据:未配置 credentialRef → undefined;真实值不进代码/配置明文。
34
+ // 真实实现通常把 credential.value 映射为签名/请求头;此处仅演示读取时机。
35
+ const credential = input.credential?.();
36
+ void credential;
37
+ const timeoutMs = typeof input.config.timeoutMs === 'number' ? input.config.timeoutMs : undefined;
38
+ const response = (await input.transport.request({
39
+ path: `/v1/malls/${encodeURIComponent(mallId)}`,
40
+ method: 'GET',
41
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
42
+ })) as MallInfoResponse;
43
+ if (!response || typeof response.name !== 'string') return undefined;
44
+ return {
45
+ mallId,
46
+ name: response.name,
47
+ ...(typeof response.address === 'string' ? { address: response.address } : {}),
48
+ ...(typeof response.latitude === 'number' ? { latitude: response.latitude } : {}),
49
+ ...(typeof response.longitude === 'number' ? { longitude: response.longitude } : {}),
50
+ ...(typeof response.cityId === 'string' ? { cityId: response.cityId } : {}),
51
+ };
52
+ },
53
+ };
54
+ return port;
55
+ }
56
+ // 其他服务:继续分支,或返回 undefined(未命中 = 该槽不由此 factory 供给)。
57
+ return undefined;
58
+ };
@@ -2,15 +2,15 @@
2
2
  * 自定义厂商实施落点空包·服务端入口(单包多厂商——多个自定义 API 的
3
3
  * adapter 均在此包 register,注册表双键不关心包边界)。
4
4
  *
5
- * 零贡献合法(manifest contributes 全空——descriptor zod 全 default):本包出厂无任何
5
+ * 零贡献合法(manifest declare 全空——descriptor zod 全 default):本包出厂无任何
6
6
  * 供给/需求/卡片声明,纯为 AI 实施自定义 API adapter 提供**有形代码落点**。运行时闭环:
7
- * 1. 某服务槽保存自定义 API 内联声明(integrations.json:provider 对象 + implementation 字面量);
7
+ * 1. 某服务槽声明厂商(推荐字符串 `provider-custom`;存量内联对象读兼容);
8
8
  * 2. 服务调用解析该绑定 → adapter 未注册 → PROVIDER_NOT_IMPLEMENTED(fail-visible);
9
- * 3. AI 按本包 AGENTS.md 指引实现 adapter 并在 register 挂载
9
+ * 3. AI 按 `npx --yes @tbox.cn/app-cli skills get provider-custom` 指引实现 adapter 并在 register 挂载
10
10
  * ctx.integrations?.registerAdapter(provider, 'inline', factory);
11
11
  * 4. 平台重启后 register 命中 → 该服务调用恢复正常(完成信号)。
12
12
  *
13
- * 真实厂商接入(官方 provider 包形态:manifest 槽声明 + 独立包发布)跳转见 AGENTS.md。
13
+ * 真实厂商接入(官方 provider 包形态:manifest 槽声明 + 独立包发布)见 skills get provider-custom。
14
14
  */
15
15
  import type { ServerContext, ServerModule } from '@tbox.cn/app-agent-sdk-server';
16
16
 
@@ -28,8 +28,9 @@ export const PROVIDER_CUSTOM = 'provider-custom';
28
28
  * // input.credential?.() 惰性凭据 getter(返回 { scope, type, value };未配 → undefined)
29
29
  * return new MyApiServiceImpl(input);
30
30
  * };
31
- * // 注册键 implementation 段恒为 'inline'(内联声明运行时按合成 'inline' 寻址):
32
- * ctx.integrations?.registerAdapter('my-custom-api', 'inline', myApiAdapterFactory);
31
+ * // 字符串声明(推荐):registerAdapter('provider-custom', '<implementation>', factory)
32
+ * // 内联对象声明(存量):registerAdapter('<provider 名>', 'inline', factory)
33
+ * ctx.integrations?.registerAdapter('provider-custom', '<implementation>', myApiAdapterFactory);
33
34
  */
34
35
  export function register(ctx: ServerContext): void {
35
36
  // 挂点:多个自定义 API 的 adapter 均在此注册(见上方签名示例)。
@@ -2,16 +2,14 @@ import { describe, expect, it } from 'vitest';
2
2
  import { providerId } from '../src/index';
3
3
  import { serverModule } from '../src/server/index';
4
4
 
5
- describe('provider-custom 空包(D10 落点)', () => {
6
- it('serverModule 形状:moduleId + 空 cards + register 可调用', () => {
5
+ // 模块身份守卫:moduleId/providerId 与包身份恒等——register 键为运行时绑定锚(registry
6
+ // 解析 / doctor 对账),误改即红灯。刻意不断言声明内容与 register 行为:那是应用实施面
7
+ // (AGENTS.md/INTEGRATION.md 指引),本测试随包分发进生成应用,不得钉死用户实施
8
+ // (testing/2026-10-20-template-shipped-test-boundary.md)。
9
+ describe('provider-custom 模块身份(D10 落点)', () => {
10
+ it('register 键与包身份一致', () => {
7
11
  expect(serverModule.declaration.moduleId).toBe('provider-custom');
8
- expect(serverModule.cards).toEqual({});
9
- expect(typeof serverModule.register).toBe('function');
10
12
  expect(providerId).toBe('provider-custom');
11
- });
12
-
13
- it('register 零贡献:调用不抛(mock ctx 无 integrations 挂点)', () => {
14
- const ctx = {} as never;
15
- expect(() => serverModule.register(ctx)).not.toThrow();
13
+ expect(typeof serverModule.register).toBe('function');
16
14
  });
17
15
  });