@harrylabsj/kiwi 0.8.0 → 0.9.0

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.
Files changed (214) hide show
  1. package/README.md +1 -1
  2. package/dist/a2a/negotiate.d.ts +6 -2
  3. package/dist/a2a/negotiate.js +10 -3
  4. package/dist/a2a/negotiate.js.map +1 -1
  5. package/dist/a2a/node.d.ts +4 -1
  6. package/dist/a2a/node.js +56 -3
  7. package/dist/a2a/node.js.map +1 -1
  8. package/dist/a2a/server/merchant-handler.d.ts +11 -3
  9. package/dist/a2a/server/merchant-handler.js +84 -26
  10. package/dist/a2a/server/merchant-handler.js.map +1 -1
  11. package/dist/agent/buyer/buyer-tools.js +2 -2
  12. package/dist/agent/buyer/buyer-tools.js.map +1 -1
  13. package/dist/agent/kernel.js +5 -1
  14. package/dist/agent/kernel.js.map +1 -1
  15. package/dist/agent/memory/schema.d.ts +1 -1
  16. package/dist/agent/memory/schema.js +9 -1
  17. package/dist/agent/memory/schema.js.map +1 -1
  18. package/dist/agent/merchant/action-candidate.d.ts +18 -0
  19. package/dist/agent/merchant/action-candidate.js +51 -0
  20. package/dist/agent/merchant/action-candidate.js.map +1 -1
  21. package/dist/agent/merchant/fake-merchant-client.js +6 -1
  22. package/dist/agent/merchant/fake-merchant-client.js.map +1 -1
  23. package/dist/agent/merchant/intelligence/default-backend.js +25 -2
  24. package/dist/agent/merchant/intelligence/default-backend.js.map +1 -1
  25. package/dist/agent/merchant/merchant-client.d.ts +50 -1
  26. package/dist/agent/merchant/merchant-client.js +157 -8
  27. package/dist/agent/merchant/merchant-client.js.map +1 -1
  28. package/dist/agent/merchant/merchant-presentations.js +25 -2
  29. package/dist/agent/merchant/merchant-presentations.js.map +1 -1
  30. package/dist/agent/merchant/merchant-tools.js +102 -188
  31. package/dist/agent/merchant/merchant-tools.js.map +1 -1
  32. package/dist/agent/merchant/types.d.ts +6 -2
  33. package/dist/agent/merchant/types.js +45 -0
  34. package/dist/agent/merchant/types.js.map +1 -1
  35. package/dist/auth/merchant-authorization.d.ts +49 -0
  36. package/dist/auth/merchant-authorization.js +61 -0
  37. package/dist/auth/merchant-authorization.js.map +1 -0
  38. package/dist/auth/merchant-oauth.d.ts +255 -0
  39. package/dist/auth/merchant-oauth.js +764 -0
  40. package/dist/auth/merchant-oauth.js.map +1 -0
  41. package/dist/auth/merchant-pairing.d.ts +62 -0
  42. package/dist/auth/merchant-pairing.js +199 -0
  43. package/dist/auth/merchant-pairing.js.map +1 -0
  44. package/dist/auth/merchant-sessions.d.ts +71 -0
  45. package/dist/auth/merchant-sessions.js +168 -0
  46. package/dist/auth/merchant-sessions.js.map +1 -0
  47. package/dist/buyer-core/build-service.d.ts +5 -0
  48. package/dist/buyer-core/build-service.js +12 -0
  49. package/dist/buyer-core/build-service.js.map +1 -1
  50. package/dist/buyer-core/errors.d.ts +1 -1
  51. package/dist/buyer-core/errors.js +2 -0
  52. package/dist/buyer-core/errors.js.map +1 -1
  53. package/dist/buyer-core/merchant-index.d.ts +19 -4
  54. package/dist/buyer-core/merchant-index.js +137 -16
  55. package/dist/buyer-core/merchant-index.js.map +1 -1
  56. package/dist/buyer-core/negotiator.d.ts +0 -10
  57. package/dist/buyer-core/negotiator.js +12 -1
  58. package/dist/buyer-core/negotiator.js.map +1 -1
  59. package/dist/buyer-core/quote-fetcher.js +2 -1
  60. package/dist/buyer-core/quote-fetcher.js.map +1 -1
  61. package/dist/buyer-core/service.d.ts +104 -0
  62. package/dist/buyer-core/service.js +105 -1
  63. package/dist/buyer-core/service.js.map +1 -1
  64. package/dist/cli.d.ts +4 -2
  65. package/dist/cli.js +612 -20
  66. package/dist/cli.js.map +1 -1
  67. package/dist/config/profile.d.ts +30 -0
  68. package/dist/config/profile.js +126 -61
  69. package/dist/config/profile.js.map +1 -1
  70. package/dist/demo/demo-runner.js +12 -9
  71. package/dist/demo/demo-runner.js.map +1 -1
  72. package/dist/discovery/catalog-source/buyer-follows.d.ts +82 -0
  73. package/dist/discovery/catalog-source/buyer-follows.js +228 -0
  74. package/dist/discovery/catalog-source/buyer-follows.js.map +1 -0
  75. package/dist/discovery/catalog-source/connector-identity.d.ts +75 -0
  76. package/dist/discovery/catalog-source/connector-identity.js +175 -0
  77. package/dist/discovery/catalog-source/connector-identity.js.map +1 -0
  78. package/dist/discovery/catalog-source/errors.d.ts +1 -1
  79. package/dist/discovery/catalog-source/errors.js +2 -0
  80. package/dist/discovery/catalog-source/errors.js.map +1 -1
  81. package/dist/discovery/catalog-source/merchant-publications.d.ts +65 -0
  82. package/dist/discovery/catalog-source/merchant-publications.js +207 -0
  83. package/dist/discovery/catalog-source/merchant-publications.js.map +1 -0
  84. package/dist/discovery/catalog-source/register.d.ts +24 -0
  85. package/dist/discovery/catalog-source/register.js +46 -0
  86. package/dist/discovery/catalog-source/register.js.map +1 -1
  87. package/dist/discovery/catalog-source/source.js +2 -1
  88. package/dist/discovery/catalog-source/source.js.map +1 -1
  89. package/dist/fs/atomic-write.d.ts +18 -0
  90. package/dist/fs/atomic-write.js +29 -0
  91. package/dist/fs/atomic-write.js.map +1 -0
  92. package/dist/http/server.js +4 -1
  93. package/dist/http/server.js.map +1 -1
  94. package/dist/mcp/cli.d.ts +2 -0
  95. package/dist/mcp/cli.js +7 -6
  96. package/dist/mcp/cli.js.map +1 -1
  97. package/dist/mcp/merchant-auth.d.ts +78 -0
  98. package/dist/mcp/merchant-auth.js +146 -0
  99. package/dist/mcp/merchant-auth.js.map +1 -0
  100. package/dist/mcp/merchant-dirs.d.ts +26 -0
  101. package/dist/mcp/merchant-dirs.js +44 -0
  102. package/dist/mcp/merchant-dirs.js.map +1 -0
  103. package/dist/mcp/merchant-resources.d.ts +38 -0
  104. package/dist/mcp/merchant-resources.js +146 -0
  105. package/dist/mcp/merchant-resources.js.map +1 -0
  106. package/dist/mcp/merchant-server.d.ts +106 -0
  107. package/dist/mcp/merchant-server.js +615 -0
  108. package/dist/mcp/merchant-server.js.map +1 -0
  109. package/dist/mcp/merchant-tools.d.ts +103 -0
  110. package/dist/mcp/merchant-tools.js +517 -0
  111. package/dist/mcp/merchant-tools.js.map +1 -0
  112. package/dist/mcp/server.js +4 -3
  113. package/dist/mcp/server.js.map +1 -1
  114. package/dist/mcp/tools.d.ts +5 -3
  115. package/dist/mcp/tools.js +102 -5
  116. package/dist/mcp/tools.js.map +1 -1
  117. package/dist/mcp/types.d.ts +1 -1
  118. package/dist/mcp/types.js +4 -0
  119. package/dist/mcp/types.js.map +1 -1
  120. package/dist/merchant/ops.d.ts +0 -11
  121. package/dist/merchant/ops.js +13 -1
  122. package/dist/merchant/ops.js.map +1 -1
  123. package/dist/merchant/workbench-service.d.ts +189 -0
  124. package/dist/merchant/workbench-service.js +417 -0
  125. package/dist/merchant/workbench-service.js.map +1 -0
  126. package/dist/merchant-admin/pending-page.d.ts +35 -0
  127. package/dist/merchant-admin/pending-page.js +69 -0
  128. package/dist/merchant-admin/pending-page.js.map +1 -0
  129. package/dist/merchant-core/commands.d.ts +99 -0
  130. package/dist/merchant-core/commands.js +179 -0
  131. package/dist/merchant-core/commands.js.map +1 -0
  132. package/dist/merchant-core/executor.d.ts +69 -0
  133. package/dist/merchant-core/executor.js +218 -0
  134. package/dist/merchant-core/executor.js.map +1 -0
  135. package/dist/merchant-core/negotiation-adapters.d.ts +55 -0
  136. package/dist/merchant-core/negotiation-adapters.js +55 -0
  137. package/dist/merchant-core/negotiation-adapters.js.map +1 -0
  138. package/dist/merchant-core/network-checks.d.ts +65 -0
  139. package/dist/merchant-core/network-checks.js +111 -0
  140. package/dist/merchant-core/network-checks.js.map +1 -0
  141. package/dist/merchant-core/operations.d.ts +64 -0
  142. package/dist/merchant-core/operations.js +136 -0
  143. package/dist/merchant-core/operations.js.map +1 -0
  144. package/dist/merchant-core/policy-runtime.d.ts +70 -0
  145. package/dist/merchant-core/policy-runtime.js +181 -0
  146. package/dist/merchant-core/policy-runtime.js.map +1 -0
  147. package/dist/merchant-core/product-import.d.ts +67 -0
  148. package/dist/merchant-core/product-import.js +160 -0
  149. package/dist/merchant-core/product-import.js.map +1 -0
  150. package/dist/merchant-core/service.d.ts +203 -0
  151. package/dist/merchant-core/service.js +402 -0
  152. package/dist/merchant-core/service.js.map +1 -0
  153. package/dist/merchant-gateway/catalog-publications.d.ts +71 -0
  154. package/dist/merchant-gateway/catalog-publications.js +175 -0
  155. package/dist/merchant-gateway/catalog-publications.js.map +1 -0
  156. package/dist/merchant-gateway/catalog-tools.d.ts +46 -0
  157. package/dist/merchant-gateway/catalog-tools.js +277 -0
  158. package/dist/merchant-gateway/catalog-tools.js.map +1 -0
  159. package/dist/merchant-gateway/cli.d.ts +75 -0
  160. package/dist/merchant-gateway/cli.js +458 -0
  161. package/dist/merchant-gateway/cli.js.map +1 -0
  162. package/dist/merchant-gateway/credential-vault.d.ts +44 -0
  163. package/dist/merchant-gateway/credential-vault.js +111 -0
  164. package/dist/merchant-gateway/credential-vault.js.map +1 -0
  165. package/dist/merchant-gateway/entry-server.d.ts +117 -0
  166. package/dist/merchant-gateway/entry-server.js +710 -0
  167. package/dist/merchant-gateway/entry-server.js.map +1 -0
  168. package/dist/merchant-gateway/instance-registration.d.ts +143 -0
  169. package/dist/merchant-gateway/instance-registration.js +382 -0
  170. package/dist/merchant-gateway/instance-registration.js.map +1 -0
  171. package/dist/merchant-gateway/instance-tools.d.ts +58 -0
  172. package/dist/merchant-gateway/instance-tools.js +184 -0
  173. package/dist/merchant-gateway/instance-tools.js.map +1 -0
  174. package/dist/merchant-gateway/mcp-proxy.d.ts +25 -0
  175. package/dist/merchant-gateway/mcp-proxy.js +192 -0
  176. package/dist/merchant-gateway/mcp-proxy.js.map +1 -0
  177. package/dist/merchant-gateway/pinned-fetch.d.ts +52 -0
  178. package/dist/merchant-gateway/pinned-fetch.js +212 -0
  179. package/dist/merchant-gateway/pinned-fetch.js.map +1 -0
  180. package/dist/merchant-gateway/tenant-registry.d.ts +82 -0
  181. package/dist/merchant-gateway/tenant-registry.js +190 -0
  182. package/dist/merchant-gateway/tenant-registry.js.map +1 -0
  183. package/dist/merchant-gateway/tool-bundle.d.ts +26 -0
  184. package/dist/merchant-gateway/tool-bundle.js +56 -0
  185. package/dist/merchant-gateway/tool-bundle.js.map +1 -0
  186. package/dist/merchant-runtime/backup.d.ts +48 -0
  187. package/dist/merchant-runtime/backup.js +226 -0
  188. package/dist/merchant-runtime/backup.js.map +1 -0
  189. package/dist/merchant-runtime/health.d.ts +99 -0
  190. package/dist/merchant-runtime/health.js +206 -0
  191. package/dist/merchant-runtime/health.js.map +1 -0
  192. package/dist/merchant-runtime/jobs.d.ts +64 -0
  193. package/dist/merchant-runtime/jobs.js +107 -0
  194. package/dist/merchant-runtime/jobs.js.map +1 -0
  195. package/dist/merchant-runtime/manager.d.ts +94 -0
  196. package/dist/merchant-runtime/manager.js +305 -0
  197. package/dist/merchant-runtime/manager.js.map +1 -0
  198. package/dist/merchant-runtime/services.d.ts +30 -0
  199. package/dist/merchant-runtime/services.js +51 -0
  200. package/dist/merchant-runtime/services.js.map +1 -0
  201. package/dist/net/url.d.ts +26 -0
  202. package/dist/net/url.js +32 -0
  203. package/dist/net/url.js.map +1 -0
  204. package/dist/product-cli.js +22 -3
  205. package/dist/product-cli.js.map +1 -1
  206. package/dist/product-compat.d.ts +9 -1
  207. package/dist/product-compat.js +12 -1
  208. package/dist/product-compat.js.map +1 -1
  209. package/dist/product-init.js +17 -5
  210. package/dist/product-init.js.map +1 -1
  211. package/dist/product-publish.js +2 -1
  212. package/dist/product-publish.js.map +1 -1
  213. package/package.json +3 -2
  214. package/skills/kiwi-buyer/SKILL.md +2 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export class MerchantJobs {
17
+ jobs = new Map();
18
+ timers = new Map();
19
+ records = new Map();
20
+ /** 在途任务(审查 P2:重入保护,防长备份与健康轮询自我重叠)。 */
21
+ inFlight = new Set();
22
+ now;
23
+ running = false;
24
+ constructor(options = {}) {
25
+ this.now = options.now ?? (() => new Date().toISOString());
26
+ }
27
+ register(job) {
28
+ if (this.jobs.has(job.name))
29
+ throw new Error(`job ${job.name} 已注册`);
30
+ if (!(job.intervalMs > 0))
31
+ throw new Error(`job ${job.name} intervalMs 必须 > 0`);
32
+ this.jobs.set(job.name, job);
33
+ this.records.set(job.name, { name: job.name, runs: 0 });
34
+ }
35
+ /** 立即执行一次(异常隔离:记录 last_error,不抛出)。同任务在途时跳过
36
+ * (审查 P2:与「串行执行」文档口径一致——长任务不与下一轮并发重叠)。 */
37
+ async runOnce(name) {
38
+ const job = this.jobs.get(name);
39
+ if (job === undefined)
40
+ throw new Error(`未知任务 ${name}`);
41
+ if (this.inFlight.has(name)) {
42
+ const record = this.records.get(name);
43
+ record.last_run_at = this.now();
44
+ return { ...record };
45
+ }
46
+ this.inFlight.add(name);
47
+ const record = this.records.get(name);
48
+ try {
49
+ await job.run();
50
+ record.last_run_at = this.now();
51
+ record.last_error = undefined;
52
+ }
53
+ catch (err) {
54
+ record.last_run_at = this.now();
55
+ record.last_error = err instanceof Error ? err.message : String(err);
56
+ }
57
+ finally {
58
+ this.inFlight.delete(name);
59
+ }
60
+ record.runs += 1;
61
+ return { ...record };
62
+ }
63
+ /** 启动全部周期任务。 */
64
+ start() {
65
+ if (this.running)
66
+ return;
67
+ this.running = true;
68
+ for (const [name, job] of this.jobs) {
69
+ const timer = setInterval(() => {
70
+ void this.runOnce(name);
71
+ }, job.intervalMs);
72
+ timer.unref();
73
+ this.timers.set(name, timer);
74
+ }
75
+ }
76
+ stop() {
77
+ this.running = false;
78
+ for (const timer of this.timers.values())
79
+ clearInterval(timer);
80
+ this.timers.clear();
81
+ }
82
+ list() {
83
+ return [...this.records.values()].map((r) => ({ ...r }));
84
+ }
85
+ }
86
+ /**
87
+ * 标准任务集:健康轮询 + 持续备份接缝。
88
+ * backupHook 缺省 = 阶段四未实现的明确接缝(记录错误,绝不静默成功)。
89
+ */
90
+ export function standardMerchantJobs(deps) {
91
+ return [
92
+ {
93
+ name: "health-poll",
94
+ intervalMs: deps.healthIntervalMs ?? 60_000,
95
+ run: deps.healthPoll,
96
+ },
97
+ {
98
+ name: "backup",
99
+ intervalMs: deps.backupIntervalMs ?? 5 * 60_000,
100
+ run: deps.backupHook ??
101
+ (async () => {
102
+ throw new Error("持续备份未实现(阶段四);本轮为显式接缝,不静默假装已备份");
103
+ }),
104
+ },
105
+ ];
106
+ }
107
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/merchant-runtime/jobs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Merchant 实例运行时管理(V2 阶段一:src/merchant-runtime/manager.ts)。
18
+ *
19
+ * 独立管理进程语义:A2A 接待服务与 MCP 管理服务作为受管子进程管理,
20
+ * 互不影响——停止 A2A 后管理入口(本 manager)仍可重启它(阶段一验收项)。
21
+ * WorkBuddy / MCP 会话退出不影响受管服务(detached + unref)。
22
+ *
23
+ * 进程状态落 `<dir>/runtime/`:`<name>.pid` / `<name>.log` / `<name>.exit.json`。
24
+ * 自动重启:supervise() 监控子进程异常退出并按退避重启;显式 stop 的不重启。
25
+ * 阶段一为单活形态;主备 fencing 留阶段四(V2 §5.3)。
26
+ */
27
+ import { spawn } from "node:child_process";
28
+ export interface ManagedServiceSpec {
29
+ /** 服务名(a2a / mcp 等,作为文件名须安全)。 */
30
+ name: string;
31
+ /** 完整 argv(如 [process.execPath, "dist/cli.js", "merchant", "start", "--no-chat"])。 */
32
+ command: string[];
33
+ env?: Record<string, string>;
34
+ /** 确定的工作目录(BUG-04:缺省 = 数据根目录语义由调用方保证)。 */
35
+ cwd?: string;
36
+ }
37
+ export interface ManagedServiceState {
38
+ name: string;
39
+ running: boolean;
40
+ pid?: number;
41
+ restarts: number;
42
+ /** 显式停止(stop)后不再自动重启,直到再次 start。 */
43
+ stopped: boolean;
44
+ last_exit?: {
45
+ exit_code: number | null;
46
+ at: string;
47
+ };
48
+ }
49
+ export declare class MerchantRuntimeError extends Error {
50
+ readonly code: "unknown_service" | "already_running" | "not_running" | "spawn_failed";
51
+ constructor(message: string, code: "unknown_service" | "already_running" | "not_running" | "spawn_failed");
52
+ }
53
+ export declare class MerchantRuntimeManager {
54
+ private readonly dir;
55
+ private readonly runDir;
56
+ private readonly services;
57
+ private readonly children;
58
+ private readonly now;
59
+ private readonly spawnImpl;
60
+ constructor(options: {
61
+ dir: string;
62
+ services: ManagedServiceSpec[];
63
+ now?: () => string;
64
+ /** 测试注入。 */
65
+ spawnImpl?: typeof spawn;
66
+ });
67
+ private pidFile;
68
+ private logFile;
69
+ private exitFile;
70
+ private spec;
71
+ /** 读取 pidfile 里的存活状态(管理入口重启后据此恢复视图)。 */
72
+ private livePid;
73
+ /**
74
+ * PID 存活不等于仍是 Kiwi 子进程;校验命令行,避免 PID 复用误杀。
75
+ * 返回 "unknown" = 查询手段失败(ps 缺失/超时)——不能证明进程不存在,
76
+ * 调用方按保守(存活)处理,绝不据此重拉新实例(审查 P2 fail-open 修复)。
77
+ */
78
+ private matchesProcess;
79
+ private scheduleRestart;
80
+ /** 启动服务(已在运行 → already_running 拒绝重复启动)。 */
81
+ start(name: string): Promise<ManagedServiceState>;
82
+ /** 停止服务(SIGTERM;显式停止后不自动重启)。 */
83
+ stop(name: string): Promise<ManagedServiceState>;
84
+ /** 重启(停止 → 启动);停止 A2A 后管理入口可重启它(阶段一验收项)。 */
85
+ restart(name: string): Promise<ManagedServiceState>;
86
+ private stateOf;
87
+ /** 全部服务状态。 */
88
+ status(): ManagedServiceState[];
89
+ /** 监控模式(runtime start 前台运行):启动全部服务并保持,异常退出自动重启。 */
90
+ private supervising;
91
+ supervise(): Promise<void>;
92
+ /** 停止监控并停掉全部服务(优雅关闭)。 */
93
+ shutdown(): Promise<void>;
94
+ }
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Merchant 实例运行时管理(V2 阶段一:src/merchant-runtime/manager.ts)。
18
+ *
19
+ * 独立管理进程语义:A2A 接待服务与 MCP 管理服务作为受管子进程管理,
20
+ * 互不影响——停止 A2A 后管理入口(本 manager)仍可重启它(阶段一验收项)。
21
+ * WorkBuddy / MCP 会话退出不影响受管服务(detached + unref)。
22
+ *
23
+ * 进程状态落 `<dir>/runtime/`:`<name>.pid` / `<name>.log` / `<name>.exit.json`。
24
+ * 自动重启:supervise() 监控子进程异常退出并按退避重启;显式 stop 的不重启。
25
+ * 阶段一为单活形态;主备 fencing 留阶段四(V2 §5.3)。
26
+ */
27
+ import { execFileSync, spawn } from "node:child_process";
28
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
29
+ import path from "node:path";
30
+ export class MerchantRuntimeError extends Error {
31
+ code;
32
+ constructor(message, code) {
33
+ super(message);
34
+ this.code = code;
35
+ this.name = "MerchantRuntimeError";
36
+ }
37
+ }
38
+ function pidAlive(pid) {
39
+ try {
40
+ process.kill(pid, 0);
41
+ return true;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ /** 异常退出后的重启退避(毫秒;指数,封顶 30s)。 */
48
+ function backoffMs(restarts) {
49
+ return Math.min(30_000, 500 * 2 ** Math.min(restarts, 6));
50
+ }
51
+ export class MerchantRuntimeManager {
52
+ dir;
53
+ runDir;
54
+ services = new Map();
55
+ children = new Map();
56
+ now;
57
+ spawnImpl;
58
+ constructor(options) {
59
+ this.dir = options.dir;
60
+ this.runDir = path.join(options.dir, "runtime");
61
+ this.now = options.now ?? (() => new Date().toISOString());
62
+ this.spawnImpl = options.spawnImpl ?? spawn;
63
+ for (const spec of options.services) {
64
+ if (!/^[a-z0-9-]+$/.test(spec.name)) {
65
+ throw new MerchantRuntimeError(`非法服务名 ${spec.name}`, "unknown_service");
66
+ }
67
+ this.services.set(spec.name, spec);
68
+ }
69
+ mkdirSync(this.runDir, { recursive: true, mode: 0o700 });
70
+ }
71
+ pidFile(name) {
72
+ return path.join(this.runDir, `${name}.pid`);
73
+ }
74
+ logFile(name) {
75
+ return path.join(this.runDir, `${name}.log`);
76
+ }
77
+ exitFile(name) {
78
+ return path.join(this.runDir, `${name}.exit.json`);
79
+ }
80
+ spec(name) {
81
+ const spec = this.services.get(name);
82
+ if (spec === undefined) {
83
+ throw new MerchantRuntimeError(`未知服务 ${name}(已知:${[...this.services.keys()].join(", ")})`, "unknown_service");
84
+ }
85
+ return spec;
86
+ }
87
+ /** 读取 pidfile 里的存活状态(管理入口重启后据此恢复视图)。 */
88
+ livePid(name) {
89
+ try {
90
+ const record = JSON.parse(readFileSync(this.pidFile(name), "utf8"));
91
+ if (!Number.isInteger(record.pid) || record.pid <= 0 || !pidAlive(record.pid))
92
+ return undefined;
93
+ const matched = this.matchesProcess(record.pid, this.spec(name));
94
+ if (matched === false)
95
+ return undefined;
96
+ // matched === true | "unknown":unknown(ps 不可用/超时)时 pid 存活 +
97
+ // pidfile 记录即证据——按存活认领,绝不 fail-open 双 spawn(审查 P2)。
98
+ return record.pid;
99
+ }
100
+ catch {
101
+ return undefined;
102
+ }
103
+ }
104
+ /**
105
+ * PID 存活不等于仍是 Kiwi 子进程;校验命令行,避免 PID 复用误杀。
106
+ * 返回 "unknown" = 查询手段失败(ps 缺失/超时)——不能证明进程不存在,
107
+ * 调用方按保守(存活)处理,绝不据此重拉新实例(审查 P2 fail-open 修复)。
108
+ */
109
+ matchesProcess(pid, spec) {
110
+ // Windows does not provide a portable command-line query through the
111
+ // standard Node APIs; keep the live-pid behavior there and rely on the
112
+ // service manager's per-instance directory isolation.
113
+ if (process.platform === "win32")
114
+ return true;
115
+ try {
116
+ const commandLine = execFileSync("ps", ["-p", String(pid), "-o", "command="], {
117
+ encoding: "utf8",
118
+ timeout: 2_000,
119
+ }).trim();
120
+ return spec.command.every((arg) => arg === "" || commandLine.includes(arg));
121
+ }
122
+ catch {
123
+ return "unknown";
124
+ }
125
+ }
126
+ scheduleRestart(name, previous) {
127
+ const delay = backoffMs(previous.restarts);
128
+ setTimeout(() => {
129
+ if (!this.supervising || previous.stopped)
130
+ return;
131
+ void this.start(name)
132
+ .then(() => {
133
+ const next = this.children.get(name);
134
+ if (next !== undefined)
135
+ next.restarts = previous.restarts;
136
+ })
137
+ .catch(() => {
138
+ // 配置/权限/工作目录错误也按退避持续重试,保持 7×24 manager 存活。
139
+ if (this.supervising && !previous.stopped) {
140
+ previous.restarts = Math.min(previous.restarts + 1, 32);
141
+ this.scheduleRestart(name, previous);
142
+ }
143
+ });
144
+ }, delay).unref();
145
+ }
146
+ /** 启动服务(已在运行 → already_running 拒绝重复启动)。 */
147
+ async start(name) {
148
+ const spec = this.spec(name);
149
+ const existing = this.livePid(name);
150
+ if (existing !== undefined) {
151
+ throw new MerchantRuntimeError(`服务 ${name} 已在运行(pid ${existing})`, "already_running");
152
+ }
153
+ const child = this.spawnImpl(spec.command[0] ?? "", spec.command.slice(1), {
154
+ detached: true,
155
+ stdio: ["ignore", "ignore", "ignore"],
156
+ env: { ...process.env, ...spec.env },
157
+ ...(spec.cwd !== undefined ? { cwd: spec.cwd } : {}),
158
+ });
159
+ // An invalid executable emits `error` asynchronously; attach a listener
160
+ // before checking pid so a failed spawn cannot crash the runtime manager.
161
+ child.once("error", () => undefined);
162
+ child.unref();
163
+ if (child.pid === undefined) {
164
+ throw new MerchantRuntimeError(`服务 ${name} 启动失败(无 pid)`, "spawn_failed");
165
+ }
166
+ const state = { pid: child.pid, restarts: 0, stopped: false };
167
+ this.children.set(name, state);
168
+ try {
169
+ writeFileSync(this.pidFile(name), `${JSON.stringify({ pid: child.pid, command: spec.command, ...(spec.cwd !== undefined ? { cwd: spec.cwd } : {}) })}\n`, { mode: 0o600 });
170
+ }
171
+ catch (err) {
172
+ // 审查 P2:pidfile 写失败时子进程已在跑——不回滚就会出现「无 pidfile
173
+ // 的活子进程」,异常路径重试会双 spawn(双 a2a 抢账本/端口)。
174
+ this.children.delete(name);
175
+ try {
176
+ child.kill("SIGTERM");
177
+ }
178
+ catch {
179
+ // 已退出
180
+ }
181
+ throw new MerchantRuntimeError(`服务 ${name} pidfile 写入失败,已终止刚启动的子进程:` +
182
+ `${err instanceof Error ? err.message : String(err)}`, "spawn_failed");
183
+ }
184
+ rmSync(this.exitFile(name), { force: true });
185
+ let finalized = false;
186
+ const finalize = (code) => {
187
+ if (finalized)
188
+ return;
189
+ finalized = true;
190
+ writeFileSync(this.exitFile(name), `${JSON.stringify({ exit_code: code, at: this.now() })}\n`, { mode: 0o600 });
191
+ const current = this.children.get(name);
192
+ this.children.delete(name);
193
+ rmSync(this.pidFile(name), { force: true });
194
+ // 异常退出自动重启(显式 stop 的不重启);退避防崩溃风暴。
195
+ if (current !== undefined && !current.stopped && this.supervising) {
196
+ current.restarts += 1;
197
+ this.scheduleRestart(name, current);
198
+ }
199
+ };
200
+ // spawn 的 error 事件若无监听会成为未处理 EventEmitter 错误,直接退出 manager。
201
+ child.once("error", () => finalize(null));
202
+ child.once("exit", (code) => finalize(code));
203
+ return this.stateOf(name);
204
+ }
205
+ /** 停止服务(SIGTERM;显式停止后不自动重启)。 */
206
+ async stop(name) {
207
+ this.spec(name);
208
+ const current = this.children.get(name);
209
+ if (current !== undefined)
210
+ current.stopped = true;
211
+ let pid = current?.pid ?? this.livePid(name);
212
+ if (pid === undefined) {
213
+ // 审查 P2:spec(argv)变更后旧进程与新 spec 命令行不符,livePid 认领
214
+ // 不到——按 pidfile 原始记录的 command 校验并停掉,否则旧进程永远停
215
+ // 不掉且 start 会双跑(旧实例以旧策略继续对外报价)。
216
+ try {
217
+ const record = JSON.parse(readFileSync(this.pidFile(name), "utf8"));
218
+ if (Number.isInteger(record.pid) &&
219
+ record.pid > 0 &&
220
+ pidAlive(record.pid) &&
221
+ this.matchesProcess(record.pid, {
222
+ name,
223
+ command: record.command,
224
+ ...(record.cwd !== undefined ? { cwd: record.cwd } : {}),
225
+ }) !== false) {
226
+ pid = record.pid;
227
+ }
228
+ }
229
+ catch {
230
+ // 无 pidfile / 解析失败:按无进程处理
231
+ }
232
+ }
233
+ if (pid === undefined) {
234
+ rmSync(this.pidFile(name), { force: true });
235
+ return this.stateOf(name);
236
+ }
237
+ try {
238
+ process.kill(pid, "SIGTERM");
239
+ }
240
+ catch {
241
+ // 已退出
242
+ }
243
+ const deadline = Date.now() + 5_000;
244
+ while (Date.now() < deadline && pidAlive(pid)) {
245
+ await new Promise((r) => setTimeout(r, 25));
246
+ }
247
+ if (pidAlive(pid)) {
248
+ try {
249
+ process.kill(pid, "SIGKILL");
250
+ }
251
+ catch {
252
+ // 已退出
253
+ }
254
+ }
255
+ this.children.delete(name);
256
+ rmSync(this.pidFile(name), { force: true });
257
+ return this.stateOf(name);
258
+ }
259
+ /** 重启(停止 → 启动);停止 A2A 后管理入口可重启它(阶段一验收项)。 */
260
+ async restart(name) {
261
+ await this.stop(name);
262
+ return await this.start(name);
263
+ }
264
+ stateOf(name) {
265
+ const current = this.children.get(name);
266
+ const pid = current?.pid ?? this.livePid(name);
267
+ let lastExit;
268
+ try {
269
+ lastExit = JSON.parse(readFileSync(this.exitFile(name), "utf8"));
270
+ }
271
+ catch {
272
+ lastExit = undefined;
273
+ }
274
+ return {
275
+ name,
276
+ running: pid !== undefined,
277
+ ...(pid !== undefined ? { pid } : {}),
278
+ restarts: current?.restarts ?? 0,
279
+ stopped: current?.stopped ?? pid === undefined,
280
+ ...(lastExit !== undefined && lastExit !== null ? { last_exit: lastExit } : {}),
281
+ };
282
+ }
283
+ /** 全部服务状态。 */
284
+ status() {
285
+ return [...this.services.keys()].map((name) => this.stateOf(name));
286
+ }
287
+ /** 监控模式(runtime start 前台运行):启动全部服务并保持,异常退出自动重启。 */
288
+ supervising = false;
289
+ async supervise() {
290
+ this.supervising = true;
291
+ for (const name of this.services.keys()) {
292
+ const pid = this.livePid(name);
293
+ if (pid === undefined)
294
+ await this.start(name);
295
+ }
296
+ }
297
+ /** 停止监控并停掉全部服务(优雅关闭)。 */
298
+ async shutdown() {
299
+ this.supervising = false;
300
+ for (const name of [...this.services.keys()].reverse()) {
301
+ await this.stop(name);
302
+ }
303
+ }
304
+ }
305
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/merchant-runtime/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * runtime 受管服务命令构造(BUG-04 修复)。
18
+ *
19
+ * A2A 与 MCP 子进程显式携带 `--data-dir <merchantDataDir>`(三槽位解析结果)
20
+ * 与确定的工作目录(cwd = merchantDataDir)——A2A Ledger、MCP 状态、
21
+ * oauth.sqlite、stats 等全部落在同一数据根目录;manager 的健康/备份与
22
+ * 子进程读写同一真实业务状态。
23
+ */
24
+ import type { ManagedServiceSpec } from "./manager.js";
25
+ import type { MerchantMcpRuntimeDirs } from "../mcp/merchant-dirs.js";
26
+ export declare function buildRuntimeServiceSpecs(options: {
27
+ dirs: MerchantMcpRuntimeDirs;
28
+ cliEntry: string;
29
+ profileArgs: string[];
30
+ }): ManagedServiceSpec[];
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export function buildRuntimeServiceSpecs(options) {
17
+ const dataDirArgs = ["--data-dir", options.dirs.merchantDataDir];
18
+ // 确定的工作目录:数据根目录(子进程内相对路径解析一致)。
19
+ const env = { KIWI_RUNTIME_CWD: options.dirs.merchantDataDir };
20
+ return [
21
+ {
22
+ name: "a2a",
23
+ command: [
24
+ process.execPath,
25
+ options.cliEntry,
26
+ "merchant",
27
+ "start",
28
+ "--no-chat",
29
+ ...options.profileArgs,
30
+ ...dataDirArgs,
31
+ ],
32
+ env,
33
+ cwd: options.dirs.merchantDataDir,
34
+ },
35
+ {
36
+ name: "mcp",
37
+ command: [
38
+ process.execPath,
39
+ options.cliEntry,
40
+ "merchant",
41
+ "mcp",
42
+ "serve",
43
+ ...options.profileArgs,
44
+ ...dataDirArgs,
45
+ ],
46
+ env,
47
+ cwd: options.dirs.merchantDataDir,
48
+ },
49
+ ];
50
+ }
51
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/merchant-runtime/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAcH,MAAM,UAAU,wBAAwB,CAAC,OAIxC;IACC,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACjE,+BAA+B;IAC/B,MAAM,GAAG,GAAG,EAAE,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;IAC/D,OAAO;QACL;YACE,IAAI,EAAE,KAAK;YACX,OAAO,EAAE;gBACP,OAAO,CAAC,QAAQ;gBAChB,OAAO,CAAC,QAAQ;gBAChB,UAAU;gBACV,OAAO;gBACP,WAAW;gBACX,GAAG,OAAO,CAAC,WAAW;gBACtB,GAAG,WAAW;aACf;YACD,GAAG;YACH,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe;SAClC;QACD;YACE,IAAI,EAAE,KAAK;YACX,OAAO,EAAE;gBACP,OAAO,CAAC,QAAQ;gBAChB,OAAO,CAAC,QAAQ;gBAChB,UAAU;gBACV,KAAK;gBACL,OAAO;gBACP,GAAG,OAAO,CAAC,WAAW;gBACtB,GAAG,WAAW;aACf;YACD,GAAG;YACH,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe;SAClC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright 2026 harrylabsj
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * URL 规范化小工具。
18
+ *
19
+ * `value.replace(/\/+$/, "")` 看着是 O(N),但正则引擎会在**每个起始位置**重试一次,
20
+ * 遇到长尾斜杠串时退化成 O(N²)(CodeQL `js/polynomial-redos`)。这里改成一次线性
21
+ * 扫描,语义与原来完全一致:去掉末尾连续斜杠,全斜杠输入得到空串。
22
+ *
23
+ * 调用方多是运维配置里的 baseUrl,实际不可达;但"输入长度不可控"是一般性问题,
24
+ * 统一用线性写法收口,不依赖"调用方保证输入不长"。
25
+ */
26
+ export declare function trimTrailingSlashes(value: string): string;