dsh-calorie 0.1.1 → 0.1.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/client.js CHANGED
@@ -1,20 +1,199 @@
1
- /** dsh-calorie 客户端存根(P10 脚手架)。
2
- *
3
- * 写死槽位原生组件,不做动态按需加载,不做外嵌页。
4
- * 面板取数只经 host.call 进 host 桥(见 bridge.ts),不 import 技能实现。
5
- * 缺席纯条件渲染,无轮询(本文件无任何定时器)。
6
- */
7
- import { TAB_COMPONENT, registerSingle, openSingle } from './slot.js';
8
- import { HOST_CALL_METHOD } from './bridge.js';
9
- export const CLIENT_COMPONENT = TAB_COMPONENT;
10
- export const CLIENT_METHOD = HOST_CALL_METHOD;
11
- export function mountSingleClient(port) {
12
- return registerSingle(port);
13
- }
14
- export function openSingleClient(port, sessionId) {
15
- openSingle(port, sessionId);
16
- }
17
- export function requestReadViaHost(host, key, params = {}) {
18
- return host.call(HOST_CALL_METHOD, { key, params });
19
- }
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-calorie",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
29
+ let react = require("react");
30
+ react = __toESM(react, 1);
31
+ //#region src/contract.ts
32
+ /** dsh-calorie 端口(port):DSH 世界与卡路里 hexagon 之间的契约。
33
+ *
34
+ * browser 安全:零 node 导入。host 适配器(注册 RPC 通道)与 client
35
+ * 适配器(调用 RPC)共用同一份定义;单测与 loader 回路以此为准。
36
+ * 通道命名遵守宿主约束:单段且不等于 /api(见 cookbook「RPC 通道」)。
37
+ */
38
+ const RPC_CHANNEL = "/ilife-calorie";
39
+ const RPC_ENDPOINT_READ = "read";
40
+ /** 面板默认读键(与 HITL 一致性对比同键)。 */
41
+ const DEFAULT_READ_KEY = "calorie.view.home";
42
+ //#endregion
43
+ //#region src/slot.ts
44
+ const SLOT_TITLE = "卡路里";
45
+ //#endregion
46
+ //#region src/settings.ts
47
+ /** 脚手架期唯一设置行:总开关(缺省启用,与官方关闭语义对齐)。 */
48
+ const SETTING_ROWS = [{
49
+ key: "enabled",
50
+ title: "卡路里面板启用",
51
+ control: "switch"
52
+ }];
53
+ //#endregion
54
+ //#region src/client.ts
55
+ /** dsh-calorie client 适配器(六边形:port=contract+dsh-ctx 镜像,adapter=本文件)。
56
+ *
57
+ * 产物经 tsdown 打成 loader 工厂包(browser/CJS,见 tsdown.config.ts)。
58
+ * 本文件传递闭包:禁 node、禁 DOM 直写(document/window/process)、禁定时器/轮询。
59
+ * 只用 dsh-ctx 镜像内成员(slots.inject/register、connection.rpc.call);
60
+ * 取数只经 connection.rpc.call 进 host 通道;缺席/错误纯条件渲染,不返空冒充。
61
+ * 组件 React.createElement 手写,不引入 JSX 构建复杂度。
62
+ */
63
+ const inject = ["slots", "connection"];
64
+ /** 本地今日 YYYY-MM-DD(与面板默认读键的 date 参数同形)。 */
65
+ function todayString() {
66
+ const d = /* @__PURE__ */ new Date();
67
+ const m = String(d.getMonth() + 1).padStart(2, "0");
68
+ const day = String(d.getDate()).padStart(2, "0");
69
+ return `${d.getFullYear()}-${m}-${day}`;
70
+ }
71
+ /** 数据态取值:有 total 显示 total,有值无 total 显示原值 JSON,空值返回 null(由调用方进错误态)。 */
72
+ function extractTotal(value) {
73
+ if (value === null || value === void 0) return null;
74
+ if (typeof value === "string") return value.length > 0 ? value : null;
75
+ if (typeof value === "object") {
76
+ const total = value.total;
77
+ if (total !== null && total !== void 0) return String(total);
78
+ try {
79
+ return JSON.stringify(value);
80
+ } catch {
81
+ return null;
82
+ }
83
+ }
84
+ return String(value);
85
+ }
86
+ function isEnvelope(raw) {
87
+ if (typeof raw !== "object" || raw === null) return false;
88
+ const ok = raw.ok;
89
+ return ok === true || ok === false;
90
+ }
91
+ /** 卡路里面板:挂载期一次 RPC,无轮询;loading / 数据 / 缺席或错误三态。 */
92
+ function CaloriePanel(props) {
93
+ const [state, setState] = react.useState({ kind: "loading" });
94
+ react.useEffect(() => {
95
+ let alive = true;
96
+ const date = todayString();
97
+ const call = props.call;
98
+ (async () => {
99
+ if (typeof call !== "function") {
100
+ if (alive) setState({
101
+ kind: "absent",
102
+ message: "宿主连接缺席:connection.rpc.call 不可用"
103
+ });
104
+ return;
105
+ }
106
+ let result;
107
+ try {
108
+ const raw = await call(RPC_CHANNEL, RPC_ENDPOINT_READ, {
109
+ key: DEFAULT_READ_KEY,
110
+ params: { date }
111
+ });
112
+ if (!isEnvelope(raw)) {
113
+ if (alive) setState({
114
+ kind: "error",
115
+ message: "回执信封异常(非 ok 信封)"
116
+ });
117
+ return;
118
+ }
119
+ result = raw;
120
+ } catch (e) {
121
+ if (alive) setState({
122
+ kind: "error",
123
+ message: `取数失败:${e instanceof Error ? e.message : String(e)}`
124
+ });
125
+ return;
126
+ }
127
+ if (!alive) return;
128
+ if (!result.ok) {
129
+ const code = result.error?.code ?? "unknown";
130
+ const message = result.error?.message ?? "";
131
+ if (code === "missing-cli") setState({
132
+ kind: "absent",
133
+ message: `技能出口缺席(missing-cli):${message}`
134
+ });
135
+ else setState({
136
+ kind: "error",
137
+ message: `取数失败(${code}):${message}`
138
+ });
139
+ return;
140
+ }
141
+ const total = extractTotal(result.value);
142
+ if (total === null) {
143
+ setState({
144
+ kind: "error",
145
+ message: "取数为空(不冒充正常)"
146
+ });
147
+ return;
148
+ }
149
+ setState({
150
+ kind: "data",
151
+ date,
152
+ total
153
+ });
154
+ })();
155
+ return () => {
156
+ alive = false;
157
+ };
158
+ }, [props.call]);
159
+ if (state.kind === "loading") return react.createElement("div", null, "卡路里加载中…");
160
+ if (state.kind === "data") return react.createElement("div", null, react.createElement("div", null, `卡路里 · ${state.date}`), react.createElement("div", null, `total ${state.total}`));
161
+ return react.createElement("div", null, state.message);
162
+ }
163
+ /** 边栏入口:标题 + 面板同体,紧凑只读。 */
164
+ function CalorieAction(props) {
165
+ return react.createElement("div", null, react.createElement("div", null, SLOT_TITLE), react.createElement(CaloriePanel, { call: props.call }));
166
+ }
167
+ function controlLabel(control) {
168
+ if (control === "switch") return "开关(缺省启用,只读)";
169
+ if (control === "text") return "文本(只读)";
170
+ if (control === "number") return "数字(只读)";
171
+ return `${control}(只读)`;
172
+ }
173
+ /** 设置卡:面板 + 设置行只读呈现(禁做假开关,无交互控件)。 */
174
+ function CalorieSettings(props) {
175
+ return react.createElement("div", null, react.createElement(CaloriePanel, { call: props.call }), react.createElement("div", null, SETTING_ROWS.map((row) => react.createElement("div", { key: row.key }, `${row.title} · ${controlLabel(row.control)}`))));
176
+ }
177
+ function apply(ctx) {
178
+ const call = ctx.connection?.rpc?.call ?? null;
179
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
180
+ name: "settings.section",
181
+ id: "dsh-calorie",
182
+ order: 23,
183
+ label: () => SLOT_TITLE,
184
+ inject: () => ({})
185
+ }, () => react.createElement(CalorieSettings, { call })));
186
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
187
+ name: "sidebar.footer.action",
188
+ id: "dsh-calorie",
189
+ order: 75
190
+ }, () => react.createElement(CalorieAction, { call })));
191
+ }
192
+ //#endregion
193
+ exports.apply = apply;
194
+ exports.inject = inject;
195
+ return module.exports;
196
+ }
197
+ });
198
+
20
199
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAM/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAC9C,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAE9C,MAAM,UAAU,iBAAiB,CAAC,IAAc;IAC9C,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAc,EAAE,SAAkB;IACjE,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAgB,EAAE,GAAW,EAAE,SAAkC,EAAE;IACpG,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;AACtD,CAAC"}
1
+ {"version":3,"file":"client.js","names":["React"],"sources":["../src/contract.ts","../src/slot.ts","../src/settings.ts","../src/client.ts"],"sourcesContent":["/** dsh-calorie 端口(port):DSH 世界与卡路里 hexagon 之间的契约。\n *\n * browser 安全:零 node 导入。host 适配器(注册 RPC 通道)与 client\n * 适配器(调用 RPC)共用同一份定义;单测与 loader 回路以此为准。\n * 通道命名遵守宿主约束:单段且不等于 /api(见 cookbook「RPC 通道」)。\n */\nexport const RPC_CHANNEL = '/ilife-calorie' as const;\nexport const RPC_ENDPOINT_READ = 'read' as const;\n\n/** 读请求载荷:与技能 CLI 的 key/params 同形(见 skill-calorie SKILL.md)。 */\nexport interface ReadPayload {\n readonly key: string;\n readonly params: Record<string, unknown>;\n}\n\nexport interface RpcError {\n readonly code: string;\n readonly message: string;\n readonly details: Record<string, unknown>;\n}\n\nexport type RpcResult =\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: RpcError };\n\nexport function ok(value: unknown): RpcResult {\n return { ok: true, value };\n}\n\nexport function fail(code: string, message: string): RpcResult {\n return { ok: false, error: { code, message, details: {} } };\n}\n\n/** 载荷校验:形状不对返回 null,由调用方按 bad-request 回绝(不抛)。 */\nexport function parseReadPayload(raw: unknown): ReadPayload | null {\n if (typeof raw !== 'object' || raw === null) return null;\n const { key, params } = raw as { key?: unknown; params?: unknown };\n if (typeof key !== 'string' || key.length === 0) return null;\n if (typeof params !== 'object' || params === null || Array.isArray(params)) return null;\n return { key, params: params as Record<string, unknown> };\n}\n\n/** 面板默认读键(与 HITL 一致性对比同键)。 */\nexport const DEFAULT_READ_KEY = 'calorie.view.home' as const;\n","/** dsh-calorie 槽位描述(P10 脚手架,P3 #4 定案)。\n *\n * 写死槽位原生组件:id 命名空间 ilife:calorie,order 75。\n * 注册与打开只走 registerTab/openTab 的路径导航;子页后缀(如 ilife:calorie:*)\n * 只在主面板内导航,不占栏。缺席纯条件渲染,不轮询(本文件无定时器;\n * 有界重试归一由 base-render 拥有,单品不自建)。\n */\n\nexport const SKILL = 'calorie' as const;\nexport const SLOT_ID = 'ilife:calorie' as const;\nexport const SLOT_ORDER = 75 as const;\nexport const SLOT_TITLE = '卡路里' as const;\nexport const PLUGIN = 'dsh-calorie' as const;\nexport const MANAGER_PLUGIN = 'dsh-life-pack' as const;\n\nexport interface SlotDescriptor {\n readonly skill: string;\n readonly slotId: string;\n readonly order: number;\n readonly title: string;\n readonly kind: 'page';\n}\n\nexport function slotDescriptor(): SlotDescriptor {\n return { skill: SKILL, slotId: SLOT_ID, order: SLOT_ORDER, title: SLOT_TITLE, kind: 'page' };\n}\n\n/** 写死原生组件描述(纯数据,无按需加载,无外嵌页)。 */\nexport const TAB_COMPONENT = { kind: 'native', name: 'CaloriePanel' } as const;\n\nexport interface TabsPort {\n hasTabs(): boolean;\n registerTab(entry: { readonly id: string; readonly title: string; readonly order: number; readonly single: boolean; readonly component: unknown }): () => void;\n openTab(seed: { readonly type: string; readonly path: string }, scope?: { readonly sessionId?: string }): void;\n}\n\n/** 自注册:幂等(调用方持 disposer),失败返回 false 由调用方决定重试。 */\nexport function registerSingle(port: TabsPort): (() => void) | null {\n if (!port.hasTabs()) return null;\n return port.registerTab({ id: SLOT_ID, title: SLOT_TITLE, order: SLOT_ORDER, single: true, component: TAB_COMPONENT });\n}\n\n/** 内容型打开:path seed,折叠面板自动展开。 */\nexport function openSingle(port: TabsPort, sessionId?: string): void {\n if (!port.hasTabs()) return;\n port.openTab({ type: SLOT_ID, path: SLOT_ID }, sessionId ? { sessionId } : undefined);\n}\n","/** dsh-calorie 设置页(P10 脚手架:设置页住单品包)。\n *\n * 一次 registerTab,两处呈现:边栏 + 号菜单多一项,DSH 设置页侧边卡片\n * 分区自动多一张小卡片(注册表驱动、无硬编码,开关缺省启用)。\n * 本文件只声明本单品自己的设置行;总管不声明设置(见 boundaries 断言)。\n */\n\nexport const SETTINGS_OWNER = 'dsh-calorie' as const;\nexport const SETTINGS_SLOT = 'ilife:calorie' as const;\n\nexport interface SettingRow {\n readonly key: string;\n readonly title: string;\n readonly control: 'switch' | 'text' | 'number';\n}\n\n/** 脚手架期唯一设置行:总开关(缺省启用,与官方关闭语义对齐)。 */\nexport const SETTING_ROWS: readonly SettingRow[] = [\n { key: 'enabled', title: '卡路里面板启用', control: 'switch' },\n];\n","/** dsh-calorie client 适配器(六边形:port=contract+dsh-ctx 镜像,adapter=本文件)。\n *\n * 产物经 tsdown 打成 loader 工厂包(browser/CJS,见 tsdown.config.ts)。\n * 本文件传递闭包:禁 node、禁 DOM 直写(document/window/process)、禁定时器/轮询。\n * 只用 dsh-ctx 镜像内成员(slots.inject/register、connection.rpc.call);\n * 取数只经 connection.rpc.call 进 host 通道;缺席/错误纯条件渲染,不返空冒充。\n * 组件 React.createElement 手写,不引入 JSX 构建复杂度。\n */\nimport * as React from 'react';\nimport { RPC_CHANNEL, RPC_ENDPOINT_READ, DEFAULT_READ_KEY } from './contract.js';\nimport { SLOT_TITLE } from './slot.js';\nimport { SETTING_ROWS } from './settings.js';\nimport type { ClientCtx, RpcCallResult } from './dsh-ctx.js';\n\nexport const inject = ['slots', 'connection'];\n\ntype PanelState =\n | { readonly kind: 'loading' }\n | { readonly kind: 'data'; readonly date: string; readonly total: string }\n | { readonly kind: 'absent'; readonly message: string }\n | { readonly kind: 'error'; readonly message: string };\n\n/** 本地今日 YYYY-MM-DD(与面板默认读键的 date 参数同形)。 */\nfunction todayString(): string {\n const d = new Date();\n const m = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${d.getFullYear()}-${m}-${day}`;\n}\n\n/** 数据态取值:有 total 显示 total,有值无 total 显示原值 JSON,空值返回 null(由调用方进错误态)。 */\nfunction extractTotal(value: unknown): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'string') return value.length > 0 ? value : null;\n if (typeof value === 'object') {\n const total = (value as { total?: unknown }).total;\n if (total !== null && total !== undefined) return String(total);\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n }\n return String(value);\n}\n\nfunction isEnvelope(raw: unknown): raw is RpcCallResult {\n if (typeof raw !== 'object' || raw === null) return false;\n const ok = (raw as { ok?: unknown }).ok;\n return ok === true || ok === false;\n}\n\n/** 卡路里面板:挂载期一次 RPC,无轮询;loading / 数据 / 缺席或错误三态。 */\nfunction CaloriePanel(props: { call: unknown }): React.ReactElement {\n const [state, setState] = React.useState<PanelState>({ kind: 'loading' });\n React.useEffect(() => {\n let alive = true;\n const date = todayString();\n const call = props.call;\n (async () => {\n // extractRpc 同式守卫:非函数即缺席态。\n if (typeof call !== 'function') {\n if (alive) setState({ kind: 'absent', message: '宿主连接缺席:connection.rpc.call 不可用' });\n return;\n }\n let result: RpcCallResult;\n try {\n const raw: unknown = await call(RPC_CHANNEL, RPC_ENDPOINT_READ, {\n key: DEFAULT_READ_KEY,\n params: { date },\n });\n if (!isEnvelope(raw)) {\n if (alive) setState({ kind: 'error', message: '回执信封异常(非 ok 信封)' });\n return;\n }\n result = raw;\n } catch (e) {\n if (alive) setState({ kind: 'error', message: `取数失败:${e instanceof Error ? e.message : String(e)}` });\n return;\n }\n if (!alive) return;\n if (!result.ok) {\n const code = result.error?.code ?? 'unknown';\n const message = result.error?.message ?? '';\n if (code === 'missing-cli') {\n setState({ kind: 'absent', message: `技能出口缺席(missing-cli):${message}` });\n } else {\n setState({ kind: 'error', message: `取数失败(${code}):${message}` });\n }\n return;\n }\n const total = extractTotal(result.value);\n if (total === null) {\n setState({ kind: 'error', message: '取数为空(不冒充正常)' });\n return;\n }\n setState({ kind: 'data', date, total });\n })();\n return () => {\n alive = false;\n };\n }, [props.call]);\n if (state.kind === 'loading') {\n return React.createElement('div', null, '卡路里加载中…');\n }\n if (state.kind === 'data') {\n return React.createElement(\n 'div',\n null,\n React.createElement('div', null, `卡路里 · ${state.date}`),\n React.createElement('div', null, `total ${state.total}`),\n );\n }\n return React.createElement('div', null, state.message);\n}\n\n/** 边栏入口:标题 + 面板同体,紧凑只读。 */\nfunction CalorieAction(props: { call: unknown }): React.ReactElement {\n return React.createElement(\n 'div',\n null,\n React.createElement('div', null, SLOT_TITLE),\n React.createElement(CaloriePanel, { call: props.call }),\n );\n}\n\nfunction controlLabel(control: string): string {\n if (control === 'switch') return '开关(缺省启用,只读)';\n if (control === 'text') return '文本(只读)';\n if (control === 'number') return '数字(只读)';\n return `${control}(只读)`;\n}\n\n/** 设置卡:面板 + 设置行只读呈现(禁做假开关,无交互控件)。 */\nfunction CalorieSettings(props: { call: unknown }): React.ReactElement {\n return React.createElement(\n 'div',\n null,\n React.createElement(CaloriePanel, { call: props.call }),\n React.createElement(\n 'div',\n null,\n SETTING_ROWS.map((row) =>\n React.createElement('div', { key: row.key }, `${row.title} · ${controlLabel(row.control)}`),\n ),\n ),\n );\n}\n\nexport function apply(ctx: ClientCtx): void {\n // 调用口在注册期快照进组件 props(extractRpc 同式,非函数由组件判缺席)。\n const call: unknown = ctx.connection?.rpc?.call ?? null;\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register(\n {\n name: 'settings.section',\n id: 'dsh-calorie',\n order: 23,\n label: () => SLOT_TITLE,\n inject: () => ({}),\n },\n () => React.createElement(CalorieSettings, { call }),\n ),\n );\n ctx.slots.inject('sidebar.footer.action', () =>\n ctx.slots.register(\n {\n name: 'sidebar.footer.action',\n id: 'dsh-calorie',\n order: 75,\n },\n () => React.createElement(CalorieAction, { call }),\n ),\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /** dsh-calorie 端口(port):DSH 世界与卡路里 hexagon 之间的契约。
2
+ *
3
+ * browser 安全:零 node 导入。host 适配器(注册 RPC 通道)与 client
4
+ * 适配器(调用 RPC)共用同一份定义;单测与 loader 回路以此为准。
5
+ * 通道命名遵守宿主约束:单段且不等于 /api(见 cookbook「RPC 通道」)。
6
+ */
7
+ export declare const RPC_CHANNEL: "/ilife-calorie";
8
+ export declare const RPC_ENDPOINT_READ: "read";
9
+ /** 读请求载荷:与技能 CLI 的 key/params 同形(见 skill-calorie SKILL.md)。 */
10
+ export interface ReadPayload {
11
+ readonly key: string;
12
+ readonly params: Record<string, unknown>;
13
+ }
14
+ export interface RpcError {
15
+ readonly code: string;
16
+ readonly message: string;
17
+ readonly details: Record<string, unknown>;
18
+ }
19
+ export type RpcResult = {
20
+ readonly ok: true;
21
+ readonly value: unknown;
22
+ } | {
23
+ readonly ok: false;
24
+ readonly error: RpcError;
25
+ };
26
+ export declare function ok(value: unknown): RpcResult;
27
+ export declare function fail(code: string, message: string): RpcResult;
28
+ /** 载荷校验:形状不对返回 null,由调用方按 bad-request 回绝(不抛)。 */
29
+ export declare function parseReadPayload(raw: unknown): ReadPayload | null;
30
+ /** 面板默认读键(与 HITL 一致性对比同键)。 */
31
+ export declare const DEFAULT_READ_KEY: "calorie.view.home";
32
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAG,gBAAyB,CAAC;AACrD,eAAO,MAAM,iBAAiB,EAAG,MAAe,CAAC;AAEjD,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC;AAErD,wBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAE5C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAE7D;AAED,iDAAiD;AACjD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAMjE;AAED,8BAA8B;AAC9B,eAAO,MAAM,gBAAgB,EAAG,mBAA4B,CAAC"}
@@ -0,0 +1,28 @@
1
+ /** dsh-calorie 端口(port):DSH 世界与卡路里 hexagon 之间的契约。
2
+ *
3
+ * browser 安全:零 node 导入。host 适配器(注册 RPC 通道)与 client
4
+ * 适配器(调用 RPC)共用同一份定义;单测与 loader 回路以此为准。
5
+ * 通道命名遵守宿主约束:单段且不等于 /api(见 cookbook「RPC 通道」)。
6
+ */
7
+ export const RPC_CHANNEL = '/ilife-calorie';
8
+ export const RPC_ENDPOINT_READ = 'read';
9
+ export function ok(value) {
10
+ return { ok: true, value };
11
+ }
12
+ export function fail(code, message) {
13
+ return { ok: false, error: { code, message, details: {} } };
14
+ }
15
+ /** 载荷校验:形状不对返回 null,由调用方按 bad-request 回绝(不抛)。 */
16
+ export function parseReadPayload(raw) {
17
+ if (typeof raw !== 'object' || raw === null)
18
+ return null;
19
+ const { key, params } = raw;
20
+ if (typeof key !== 'string' || key.length === 0)
21
+ return null;
22
+ if (typeof params !== 'object' || params === null || Array.isArray(params))
23
+ return null;
24
+ return { key, params: params };
25
+ }
26
+ /** 面板默认读键(与 HITL 一致性对比同键)。 */
27
+ export const DEFAULT_READ_KEY = 'calorie.view.home';
28
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAyB,CAAC;AACrD,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAe,CAAC;AAkBjD,MAAM,UAAU,EAAE,CAAC,KAAc;IAC/B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,OAAe;IAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC;AAC9D,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAA0C,CAAC;IACnE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACxF,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAiC,EAAE,CAAC;AAC5D,CAAC;AAED,8BAA8B;AAC9B,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAA4B,CAAC"}
@@ -0,0 +1,52 @@
1
+ /** DSH ctx 最小镜像:只含本仓实际使用的面(type-only,构建期擦除,零运行时)。
2
+ *
3
+ * 每条成员的用法出处见 docs/agents/dsh-client-contract.md(附源码路径+行)。
4
+ * 禁止加镜外成员:要用新能力,先在 cookbook 落出处,再加镜像。用 `import type` 引用本文件。
5
+ */
6
+ export interface SlotsRegisterOptions {
7
+ readonly name: string;
8
+ readonly id?: string;
9
+ readonly order?: number;
10
+ readonly label?: string | (() => string);
11
+ readonly locale?: string;
12
+ readonly inject?: () => Record<string, unknown>;
13
+ }
14
+ export interface SlotsFace {
15
+ inject(key: string, callback: () => (() => void) | Iterable<() => void>): () => void;
16
+ register(options: SlotsRegisterOptions, component: unknown): () => void;
17
+ }
18
+ export type RpcCallResult = {
19
+ readonly ok: true;
20
+ readonly value: unknown;
21
+ } | {
22
+ readonly ok: false;
23
+ readonly error: {
24
+ readonly code: string;
25
+ readonly message: string;
26
+ readonly details: Record<string, unknown>;
27
+ };
28
+ };
29
+ export interface RpcCallFace {
30
+ (channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise<RpcCallResult>;
31
+ }
32
+ export interface ClientCtx {
33
+ readonly slots: SlotsFace;
34
+ readonly connection?: {
35
+ readonly rpc?: {
36
+ readonly call: RpcCallFace;
37
+ };
38
+ };
39
+ effect(callback: () => ((() => void) | void), label?: string): () => void;
40
+ get?(name: string): unknown;
41
+ }
42
+ export type RpcHandler = (endpoint: string, payload: unknown, signal?: AbortSignal) => Promise<unknown>;
43
+ export interface HostCtx {
44
+ readonly connection: {
45
+ readonly rpc: {
46
+ handle(channel: string, handler: RpcHandler): () => void;
47
+ };
48
+ };
49
+ effect(callback: () => ((() => void) | void), label?: string): () => void;
50
+ readonly logger?: unknown;
51
+ }
52
+ //# sourceMappingURL=dsh-ctx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh-ctx.d.ts","sourceRoot":"","sources":["../src/dsh-ctx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;IACrF,QAAQ,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,IAAI,CAAC;CACzE;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAAE,CAAC;AAE3I,MAAM,WAAW,WAAW;IAC1B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACrG;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;SAAE,CAAA;KAAE,CAAC;IACxE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IAC1E,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAExG,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE;YAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,IAAI,CAAA;SAAE,CAAA;KAAE,CAAC;IACpG,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dsh-ctx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh-ctx.js","sourceRoot":"","sources":["../src/dsh-ctx.ts"],"names":[],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -1,16 +1,12 @@
1
- /** dsh-calorie host 半(P10 脚手架,照抄 DSH 官方插件包模式)。
2
- *
3
- * 形态:cordis 插件(name/inject/apply)+ dsh.bundle.patch 装配行。
4
- * 单品硬依赖总管(dependencies,非 peer,见 package.json);设置页住本包。
5
- */
1
+ import type { HostCtx } from './dsh-ctx.js';
6
2
  export declare const name = "dsh-calorie";
7
- export declare const inject: readonly string[];
8
- export declare function apply(_ctx: unknown): void;
3
+ export declare const inject: string[];
4
+ export declare function apply(ctx: HostCtx): void;
9
5
  export { SKILL, SLOT_ID, SLOT_ORDER, SLOT_TITLE, PLUGIN, MANAGER_PLUGIN, slotDescriptor, TAB_COMPONENT, registerSingle, openSingle } from './slot.js';
10
6
  export type { SlotDescriptor, TabsPort } from './slot.js';
11
7
  export { SETTINGS_OWNER, SETTINGS_SLOT, SETTING_ROWS } from './settings.js';
12
8
  export type { SettingRow } from './settings.js';
13
9
  export { SKILL_PACKAGE, SKILL_CLI, SKILL_CLI_REL, HOST_CALL_METHOD, MANAGER_MISSING_HINT, SkillBridgeError, cliPath, assertCliPresent, handleHostCall, requestViaHost, readViaCli } from './bridge.js';
14
- export { CLIENT_COMPONENT, CLIENT_METHOD, mountSingleClient, openSingleClient, requestReadViaHost } from './client.js';
15
- export type { HostCaller } from './client.js';
10
+ export { RPC_CHANNEL, RPC_ENDPOINT_READ, DEFAULT_READ_KEY, ok, fail, parseReadPayload } from './contract.js';
11
+ export type { ReadPayload, RpcError, RpcResult } from './contract.js';
16
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAClC,eAAO,MAAM,MAAM,EAAE,SAAS,MAAM,EAAO,CAAC;AAE5C,wBAAgB,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAEzC;AAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtJ,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC5E,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvM,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACvH,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAc,MAAM,cAAc,CAAC;AAExD,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAClC,eAAO,MAAM,MAAM,UAAiB,CAAC;AAqBrC,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAiBxC;AAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtJ,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC5E,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvM,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7G,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,15 +1,50 @@
1
- /** dsh-calorie host 半(P10 脚手架,照抄 DSH 官方插件包模式)。
1
+ /** dsh-calorie host 适配器(六边形:port=contract,adapter=本文件+bridge)。
2
2
  *
3
- * 形态:cordis 插件(name/inject/apply)+ dsh.bundle.patch 装配行。
3
+ * 形态:cordis 插件(name/inject/apply)。RPC 通道与信封由 contract 定义,
4
+ * apply 真注册通道,取数只经 bridge.readViaCli(spawn 技能 CLI),
5
+ * 从不 import 任何技能实现。
4
6
  * 单品硬依赖总管(dependencies,非 peer,见 package.json);设置页住本包。
5
7
  */
8
+ import { RPC_CHANNEL, RPC_ENDPOINT_READ, ok, fail, parseReadPayload } from './contract.js';
9
+ import { SkillBridgeError, readViaCli } from './bridge.js';
6
10
  export const name = 'dsh-calorie';
7
- export const inject = [];
8
- export function apply(_ctx) {
9
- void _ctx;
11
+ export const inject = ['connection'];
12
+ /** RPC 处理函数:endpoint 分发 → 载荷校验 → readViaCli → 信封包装(companion rpc.ts 同形)。 */
13
+ const handleCalorieRpc = async (endpoint, payload) => {
14
+ if (endpoint !== RPC_ENDPOINT_READ)
15
+ return fail('bad-request', `未知端点:${String(endpoint)}`);
16
+ const parsed = parseReadPayload(payload ?? {});
17
+ if (!parsed)
18
+ return fail('bad-request', '载荷须为 {key: string, params: object}');
19
+ try {
20
+ return ok(readViaCli(parsed.key, parsed.params));
21
+ }
22
+ catch (e) {
23
+ if (e instanceof SkillBridgeError)
24
+ return fail(e.code, e.message);
25
+ return fail('internal', e instanceof Error ? e.message : String(e));
26
+ }
27
+ };
28
+ export function apply(ctx) {
29
+ const loggerSource = ctx?.logger;
30
+ const logger = (typeof loggerSource === 'function'
31
+ ? loggerSource(name)
32
+ : loggerSource) ?? console;
33
+ try {
34
+ const dispose = ctx.connection.rpc.handle(RPC_CHANNEL, handleCalorieRpc);
35
+ ctx.effect(() => () => dispose(), 'dsh-calorie: rpc channel cleanup');
36
+ }
37
+ catch (error) {
38
+ // 通道是宿主共享单例:重装配时上一实例可能已注册,此时退让(照抄 companion),他错重抛。
39
+ if (String(error?.message ?? error).includes('duplicate prefix route')) {
40
+ logger.warn?.('[dsh-calorie] rpc channel ' + RPC_CHANNEL + ' already registered by another instance; yielding');
41
+ return;
42
+ }
43
+ throw error;
44
+ }
10
45
  }
11
46
  export { SKILL, SLOT_ID, SLOT_ORDER, SLOT_TITLE, PLUGIN, MANAGER_PLUGIN, slotDescriptor, TAB_COMPONENT, registerSingle, openSingle } from './slot.js';
12
47
  export { SETTINGS_OWNER, SETTINGS_SLOT, SETTING_ROWS } from './settings.js';
13
48
  export { SKILL_PACKAGE, SKILL_CLI, SKILL_CLI_REL, HOST_CALL_METHOD, MANAGER_MISSING_HINT, SkillBridgeError, cliPath, assertCliPresent, handleHostCall, requestViaHost, readViaCli } from './bridge.js';
14
- export { CLIENT_COMPONENT, CLIENT_METHOD, mountSingleClient, openSingleClient, requestReadViaHost } from './client.js';
49
+ export { RPC_CHANNEL, RPC_ENDPOINT_READ, DEFAULT_READ_KEY, ok, fail, parseReadPayload } from './contract.js';
15
50
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG,aAAa,CAAC;AAClC,MAAM,CAAC,MAAM,MAAM,GAAsB,EAAE,CAAC;AAE5C,MAAM,UAAU,KAAK,CAAC,IAAa;IACjC,KAAK,IAAI,CAAC;AACZ,CAAC;AAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtJ,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE5E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvM,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-calorie",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "爱生活单品插件 P10 脚手架:卡路里(ilife:calorie order 75),硬依赖总管 dsh-life-pack",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -34,11 +34,22 @@
34
34
  },
35
35
  "client": {
36
36
  "platform": "web",
37
- "inject": []
37
+ "inject": [
38
+ "@deepseek-ai/dsh-client-ui-slots",
39
+ "@deepseek-ai/dsh-client-connection"
40
+ ]
38
41
  }
39
42
  },
40
43
  "scripts": {
41
- "build": "tsc -b",
44
+ "build": "npm run build:host && npm run build:client",
45
+ "build:host": "tsc -b",
46
+ "build:client": "tsdown",
47
+ "typecheck": "tsc -p tsconfig.client.json",
42
48
  "test": "node --test test/smoke.test.mjs"
49
+ },
50
+ "devDependencies": {
51
+ "@types/react": "19.2.18",
52
+ "react": "19.2.8",
53
+ "tsdown": "0.22.14"
43
54
  }
44
55
  }