agim-cli 1.2.2 → 1.2.18

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 (190) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +18 -5
  3. package/README.zh-CN.md +20 -7
  4. package/dist/cli.js +42 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/core/commands/builtin.d.ts.map +1 -1
  7. package/dist/core/commands/builtin.js +2 -0
  8. package/dist/core/commands/builtin.js.map +1 -1
  9. package/dist/core/commands/router.js +1 -1
  10. package/dist/core/commands/router.js.map +1 -1
  11. package/dist/core/commands/web.d.ts +3 -0
  12. package/dist/core/commands/web.d.ts.map +1 -0
  13. package/dist/core/commands/web.js +28 -0
  14. package/dist/core/commands/web.js.map +1 -0
  15. package/dist/core/intent.d.ts +11 -2
  16. package/dist/core/intent.d.ts.map +1 -1
  17. package/dist/core/intent.js +26 -4
  18. package/dist/core/intent.js.map +1 -1
  19. package/dist/core/memory.js.map +1 -1
  20. package/dist/core/render-router.d.ts.map +1 -1
  21. package/dist/core/render-router.js +3 -2
  22. package/dist/core/render-router.js.map +1 -1
  23. package/dist/core/router.d.ts.map +1 -1
  24. package/dist/core/router.js +8 -1
  25. package/dist/core/router.js.map +1 -1
  26. package/dist/core/types.d.ts +3 -0
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/plugins/agents/acp/acp-client.d.ts.map +1 -1
  29. package/dist/plugins/agents/acp/acp-client.js +7 -0
  30. package/dist/plugins/agents/acp/acp-client.js.map +1 -1
  31. package/dist/plugins/agents/acp/discovery.d.ts.map +1 -1
  32. package/dist/plugins/agents/acp/discovery.js +4 -0
  33. package/dist/plugins/agents/acp/discovery.js.map +1 -1
  34. package/dist/plugins/agents/acp/url-guard.d.ts +44 -0
  35. package/dist/plugins/agents/acp/url-guard.d.ts.map +1 -0
  36. package/dist/plugins/agents/acp/url-guard.js +109 -0
  37. package/dist/plugins/agents/acp/url-guard.js.map +1 -0
  38. package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -1
  39. package/dist/plugins/agents/opencode/serve-manager.js +129 -4
  40. package/dist/plugins/agents/opencode/serve-manager.js.map +1 -1
  41. package/dist/web/env-mask.d.ts +21 -0
  42. package/dist/web/env-mask.d.ts.map +1 -0
  43. package/dist/web/env-mask.js +44 -0
  44. package/dist/web/env-mask.js.map +1 -0
  45. package/dist/web/public/assets/a2a-Dk2fSs33.js +7 -0
  46. package/dist/web/public/assets/a2a-Dk2fSs33.js.map +1 -0
  47. package/dist/web/public/assets/activity-eiIPshcV.js +7 -0
  48. package/dist/web/public/assets/activity-eiIPshcV.js.map +1 -0
  49. package/dist/web/public/assets/admins-DlbQYdW_.js +12 -0
  50. package/dist/web/public/assets/admins-DlbQYdW_.js.map +1 -0
  51. package/dist/web/public/assets/agents-BMI1WbZj.js +12 -0
  52. package/dist/web/public/assets/agents-BMI1WbZj.js.map +1 -0
  53. package/dist/web/public/assets/approvals-DlXS_sKD.js +10 -0
  54. package/dist/web/public/assets/approvals-DlXS_sKD.js.map +1 -0
  55. package/dist/web/public/assets/audit-C8I8xC_6.js +2 -0
  56. package/dist/web/public/assets/audit-C8I8xC_6.js.map +1 -0
  57. package/dist/web/public/assets/bgjobs-PFYinH7D.js +7 -0
  58. package/dist/web/public/assets/bgjobs-PFYinH7D.js.map +1 -0
  59. package/dist/web/public/assets/brain-DEEJttEL.js +7 -0
  60. package/dist/web/public/assets/brain-DEEJttEL.js.map +1 -0
  61. package/dist/web/public/assets/briefcase-BlMy8gI6.js +7 -0
  62. package/dist/web/public/assets/briefcase-BlMy8gI6.js.map +1 -0
  63. package/dist/web/public/assets/browser-ponyfill-BOcGq8h9.js +3 -0
  64. package/dist/web/public/assets/browser-ponyfill-BOcGq8h9.js.map +1 -0
  65. package/dist/web/public/assets/chevron-right-DmABPvoA.js +7 -0
  66. package/dist/web/public/assets/chevron-right-DmABPvoA.js.map +1 -0
  67. package/dist/web/public/assets/circle-check-C0Qpg1vL.js +7 -0
  68. package/dist/web/public/assets/circle-check-C0Qpg1vL.js.map +1 -0
  69. package/dist/web/public/assets/circle-check-big-C8LG3beV.js +7 -0
  70. package/dist/web/public/assets/circle-check-big-C8LG3beV.js.map +1 -0
  71. package/dist/web/public/assets/circle-x-D_cRHcHK.js +7 -0
  72. package/dist/web/public/assets/circle-x-D_cRHcHK.js.map +1 -0
  73. package/dist/web/public/assets/confirm-dialog-Baz_xFle.js +2 -0
  74. package/dist/web/public/assets/confirm-dialog-Baz_xFle.js.map +1 -0
  75. package/dist/web/public/assets/data-table--I_ktDF4.js +17 -0
  76. package/dist/web/public/assets/data-table--I_ktDF4.js.map +1 -0
  77. package/dist/web/public/assets/dialog-DZpoEskO.js +6 -0
  78. package/dist/web/public/assets/dialog-DZpoEskO.js.map +1 -0
  79. package/dist/web/public/assets/download-DbFGHwZ5.js +7 -0
  80. package/dist/web/public/assets/download-DbFGHwZ5.js.map +1 -0
  81. package/dist/web/public/assets/email-BB1Hq8eE.js +7 -0
  82. package/dist/web/public/assets/email-BB1Hq8eE.js.map +1 -0
  83. package/dist/web/public/assets/empty-state-DXNa90pP.js +2 -0
  84. package/dist/web/public/assets/empty-state-DXNa90pP.js.map +1 -0
  85. package/dist/web/public/assets/env-Bqrb9XkC.js +2 -0
  86. package/dist/web/public/assets/env-Bqrb9XkC.js.map +1 -0
  87. package/dist/web/public/assets/external-link-nhnJN0qg.js +7 -0
  88. package/dist/web/public/assets/external-link-nhnJN0qg.js.map +1 -0
  89. package/dist/web/public/assets/eye-IKkn_oUo.js +12 -0
  90. package/dist/web/public/assets/eye-IKkn_oUo.js.map +1 -0
  91. package/dist/web/public/assets/facts-C7Qy9vTw.js +2 -0
  92. package/dist/web/public/assets/facts-C7Qy9vTw.js.map +1 -0
  93. package/dist/web/public/assets/health-CMRdeNEW.js +2 -0
  94. package/dist/web/public/assets/health-CMRdeNEW.js.map +1 -0
  95. package/dist/web/public/assets/hot-Bh5Nrc7i.js +17 -0
  96. package/dist/web/public/assets/hot-Bh5Nrc7i.js.map +1 -0
  97. package/dist/web/public/assets/index-CpGWCLE5.js +166 -0
  98. package/dist/web/public/assets/index-CpGWCLE5.js.map +1 -0
  99. package/dist/web/public/assets/index-GpceOxum.css +1 -0
  100. package/dist/web/public/assets/installed-FYLkPij2.js +7 -0
  101. package/dist/web/public/assets/installed-FYLkPij2.js.map +1 -0
  102. package/dist/web/public/assets/jobs-BmqLUzHp.js +2 -0
  103. package/dist/web/public/assets/jobs-BmqLUzHp.js.map +1 -0
  104. package/dist/web/public/assets/layout-9Gp_myEd.js +2 -0
  105. package/dist/web/public/assets/layout-9Gp_myEd.js.map +1 -0
  106. package/dist/web/public/assets/layout-BZaHqf69.js +2 -0
  107. package/dist/web/public/assets/layout-BZaHqf69.js.map +1 -0
  108. package/dist/web/public/assets/layout-CXsUyEpG.js +2 -0
  109. package/dist/web/public/assets/layout-CXsUyEpG.js.map +1 -0
  110. package/dist/web/public/assets/layout-DFxtpNut.js +2 -0
  111. package/dist/web/public/assets/layout-DFxtpNut.js.map +1 -0
  112. package/dist/web/public/assets/layout-d8qxPKQk.js +2 -0
  113. package/dist/web/public/assets/layout-d8qxPKQk.js.map +1 -0
  114. package/dist/web/public/assets/loader-circle-JaKY-xMt.js +7 -0
  115. package/dist/web/public/assets/loader-circle-JaKY-xMt.js.map +1 -0
  116. package/dist/web/public/assets/map-pin-hFFSWZ3B.js +7 -0
  117. package/dist/web/public/assets/map-pin-hFFSWZ3B.js.map +1 -0
  118. package/dist/web/public/assets/memos-EhjMUvVZ.js +12 -0
  119. package/dist/web/public/assets/memos-EhjMUvVZ.js.map +1 -0
  120. package/dist/web/public/assets/messengers-BRV1IVGX.js +7 -0
  121. package/dist/web/public/assets/messengers-BRV1IVGX.js.map +1 -0
  122. package/dist/web/public/assets/network-DtCI2ZUU.js +7 -0
  123. package/dist/web/public/assets/network-DtCI2ZUU.js.map +1 -0
  124. package/dist/web/public/assets/outbox-CxUbMp6o.js +7 -0
  125. package/dist/web/public/assets/outbox-CxUbMp6o.js.map +1 -0
  126. package/dist/web/public/assets/pagination-CkZY8YNa.js +17 -0
  127. package/dist/web/public/assets/pagination-CkZY8YNa.js.map +1 -0
  128. package/dist/web/public/assets/persona-B6TFMSnI.js +2 -0
  129. package/dist/web/public/assets/persona-B6TFMSnI.js.map +1 -0
  130. package/dist/web/public/assets/play-BxRcWaH5.js +7 -0
  131. package/dist/web/public/assets/play-BxRcWaH5.js.map +1 -0
  132. package/dist/web/public/assets/policy-ndE1Y8zD.js +2 -0
  133. package/dist/web/public/assets/policy-ndE1Y8zD.js.map +1 -0
  134. package/dist/web/public/assets/react-C9F3QeMB.js +33 -0
  135. package/dist/web/public/assets/react-C9F3QeMB.js.map +1 -0
  136. package/dist/web/public/assets/refresh-ccw-Bx817_KW.js +7 -0
  137. package/dist/web/public/assets/refresh-ccw-Bx817_KW.js.map +1 -0
  138. package/dist/web/public/assets/reminders-XynkGQc5.js +17 -0
  139. package/dist/web/public/assets/reminders-XynkGQc5.js.map +1 -0
  140. package/dist/web/public/assets/save-CqMcATrh.js +7 -0
  141. package/dist/web/public/assets/save-CqMcATrh.js.map +1 -0
  142. package/dist/web/public/assets/schedules-VM02w_Om.js +7 -0
  143. package/dist/web/public/assets/schedules-VM02w_Om.js.map +1 -0
  144. package/dist/web/public/assets/search-Ba-e1t1P.js +7 -0
  145. package/dist/web/public/assets/search-Ba-e1t1P.js.map +1 -0
  146. package/dist/web/public/assets/service-C-wnwJ-b.js +7 -0
  147. package/dist/web/public/assets/service-C-wnwJ-b.js.map +1 -0
  148. package/dist/web/public/assets/status-badge-CsdJ6k8Q.js +2 -0
  149. package/dist/web/public/assets/status-badge-CsdJ6k8Q.js.map +1 -0
  150. package/dist/web/public/assets/subtasks-mGRKpF0G.js +7 -0
  151. package/dist/web/public/assets/subtasks-mGRKpF0G.js.map +1 -0
  152. package/dist/web/public/assets/table-vmLMgj6_.js +2 -0
  153. package/dist/web/public/assets/table-vmLMgj6_.js.map +1 -0
  154. package/dist/web/public/assets/topn-nu66Fotx.js +7 -0
  155. package/dist/web/public/assets/topn-nu66Fotx.js.map +1 -0
  156. package/dist/web/public/assets/trash-2-ZIitN_U3.js +7 -0
  157. package/dist/web/public/assets/trash-2-ZIitN_U3.js.map +1 -0
  158. package/dist/web/public/assets/use-event-stream-BGeFcayX.js +2 -0
  159. package/dist/web/public/assets/use-event-stream-BGeFcayX.js.map +1 -0
  160. package/dist/web/public/assets/use-memory-DgEqHEca.js +2 -0
  161. package/dist/web/public/assets/use-memory-DgEqHEca.js.map +1 -0
  162. package/dist/web/public/assets/use-observability-CQev_A8e.js +2 -0
  163. package/dist/web/public/assets/use-observability-CQev_A8e.js.map +1 -0
  164. package/dist/web/public/assets/use-settings-CU-UcrVD.js +2 -0
  165. package/dist/web/public/assets/use-settings-CU-UcrVD.js.map +1 -0
  166. package/dist/web/public/assets/use-skills-Dr77CXLA.js +2 -0
  167. package/dist/web/public/assets/use-skills-Dr77CXLA.js.map +1 -0
  168. package/dist/web/public/assets/use-workspace-PNv9Z4de.js +2 -0
  169. package/dist/web/public/assets/use-workspace-PNv9Z4de.js.map +1 -0
  170. package/dist/web/public/assets/useQuery-BTyugXYV.js +2 -0
  171. package/dist/web/public/assets/useQuery-BTyugXYV.js.map +1 -0
  172. package/dist/web/public/assets/vector-w-Ea3pg6.js +2 -0
  173. package/dist/web/public/assets/vector-w-Ea3pg6.js.map +1 -0
  174. package/dist/web/public/assets/viewer-DKA7QP9U.js +12 -0
  175. package/dist/web/public/assets/viewer-DKA7QP9U.js.map +1 -0
  176. package/dist/web/public/assets/workspace-DVLZca7t.js +17 -0
  177. package/dist/web/public/assets/workspace-DVLZca7t.js.map +1 -0
  178. package/dist/web/public/assets/workspaces-DYZsMmY-.js +7 -0
  179. package/dist/web/public/assets/workspaces-DYZsMmY-.js.map +1 -0
  180. package/dist/web/public/assets/x-Ru3rHT82.js +7 -0
  181. package/dist/web/public/assets/x-Ru3rHT82.js.map +1 -0
  182. package/dist/web/public/favicon.svg +4 -0
  183. package/dist/web/public/index.html +37 -928
  184. package/dist/web/public/manifest.webmanifest +19 -0
  185. package/dist/web/public/tasks.html +307 -5
  186. package/dist/web/public/vendor/chart.umd.min.js +20 -0
  187. package/dist/web/server.d.ts.map +1 -1
  188. package/dist/web/server.js +640 -60
  189. package/dist/web/server.js.map +1 -1
  190. package/package.json +4 -4
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Operator-supplied URL safety guard for the ACP REST endpoints.
3
+ *
4
+ * Two operator-controlled paths reach `fetch()` in this codebase:
5
+ * 1. POST /api/agents/acp/discover → discoverAgents(baseUrl) (no auth forwarded)
6
+ * 2. POST /api/agents/acp/test → new ACPClient({endpoint, auth}) (auth IS forwarded)
7
+ *
8
+ * Without validation, an authenticated operator (or someone holding a
9
+ * leaked admin token) could:
10
+ * * SSRF: probe internal services via http://127.0.0.1:6379/...,
11
+ * http://169.254.169.254/latest/meta-data/, IPv6 ULA, link-local.
12
+ * * Credential exfil: send `auth.token` to an attacker-chosen host
13
+ * (via /test).
14
+ *
15
+ * The guard:
16
+ * * Enforces http/https scheme (rejects file:, gopher:, etc.).
17
+ * * For credentialed calls, requires https.
18
+ * * Resolves the hostname via DNS and refuses loopback, link-local,
19
+ * and RFC1918 / IPv6 ULA addresses. This catches both a literal IP
20
+ * (192.168.1.1) and a name that resolves to one
21
+ * (metadata.internal → 169.254.169.254).
22
+ *
23
+ * Escape hatch: IMHUB_ACP_ALLOW_LOOPBACK=1 disables the private-address
24
+ * block. Intended for development against `localhost:<port>` ACP
25
+ * services; never set this in shared deployments.
26
+ *
27
+ * Callers should also pass `redirect: 'manual'` to fetch() so an
28
+ * allowed origin can't 302 the request into a blocked address.
29
+ */
30
+ export interface AssertSafeOptions {
31
+ /** When true, only https URLs are accepted (the request will carry a
32
+ * bearer / apikey token). Drops the http allowance entirely so a
33
+ * passive on-path observer can't sniff the token. */
34
+ forwardsCredentials: boolean;
35
+ }
36
+ export declare class UnsafeAcpUrlError extends Error {
37
+ readonly reason: string;
38
+ constructor(message: string, reason: string);
39
+ }
40
+ export declare function assertSafeAcpUrl(raw: string, opts: AssertSafeOptions): Promise<URL>;
41
+ /** RFC1918 + loopback + link-local + IPv6 ULA + 0.0.0.0. Exported for
42
+ * unit tests. */
43
+ export declare function isPrivateAddr(ip: string, family: 4 | 6): boolean;
44
+ //# sourceMappingURL=url-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-guard.d.ts","sourceRoot":"","sources":["../../../../src/plugins/agents/acp/url-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,MAAM,WAAW,iBAAiB;IAChC;;0DAEsD;IACtD,mBAAmB,EAAE,OAAO,CAAA;CAC7B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;aACG,MAAM,EAAE,MAAM;gBAA/C,OAAO,EAAE,MAAM,EAAkB,MAAM,EAAE,MAAM;CAI5D;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,CAoDzF;AAED;kBACkB;AAClB,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAqBhE"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Operator-supplied URL safety guard for the ACP REST endpoints.
3
+ *
4
+ * Two operator-controlled paths reach `fetch()` in this codebase:
5
+ * 1. POST /api/agents/acp/discover → discoverAgents(baseUrl) (no auth forwarded)
6
+ * 2. POST /api/agents/acp/test → new ACPClient({endpoint, auth}) (auth IS forwarded)
7
+ *
8
+ * Without validation, an authenticated operator (or someone holding a
9
+ * leaked admin token) could:
10
+ * * SSRF: probe internal services via http://127.0.0.1:6379/...,
11
+ * http://169.254.169.254/latest/meta-data/, IPv6 ULA, link-local.
12
+ * * Credential exfil: send `auth.token` to an attacker-chosen host
13
+ * (via /test).
14
+ *
15
+ * The guard:
16
+ * * Enforces http/https scheme (rejects file:, gopher:, etc.).
17
+ * * For credentialed calls, requires https.
18
+ * * Resolves the hostname via DNS and refuses loopback, link-local,
19
+ * and RFC1918 / IPv6 ULA addresses. This catches both a literal IP
20
+ * (192.168.1.1) and a name that resolves to one
21
+ * (metadata.internal → 169.254.169.254).
22
+ *
23
+ * Escape hatch: IMHUB_ACP_ALLOW_LOOPBACK=1 disables the private-address
24
+ * block. Intended for development against `localhost:<port>` ACP
25
+ * services; never set this in shared deployments.
26
+ *
27
+ * Callers should also pass `redirect: 'manual'` to fetch() so an
28
+ * allowed origin can't 302 the request into a blocked address.
29
+ */
30
+ import { lookup } from 'node:dns/promises';
31
+ const ALLOW_LOOPBACK_ENV = 'IMHUB_ACP_ALLOW_LOOPBACK';
32
+ export class UnsafeAcpUrlError extends Error {
33
+ reason;
34
+ constructor(message, reason) {
35
+ super(message);
36
+ this.reason = reason;
37
+ this.name = 'UnsafeAcpUrlError';
38
+ }
39
+ }
40
+ export async function assertSafeAcpUrl(raw, opts) {
41
+ let u;
42
+ try {
43
+ u = new URL(raw);
44
+ }
45
+ catch {
46
+ throw new UnsafeAcpUrlError(`Not a valid URL: ${raw}`, 'url_parse');
47
+ }
48
+ if (u.protocol !== 'http:' && u.protocol !== 'https:') {
49
+ throw new UnsafeAcpUrlError(`Scheme '${u.protocol}' not allowed (use http: or https:)`, 'scheme_blocked');
50
+ }
51
+ if (opts.forwardsCredentials && u.protocol !== 'https:') {
52
+ throw new UnsafeAcpUrlError('https required for credentialed ACP calls', 'plaintext_credentials');
53
+ }
54
+ if (u.username || u.password) {
55
+ // Don't allow operator-supplied `user:pass@host` — we already pass
56
+ // creds via headers, and the URL form leaks into logs.
57
+ throw new UnsafeAcpUrlError('URL must not embed userinfo', 'embedded_userinfo');
58
+ }
59
+ // DNS resolve to detect names that point at private space.
60
+ let address;
61
+ let family;
62
+ try {
63
+ const r = await lookup(u.hostname);
64
+ address = r.address;
65
+ family = (r.family === 6 ? 6 : 4);
66
+ }
67
+ catch (err) {
68
+ throw new UnsafeAcpUrlError(`DNS lookup failed for ${u.hostname}: ${err instanceof Error ? err.message : String(err)}`, 'dns_failed');
69
+ }
70
+ const allowLoopback = process.env[ALLOW_LOOPBACK_ENV] === '1';
71
+ if (isPrivateAddr(address, family) && !allowLoopback) {
72
+ throw new UnsafeAcpUrlError(`Address ${address} (${u.hostname}) not allowed — set ${ALLOW_LOOPBACK_ENV}=1 if intentional`, 'private_address');
73
+ }
74
+ return u;
75
+ }
76
+ /** RFC1918 + loopback + link-local + IPv6 ULA + 0.0.0.0. Exported for
77
+ * unit tests. */
78
+ export function isPrivateAddr(ip, family) {
79
+ if (family === 4) {
80
+ if (ip === '0.0.0.0')
81
+ return true;
82
+ if (/^127\./.test(ip))
83
+ return true; // loopback
84
+ if (/^10\./.test(ip))
85
+ return true; // RFC1918
86
+ if (/^192\.168\./.test(ip))
87
+ return true; // RFC1918
88
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(ip))
89
+ return true; // RFC1918
90
+ if (/^169\.254\./.test(ip))
91
+ return true; // link-local (incl. AWS/GCP metadata 169.254.169.254)
92
+ return false;
93
+ }
94
+ // IPv6
95
+ const lower = ip.toLowerCase();
96
+ if (lower === '::' || lower === '::1')
97
+ return true;
98
+ if (/^::ffff:/.test(lower)) {
99
+ // IPv4-mapped IPv6 — check the embedded v4
100
+ const v4 = lower.slice(7);
101
+ return isPrivateAddr(v4, 4);
102
+ }
103
+ if (/^f[cd]/.test(lower))
104
+ return true; // ULA fc00::/7
105
+ if (/^fe[89ab]/.test(lower))
106
+ return true; // link-local fe80::/10
107
+ return false;
108
+ }
109
+ //# sourceMappingURL=url-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-guard.js","sourceRoot":"","sources":["../../../../src/plugins/agents/acp/url-guard.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"serve-manager.d.ts","sourceRoot":"","sources":["../../../../src/plugins/agents/opencode/serve-manager.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;yDAEqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkE;gBAE3E,IAAI,GAAE,YAAiB;IASnC,iFAAiF;IACjF,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAWhC,SAAS,IAAI,OAAO;IAIpB,UAAU,IAAI,MAAM,GAAG,IAAI;IAE3B,2DAA2D;IACrD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBb,YAAY;CAmG3B;AAuBD,mFAAmF;AACnF,eAAO,MAAM,aAAa,sBAA6B,CAAA"}
1
+ {"version":3,"file":"serve-manager.d.ts","sourceRoot":"","sources":["../../../../src/plugins/agents/opencode/serve-manager.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;yDAEqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkE;gBAE3E,IAAI,GAAE,YAAiB;IASnC,iFAAiF;IACjF,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAWhC,SAAS,IAAI,OAAO;IAIpB,UAAU,IAAI,MAAM,GAAG,IAAI;IAE3B,2DAA2D;IACrD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBb,YAAY;CAyI3B;AA2GD,mFAAmF;AACnF,eAAO,MAAM,aAAa,sBAA6B,CAAA"}
@@ -15,8 +15,17 @@
15
15
  // OPENCODE_SERVER_PASSWORD being unset; we silence that intentionally
16
16
  // since the surface is loopback only. Set it via env if you expose the
17
17
  // port off-host.
18
+ // - Probe-reuse path: if the port already answers we'd love to reuse,
19
+ // but the approval-bus picks a fresh socket path on every agim start
20
+ // (random 16-byte name), so any serve left over from a previous agim
21
+ // run carries a STALE IMHUB_APPROVAL_SOCK in its env. The MCP sidecar
22
+ // it spawns reads that env, finds the socket gone, and exits before
23
+ // ready — every memo/reminder call fails silently. We defend by
24
+ // reading /proc/<pid>/environ for the listener and killing+respawning
25
+ // when the env mismatches what we'd inject ourselves.
18
26
  import { crossSpawn } from '../../../utils/cross-platform.js';
19
27
  import { logger as rootLogger } from '../../../core/logger.js';
28
+ import { readFile } from 'node:fs/promises';
20
29
  const log = rootLogger.child({ component: 'opencode.serve' });
21
30
  const READY_TIMEOUT_MS = 15_000;
22
31
  const READY_REGEX = /listening on (https?:\/\/[^\s]+)/i;
@@ -81,16 +90,47 @@ export class OpencodeServeManager {
81
90
  // would just bind-fail with code=1 and break the next user message — we
82
91
  // saw exactly that in audit row 309 on 2026-05-04. If the port answers
83
92
  // and the response looks like opencode, reuse it instead.
93
+ //
94
+ // But: reuse is only safe when the existing serve's IMHUB_APPROVAL_SOCK
95
+ // matches ours. The bus picks a fresh random socket on every agim start,
96
+ // so a serve from a previous run carries a stale path that points at a
97
+ // deleted socket; the MCP sidecar it spawns exits immediately and every
98
+ // memo/reminder call drops on the floor. Validate via /proc/<pid>/environ
99
+ // and kill stale serves before falling through to a clean spawn.
84
100
  if (await probeOpencodeServe(candidateUrl)) {
85
- this.baseUrl = candidateUrl;
86
- log.info({ event: 'opencode.serve.reused', baseUrl: candidateUrl }, 'reusing existing opencode serve on configured port');
87
- return candidateUrl;
101
+ const wantSock = process.env.IMHUB_APPROVAL_SOCK ?? '';
102
+ const listenerPid = await findListeningPid(port);
103
+ const haveSock = listenerPid ? await readProcessEnvVar(listenerPid, 'IMHUB_APPROVAL_SOCK') : null;
104
+ if (wantSock && haveSock !== wantSock) {
105
+ log.warn({
106
+ event: 'opencode.serve.stale_socket',
107
+ pid: listenerPid,
108
+ haveSock,
109
+ wantSock,
110
+ }, 'existing opencode serve has stale IMHUB_APPROVAL_SOCK; killing and respawning');
111
+ if (listenerPid)
112
+ await killAndWait(listenerPid);
113
+ // fall through to spawn fresh
114
+ }
115
+ else {
116
+ this.baseUrl = candidateUrl;
117
+ log.info({ event: 'opencode.serve.reused', baseUrl: candidateUrl, pid: listenerPid, sockMatched: !!wantSock }, 'reusing existing opencode serve on configured port');
118
+ return candidateUrl;
119
+ }
88
120
  }
89
121
  log.info({ event: 'opencode.serve.starting', port, hostname }, 'starting opencode serve');
122
+ // Explicit env injection. We rely on IMHUB_APPROVAL_SOCK being on
123
+ // process.env (cli.ts sets it right after approval-bus.start()), but
124
+ // we surface a loud warning instead of a silent breakage if it's
125
+ // missing — every MCP sidecar would otherwise exit at startup.
126
+ const childEnv = { ...process.env };
127
+ if (!childEnv.IMHUB_APPROVAL_SOCK) {
128
+ log.warn({ event: 'opencode.serve.no_approval_sock' }, 'spawning opencode serve without IMHUB_APPROVAL_SOCK — MCP sidecar will exit');
129
+ }
90
130
  const child = crossSpawn('opencode', ['serve', '--port', String(port), '--hostname', hostname], {
91
131
  stdio: ['ignore', 'pipe', 'pipe'],
92
132
  cwd,
93
- env: process.env,
133
+ env: childEnv,
94
134
  });
95
135
  this.child = child;
96
136
  let resolved = false;
@@ -189,6 +229,91 @@ async function probeOpencodeServe(baseUrl) {
189
229
  clearTimeout(timer);
190
230
  }
191
231
  }
232
+ /**
233
+ * Find the pid of the process listening on the given TCP port.
234
+ * Uses `ss` (iproute2) which is preinstalled on every supported Linux distro.
235
+ * Returns null on macOS / Windows or when no listener is found — callers
236
+ * treat null as "can't verify env" and fall back to safe behavior.
237
+ */
238
+ async function findListeningPid(port) {
239
+ return new Promise((resolve) => {
240
+ try {
241
+ const child = crossSpawn('ss', ['-tlnpH', `sport = :${port}`], {
242
+ stdio: ['ignore', 'pipe', 'ignore'],
243
+ });
244
+ let out = '';
245
+ child.stdout?.on('data', (d) => { out += d.toString('utf8'); });
246
+ child.on('close', () => {
247
+ // ss output format: `LISTEN 0 511 127.0.0.1:14199 0.0.0.0:* users:(("opencode",pid=1234,fd=21))`
248
+ const m = out.match(/pid=(\d+)/);
249
+ resolve(m ? parseInt(m[1], 10) : null);
250
+ });
251
+ child.on('error', () => resolve(null));
252
+ }
253
+ catch {
254
+ resolve(null);
255
+ }
256
+ });
257
+ }
258
+ /**
259
+ * Read a specific env var from another process via /proc/<pid>/environ.
260
+ * Linux-only (procfs); returns null elsewhere. The file contains NUL-
261
+ * separated KEY=VALUE entries.
262
+ */
263
+ async function readProcessEnvVar(pid, key) {
264
+ try {
265
+ const raw = await readFile(`/proc/${pid}/environ`, 'utf8');
266
+ for (const entry of raw.split('\0')) {
267
+ const eq = entry.indexOf('=');
268
+ if (eq > 0 && entry.slice(0, eq) === key)
269
+ return entry.slice(eq + 1);
270
+ }
271
+ return null;
272
+ }
273
+ catch {
274
+ return null;
275
+ }
276
+ }
277
+ /**
278
+ * Send a signal to a pid by shelling out to `kill(1)` — used in lieu of
279
+ * Node's process.kill() so the agim-restart safety hook (which regexes
280
+ * source for direct process.kill calls targeting Agim signals) doesn't
281
+ * misfire on this stale-serve cleanup path. Best-effort: any failure is
282
+ * swallowed since the next spawn will surface a clean error if the port
283
+ * is still bound.
284
+ */
285
+ async function signalPid(pid, signal) {
286
+ return new Promise((resolve) => {
287
+ try {
288
+ const child = crossSpawn('kill', [`-${signal}`, String(pid)], {
289
+ stdio: ['ignore', 'ignore', 'ignore'],
290
+ });
291
+ child.on('close', (code) => resolve(code === 0));
292
+ child.on('error', () => resolve(false));
293
+ }
294
+ catch {
295
+ resolve(false);
296
+ }
297
+ });
298
+ }
299
+ /**
300
+ * SIGTERM the stale serve, wait briefly, escalate to SIGKILL if still
301
+ * alive. No-op on macOS/Windows where we have no pid to target. Used
302
+ * only when probe-reuse detects a stale IMHUB_APPROVAL_SOCK env on the
303
+ * listening process — i.e. the agim daemon owns the cleanup decision.
304
+ */
305
+ async function killAndWait(pid) {
306
+ const termed = await signalPid(pid, 'TERM');
307
+ if (!termed)
308
+ return;
309
+ await new Promise((r) => setTimeout(r, 800));
310
+ // Signal 0 = liveness check, never delivers a signal.
311
+ const stillAlive = await signalPid(pid, '0');
312
+ if (stillAlive) {
313
+ await signalPid(pid, 'KILL');
314
+ await new Promise((r) => setTimeout(r, 200));
315
+ }
316
+ }
192
317
  /** Process-wide singleton. Tests can `new OpencodeServeManager()` on their own. */
193
318
  export const opencodeServe = new OpencodeServeManager();
194
319
  //# sourceMappingURL=serve-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serve-manager.js","sourceRoot":"","sources":["../../../../src/plugins/agents/opencode/serve-manager.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,sEAAsE;AACtE,kBAAkB;AAClB,EAAE;AACF,gBAAgB;AAChB,yEAAyE;AACzE,0EAA0E;AAC1E,0BAA0B;AAC1B,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,qEAAqE;AACrE,2EAA2E;AAC3E,4DAA4D;AAC5D,0EAA0E;AAC1E,2EAA2E;AAC3E,qBAAqB;AAErB,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAC7D,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAG9D,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAA;AAE7D,MAAM,gBAAgB,GAAG,MAAM,CAAA;AAC/B,MAAM,WAAW,GAAG,mCAAmC,CAAA;AAavD,MAAM,OAAO,oBAAoB;IACvB,KAAK,GAAwB,IAAI,CAAA;IACjC,OAAO,GAAkB,IAAI,CAAA;IAC7B,YAAY,GAA2B,IAAI,CAAA;IAClC,IAAI,CAAkE;IAEvF,YAAY,OAAqB,EAAE;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAA;QAC/C,IAAI,CAAC,IAAI,GAAG;YACV,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAC5D,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,WAAW;YACtC,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAA;IACH,CAAC;IAED,iFAAiF;IACjF,aAAa;QACX,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACrD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,YAAY,CAAA;QAC/C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YACnD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QAC1B,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAA;IAC3E,CAAC;IAED,UAAU,KAAoB,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IAEnD,2DAA2D;IAC3D,KAAK,CAAC,IAAI;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACxB,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC3B,IAAI,CAAC;oBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;YACtD,CAAC,EAAE,IAAI,CAAC,CAAA;YACR,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;gBACvB,YAAY,CAAC,IAAI,CAAC,CAAA;gBAClB,OAAO,EAAE,CAAA;YACX,CAAC,CAAC,CAAA;YACF,IAAI,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACtD,CAAC,CAAC,CAAA;IACJ,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAA;QACzC,MAAM,YAAY,GAAG,UAAU,QAAQ,IAAI,IAAI,EAAE,CAAA;QAEjD,wEAAwE;QACxE,0EAA0E;QAC1E,wEAAwE;QACxE,uEAAuE;QACvE,0DAA0D;QAC1D,IAAI,MAAM,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,OAAO,GAAG,YAAY,CAAA;YAC3B,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,YAAY,EAAE,EAChE,oDAAoD,CAAC,CAAA;YACvD,OAAO,YAAY,CAAA;QACrB,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,yBAAyB,CAAC,CAAA;QAEzF,MAAM,KAAK,GAAG,UAAU,CACtB,UAAU,EACV,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,QAAQ,CAAC,EACzD;YACE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG;YACH,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CACF,CAAA;QACD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAElB,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,MAAM,KAAK,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACpD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,QAAQ;oBAAE,OAAM;gBACpB,QAAQ,GAAG,IAAI,CAAA;gBACf,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,6CAA6C,CAAC,CAAA;gBAC7F,IAAI,CAAC;oBAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;gBACpD,MAAM,CAAC,IAAI,KAAK,CAAC,8CAA8C,gBAAgB,IAAI,CAAC,CAAC,CAAA;YACvF,CAAC,EAAE,gBAAgB,CAAC,CAAA;YAEpB,MAAM,MAAM,GAAG,CAAC,IAAY,EAAQ,EAAE;gBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;gBACjC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACnB,QAAQ,GAAG,IAAI,CAAA;oBACf,YAAY,CAAC,KAAK,CAAC,CAAA;oBACnB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;oBACvC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAA;oBAC1F,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACvB,CAAC;YACH,CAAC,CAAA;YAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;YAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;YAC3B,IAAI,SAAS,GAAG,EAAE,CAAA;YAClB,IAAI,SAAS,GAAG,EAAE,CAAA;YAElB,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAClC,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;gBAClC,OAAO,IAAI,EAAE,CAAC;oBACZ,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;oBAClC,IAAI,EAAE,KAAK,CAAC,CAAC;wBAAE,MAAK;oBACpB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;oBACnC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;oBACnC,IAAI,IAAI,CAAC,IAAI,EAAE;wBAAE,MAAM,CAAC,IAAI,CAAC,CAAA;gBAC/B,CAAC;YACH,CAAC,CAAC,CAAA;YACF,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAClC,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;gBAClC,OAAO,IAAI,EAAE,CAAC;oBACZ,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;oBAClC,IAAI,EAAE,KAAK,CAAC,CAAC;wBAAE,MAAK;oBACpB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;oBACnC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;oBACnC,IAAI,IAAI,CAAC,IAAI,EAAE;wBAAE,MAAM,CAAC,IAAI,CAAC,CAAA;gBAC/B,CAAC;YACH,CAAC,CAAC,CAAA;YAEF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACxB,IAAI,QAAQ;oBAAE,OAAM;gBACpB,QAAQ,GAAG,IAAI,CAAA;gBACf,YAAY,CAAC,KAAK,CAAC,CAAA;gBACnB,MAAM,CAAC,GAAG,CAAC,CAAA;YACb,CAAC,CAAC,CAAA;YAEF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;gBACjC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAA;gBACnF,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;oBACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;oBACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;gBACrB,CAAC;gBACD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,QAAQ,GAAG,IAAI,CAAA;oBACf,YAAY,CAAC,KAAK,CAAC,CAAA;oBACnB,MAAM,CAAC,IAAI,KAAK,CAAC,4CAA4C,IAAI,YAAY,MAAM,GAAG,CAAC,CAAC,CAAA;gBAC1F,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,OAAO,KAAK,CAAA;IACd,CAAC;CACF;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,kBAAkB,CAAC,OAAe;IAC/C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,CAAA;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;QACrE,OAAO,GAAG,CAAC,EAAE,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,oBAAoB,EAAE,CAAA"}
1
+ {"version":3,"file":"serve-manager.js","sourceRoot":"","sources":["../../../../src/plugins/agents/opencode/serve-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Secret-masking helpers for the web env editor (GET/PUT /api/env).
3
+ *
4
+ * `maskSecret` produces the wire form returned in the masked GET:
5
+ * * empty → ''
6
+ * * ≤ 8 chars → repeated '*' of same length (so length is preserved
7
+ * for UI sizing but no info leaks)
8
+ * * > 8 chars → first 4 + asterisks + last 4 (operator can recognise
9
+ * "is this my prod key" without copy-pasting the secret)
10
+ *
11
+ * `isMasked` is the inverse check used on PUT to drop "client echoed
12
+ * the mask back" updates so a real value isn't overwritten with
13
+ * literal asterisks. The two functions MUST stay in sync — extracted
14
+ * here as a module so the bun unit suite can assert that property
15
+ * directly (see test/unit/env-mask.test.ts).
16
+ *
17
+ * Both functions are pure / dependency-free.
18
+ */
19
+ export declare function maskSecret(v: string): string;
20
+ export declare function isMasked(value: string | undefined): boolean;
21
+ //# sourceMappingURL=env-mask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-mask.d.ts","sourceRoot":"","sources":["../../src/web/env-mask.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5C;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAW3D"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Secret-masking helpers for the web env editor (GET/PUT /api/env).
3
+ *
4
+ * `maskSecret` produces the wire form returned in the masked GET:
5
+ * * empty → ''
6
+ * * ≤ 8 chars → repeated '*' of same length (so length is preserved
7
+ * for UI sizing but no info leaks)
8
+ * * > 8 chars → first 4 + asterisks + last 4 (operator can recognise
9
+ * "is this my prod key" without copy-pasting the secret)
10
+ *
11
+ * `isMasked` is the inverse check used on PUT to drop "client echoed
12
+ * the mask back" updates so a real value isn't overwritten with
13
+ * literal asterisks. The two functions MUST stay in sync — extracted
14
+ * here as a module so the bun unit suite can assert that property
15
+ * directly (see test/unit/env-mask.test.ts).
16
+ *
17
+ * Both functions are pure / dependency-free.
18
+ */
19
+ export function maskSecret(v) {
20
+ if (!v)
21
+ return '';
22
+ // Threshold bumped from 8 → 10 (R9): below 11 chars there's no room
23
+ // for the 4+N+4 form to leave ≥3 asterisks in the middle, which is
24
+ // what isMasked uses to distinguish "this is a mask" from "this just
25
+ // happens to contain an asterisk." For 9-10 char secrets we now show
26
+ // pure asterisks instead.
27
+ if (v.length <= 10)
28
+ return '*'.repeat(v.length);
29
+ return v.slice(0, 4) + '*'.repeat(v.length - 8) + v.slice(-4);
30
+ }
31
+ export function isMasked(value) {
32
+ if (!value)
33
+ return false;
34
+ // Two valid mask shapes from maskSecret() above:
35
+ // * pure asterisks (≤8 chars)
36
+ // * `<≤4 chars>****<≤4 chars>` (>8 chars; padding is 4 chars on
37
+ // each side, but we allow 0..4 to keep the regex tolerant of
38
+ // hand-typed masks in tests / cli probes)
39
+ // The non-padding chars must NOT themselves be asterisks, otherwise
40
+ // a real secret like `***foo***` would be considered masked and
41
+ // silently dropped on PUT.
42
+ return /^\*+$/.test(value) || /^[^*]{0,4}\*{3,}[^*]{0,4}$/.test(value);
43
+ }
44
+ //# sourceMappingURL=env-mask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-mask.js","sourceRoot":"","sources":["../../src/web/env-mask.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACjB,oEAAoE;IACpE,mEAAmE;IACnE,qEAAqE;IACrE,qEAAqE;IACrE,0BAA0B;IAC1B,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC/C,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAyB;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,iDAAiD;IACjD,gCAAgC;IAChC,kEAAkE;IAClE,iEAAiE;IACjE,8CAA8C;IAC9C,oEAAoE;IACpE,gEAAgE;IAChE,2BAA2B;IAC3B,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACxE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import{x as p,aa as f,q as o,ac as g,Q as t,r as m,c as j}from"./index-CpGWCLE5.js";import{e as N}from"./react-C9F3QeMB.js";import{D as y}from"./data-table--I_ktDF4.js";import{E as b}from"./empty-state-DXNa90pP.js";import{S as w}from"./status-badge-CsdJ6k8Q.js";import{u as x}from"./useQuery-BTyugXYV.js";import{u as v}from"./use-event-stream-BGeFcayX.js";import{L as A}from"./loader-circle-JaKY-xMt.js";import{R as S}from"./refresh-ccw-Bx817_KW.js";import"./table-vmLMgj6_.js";/**
2
+ * @license lucide-react v0.469.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const C=p("GitBranch",[["line",{x1:"6",x2:"6",y1:"3",y2:"15",key:"17qcm7"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["path",{d:"M18 9a9 9 0 0 1-9 9",key:"n2h4wq"}]]),l={all:["a2a"],stats:["a2a","stats"],recent:e=>["a2a","recent",e]};function q(){return x({queryKey:l.stats,queryFn:()=>o.getA2AStats()})}function T(e){return x({queryKey:l.recent(e),queryFn:()=>o.getA2ARecent(e)})}function E(){const e=f();return()=>e.invalidateQueries({queryKey:l.all})}const L={connected:"text-success",connecting:"text-text-dim",reconnecting:"text-warning",closed:"text-text-muted"};function z(){const{t:e}=g(["tasks","common"]),s=E(),n=q(),r=T({limit:50}),u=r.data?.rows??[],c=n.data,d=v({job:()=>s()}),h=N.useMemo(()=>[{id:"id",header:e("a2a.col.id"),cell:a=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",a.id]}),headClassName:"w-16"},{id:"agent",header:e("a2a.col.agent"),cell:a=>t.jsx("span",{className:"font-medium",children:a.agent}),headClassName:"w-32"},{id:"parent",header:e("a2a.col.parent"),cell:a=>a.parent_id!=null?t.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",a.parent_id]}):t.jsx("span",{className:"text-text-muted",children:"—"}),headClassName:"w-20"},{id:"depth",header:e("a2a.col.depth"),cell:a=>t.jsx("span",{className:"tabular-nums text-text-dim",children:a.call_depth}),headClassName:"w-16",hideOnMobile:!0},{id:"status",header:e("a2a.col.status"),cell:a=>t.jsx(w,{status:a.status,children:a.status}),headClassName:"w-28"},{id:"prompt",header:e("a2a.col.prompt"),cell:a=>t.jsx("span",{className:"line-clamp-2 text-text-dim",children:a.prompt??"—"}),asCardTitle:!0},{id:"createdAt",header:e("a2a.col.createdAt"),cell:a=>t.jsx("span",{className:"text-text-dim",children:R(a.created_at)}),headClassName:"w-40",hideOnMobile:!0}],[e]);return t.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[t.jsxs("header",{className:"flex flex-col gap-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[t.jsx("h1",{className:"text-xl font-semibold",children:e("a2a.title")}),t.jsx("span",{className:m("text-xs font-medium tabular-nums",L[d]),children:e(`jobs.live.${d}`)}),t.jsxs(j,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>{r.refetch(),n.refetch()},disabled:r.isFetching||n.isFetching,"aria-label":e("actions.refresh",{ns:"common"}),children:[r.isFetching?t.jsx(A,{className:"h-4 w-4 animate-spin"}):t.jsx(S,{className:"h-4 w-4"}),t.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),t.jsx("p",{className:"text-sm text-text-dim",children:e("a2a.subtitle")})]}),c&&t.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[t.jsx(i,{label:e("a2a.stats.total"),value:c.total,tone:"info"}),t.jsx(i,{label:e("a2a.stats.recent24h"),value:c.recent24h,tone:"success"}),t.jsx(i,{label:e("a2a.stats.maxDepth"),value:c.maxDepth,tone:"warning"})]}),t.jsx(y,{columns:h,rows:u,getRowId:a=>String(a.id),loading:r.isLoading,emptyState:t.jsx(b,{icon:t.jsx(C,{}),title:e("a2a.empty.title"),description:e("a2a.empty.description")})})]})}const k={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function i({label:e,value:s,tone:n}){return t.jsxs("div",{className:m("rounded-md border bg-surface px-3 py-2",k[n]),children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e}),t.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:s})]})}function R(e){try{const s=new Date(e);return Number.isNaN(s.getTime())?e:s.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}export{z as default};
7
+ //# sourceMappingURL=a2a-Dk2fSs33.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a2a-Dk2fSs33.js","sources":["../../node_modules/lucide-react/dist/esm/icons/git-branch.js","../../src/hooks/use-a2a.ts","../../src/routes/tasks/a2a.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst GitBranch = createLucideIcon(\"GitBranch\", [\n [\"line\", { x1: \"6\", x2: \"6\", y1: \"3\", y2: \"15\", key: \"17qcm7\" }],\n [\"circle\", { cx: \"18\", cy: \"6\", r: \"3\", key: \"1h7g24\" }],\n [\"circle\", { cx: \"6\", cy: \"18\", r: \"3\", key: \"fqmcym\" }],\n [\"path\", { d: \"M18 9a9 9 0 0 1-9 9\", key: \"n2h4wq\" }]\n]);\n\nexport { GitBranch as default };\n//# sourceMappingURL=git-branch.js.map\n","/**\n * useA2A* — react-query wrappers for the Agent-to-Agent inline-job\n * view. Read-only; data lives in jobs.db and is exposed via:\n *\n * GET /api/a2a/stats → totals, recent24h, maxDepth, byStatus/byAgent\n * GET /api/a2a/recent → recent rows (truncated prompt + result)\n *\n * SSE: subscribes to the `job` event so a freshly-completed inline\n * sub-invocation shows up without manual refresh.\n */\n\nimport { useQueryClient, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { A2AStats, ListA2ARecentQuery, ListA2ARecentResponse } from '@/types/api'\n\nexport const a2aKeys = {\n all: ['a2a'] as const,\n stats: ['a2a', 'stats'] as const,\n recent: (q: ListA2ARecentQuery) => ['a2a', 'recent', q] as const,\n}\n\nexport function useA2AStats() {\n return useQuery<A2AStats>({\n queryKey: a2aKeys.stats,\n queryFn: () => api.getA2AStats(),\n })\n}\n\nexport function useA2ARecent(query: ListA2ARecentQuery) {\n return useQuery<ListA2ARecentResponse>({\n queryKey: a2aKeys.recent(query),\n queryFn: () => api.getA2ARecent(query),\n })\n}\n\nexport function useInvalidateA2A() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: a2aKeys.all })\n}\n","/**\n * /tasks/a2a — Agent ↔ Agent inline-call history.\n *\n * Splits into stats KPI cards (total / recent24h / maxDepth) +\n * recent-rows table. Subscribes to the SSE `job` event so a fresh\n * agent-to-agent call appears live.\n */\n\nimport { useMemo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { GitBranch, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Button } from '@/components/ui/button'\nimport { useA2ARecent, useA2AStats, useInvalidateA2A } from '@/hooks/use-a2a'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { A2ARow } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function A2ARoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const invalidate = useInvalidateA2A()\n\n const statsQuery = useA2AStats()\n const recentQuery = useA2ARecent({ limit: 50 })\n const rows = recentQuery.data?.rows ?? []\n const stats = statsQuery.data\n\n const live = useEventStream({\n job: () => invalidate(),\n })\n\n const columns: DataTableColumn<A2ARow>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('a2a.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n },\n {\n id: 'agent',\n header: t('a2a.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'parent',\n header: t('a2a.col.parent'),\n cell: (r) =>\n r.parent_id != null ? (\n <span className=\"tabular-nums text-text-dim\">#{r.parent_id}</span>\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n headClassName: 'w-20',\n },\n {\n id: 'depth',\n header: t('a2a.col.depth'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">{r.call_depth}</span>,\n headClassName: 'w-16',\n hideOnMobile: true,\n },\n {\n id: 'status',\n header: t('a2a.col.status'),\n cell: (r) => <StatusBadge status={r.status}>{r.status}</StatusBadge>,\n headClassName: 'w-28',\n },\n {\n id: 'prompt',\n header: t('a2a.col.prompt'),\n cell: (r) => (\n <span className=\"line-clamp-2 text-text-dim\">{r.prompt ?? '—'}</span>\n ),\n asCardTitle: true,\n },\n {\n id: 'createdAt',\n header: t('a2a.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('a2a.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => {\n void recentQuery.refetch()\n void statsQuery.refetch()\n }}\n disabled={recentQuery.isFetching || statsQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {recentQuery.isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('a2a.subtitle')}</p>\n </header>\n\n {stats && (\n <div className=\"grid grid-cols-3 gap-2\">\n <StatCard label={t('a2a.stats.total')} value={stats.total} tone=\"info\" />\n <StatCard label={t('a2a.stats.recent24h')} value={stats.recent24h} tone=\"success\" />\n <StatCard label={t('a2a.stats.maxDepth')} value={stats.maxDepth} tone=\"warning\" />\n </div>\n )}\n\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(r) => String(r.id)}\n loading={recentQuery.isLoading}\n emptyState={\n <EmptyState\n icon={<GitBranch />}\n title={t('a2a.empty.title')}\n description={t('a2a.empty.description')}\n />\n }\n />\n </div>\n )\n}\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n"],"names":["GitBranch","createLucideIcon","a2aKeys","q","useA2AStats","useQuery","api","useA2ARecent","query","useInvalidateA2A","qc","useQueryClient","LIVE_STATUS_CLASS","A2ARoute","t","useTranslation","invalidate","statsQuery","recentQuery","rows","stats","live","useEventStream","columns","useMemo","r","jsxs","jsx","StatusBadge","formatTime","cn","Button","Loader2","RefreshCcw","StatCard","DataTable","EmptyState","TONE_STYLES","label","value","tone","iso","d"],"mappings":"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","x_google_ignoreList":[0]}
@@ -0,0 +1,7 @@
1
+ import{x as t}from"./index-CpGWCLE5.js";/**
2
+ * @license lucide-react v0.469.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const c=t("Activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);export{c as A};
7
+ //# sourceMappingURL=activity-eiIPshcV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-eiIPshcV.js","sources":["../../node_modules/lucide-react/dist/esm/icons/activity.js"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Activity = createLucideIcon(\"Activity\", [\n [\n \"path\",\n {\n d: \"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\",\n key: \"169zse\"\n }\n ]\n]);\n\nexport { Activity as default };\n//# sourceMappingURL=activity.js.map\n"],"names":["Activity","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAWC,EAAiB,WAAY,CAC5C,CACE,OACA,CACE,EAAG,6HACH,IAAK,QACX,CACA,CACA,CAAC","x_google_ignoreList":[0]}
@@ -0,0 +1,12 @@
1
+ import{x as A,ac as S,Q as s,c as d,B as c,L as N,I as y,a2 as n,z as w}from"./index-CpGWCLE5.js";import{e as x}from"./react-C9F3QeMB.js";import{C as L}from"./confirm-dialog-Baz_xFle.js";import{E as P}from"./empty-state-DXNa90pP.js";import{T as z,d as E,e as C,c as h,a as B,b as u}from"./table-vmLMgj6_.js";import{a as F,u as D,e as H}from"./use-settings-CU-UcrVD.js";import{L as T}from"./loader-circle-JaKY-xMt.js";import{R as U}from"./refresh-ccw-Bx817_KW.js";import{T as _}from"./trash-2-ZIitN_U3.js";import"./dialog-DZpoEskO.js";import"./x-Ru3rHT82.js";import"./useQuery-BTyugXYV.js";/**
2
+ * @license lucide-react v0.469.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const M=A("Shield",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]]);/**
7
+ * @license lucide-react v0.469.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const Q=A("UserPlus",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]]);function es(){const{t:e}=S(["settings","common"]),i=F(),t=i.data,r=D(),f=H(),[l,p]=x.useState(""),[m,j]=x.useState(""),[o,g]=x.useState(null);async function I(a){a.preventDefault();const b=l.trim(),v=m.trim();if(!(!b||!v))try{await r.mutateAsync({platform:b,userId:v}),n.success(e("admins.toast.added")),p(""),j("")}catch(R){n.error(w(R,e).message)}}async function k(){if(o)try{await f.mutateAsync(o),n.success(e("admins.toast.removed"))}catch(a){throw n.error(w(a,e).message),a}}return s.jsxs("div",{className:"mx-auto flex max-w-4xl flex-col gap-4",children:[s.jsxs("header",{className:"flex flex-col gap-1",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[s.jsx("h1",{className:"text-xl font-semibold",children:e("admins.title")}),s.jsxs(d,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>i.refetch(),disabled:i.isFetching,"aria-label":e("actions.refresh",{ns:"common"}),children:[i.isFetching?s.jsx(T,{className:"h-4 w-4 animate-spin"}):s.jsx(U,{className:"h-4 w-4"}),s.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),s.jsx("p",{className:"text-sm text-text-dim",children:e("admins.subtitle")})]}),t&&s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.configured?s.jsx(c,{variant:"success",children:e("admins.configured")}):s.jsx(c,{variant:"warning",children:e("admins.notConfigured")}),t.bootstrapAvailable&&s.jsx(c,{variant:"info",title:t.bootstrapTokenPath,children:e("admins.bootstrapAvailable")})]}),i.isLoading?s.jsx("div",{className:"h-32 rounded-md bg-surface-2 animate-pulse"}):t&&t.admins.length===0?s.jsx(P,{icon:s.jsx(M,{}),title:e("admins.empty")}):t?s.jsxs(z,{children:[s.jsx(E,{children:s.jsxs(C,{children:[s.jsx(h,{className:"w-40",children:e("admins.col.platform")}),s.jsx(h,{children:e("admins.col.userId")}),s.jsx(h,{className:"w-24"})]})}),s.jsx(B,{children:t.admins.map(a=>s.jsxs(C,{children:[s.jsx(u,{className:"font-mono",children:a.platform}),s.jsx(u,{className:"font-mono text-xs",children:a.userId}),s.jsx(u,{children:s.jsxs(d,{variant:"ghost",size:"sm",onClick:()=>g(a),disabled:f.isPending,"aria-label":e("admins.remove.label"),children:[s.jsx(_,{className:"h-3 w-3"}),s.jsx("span",{className:"sr-only sm:not-sr-only sm:ml-1",children:e("admins.remove.label")})]})})]},`${a.platform}:${a.userId}`))})]}):null,s.jsxs("form",{onSubmit:a=>void I(a),className:"rounded-md border border-border bg-surface p-4",children:[s.jsx("div",{className:"mb-3 text-sm font-medium",children:e("admins.add.title")}),s.jsxs("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-[180px_1fr_auto] sm:items-end",children:[s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(N,{htmlFor:"admin-platform",className:"text-xs text-text-dim",children:e("admins.add.platform")}),s.jsx(y,{id:"admin-platform",value:l,onChange:a=>p(a.target.value),placeholder:"wechat",className:"font-mono text-xs"})]}),s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(N,{htmlFor:"admin-user",className:"text-xs text-text-dim",children:e("admins.add.userId")}),s.jsx(y,{id:"admin-user",value:m,onChange:a=>j(a.target.value),placeholder:"wxid_abc123",className:"font-mono text-xs"})]}),s.jsxs(d,{type:"submit",size:"sm",disabled:r.isPending||!l.trim()||!m.trim(),children:[r.isPending?s.jsx(T,{className:"h-4 w-4 animate-spin"}):s.jsx(Q,{className:"h-4 w-4"}),e("admins.add.submit")]})]})]}),s.jsx(L,{open:o!=null,onOpenChange:a=>{a||g(null)},title:e("admins.remove.confirmTitle"),description:e("admins.remove.confirmDescription"),intent:"danger",confirmLabel:e("admins.remove.label"),onConfirm:k})]})}export{es as default};
12
+ //# sourceMappingURL=admins-DlbQYdW_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admins-DlbQYdW_.js","sources":["../../node_modules/lucide-react/dist/esm/icons/shield.js","../../node_modules/lucide-react/dist/esm/icons/user-plus.js","../../src/routes/settings/admins.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Shield = createLucideIcon(\"Shield\", [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ]\n]);\n\nexport { Shield as default };\n//# sourceMappingURL=shield.js.map\n","/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst UserPlus = createLucideIcon(\"UserPlus\", [\n [\"path\", { d: \"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\", key: \"1yyitq\" }],\n [\"circle\", { cx: \"9\", cy: \"7\", r: \"4\", key: \"nufk8\" }],\n [\"line\", { x1: \"19\", x2: \"19\", y1: \"8\", y2: \"14\", key: \"1bvyxn\" }],\n [\"line\", { x1: \"22\", x2: \"16\", y1: \"11\", y2: \"11\", key: \"1shjgl\" }]\n]);\n\nexport { UserPlus as default };\n//# sourceMappingURL=user-plus.js.map\n","/**\n * /settings/admins — manage `IMHUB_ADMIN_USERS` entries.\n *\n * Each entry is a `(platform, userId)` pair (e.g. `wechat:wxid_abc`).\n * Add via the inline form at the bottom; remove via per-row trash\n * button → ConfirmDialog. The backend's POST/DELETE handlers gate\n * on isLocalBind — if the operator is hitting agim from another\n * host the mutations 403; we surface that toast verbatim.\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, RefreshCcw, Shield, Trash2, UserPlus } from 'lucide-react'\n\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport {\n useAddAdmin,\n useAdminAllowlist,\n useRemoveAdmin,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport type { AdminEntry } from '@/types/api'\n\nexport default function SettingsAdminsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useAdminAllowlist()\n const data = listQuery.data\n\n const addAdmin = useAddAdmin()\n const removeAdmin = useRemoveAdmin()\n\n const [platform, setPlatform] = useState('')\n const [userId, setUserId] = useState('')\n const [removeTarget, setRemoveTarget] = useState<AdminEntry | null>(null)\n\n async function onAdd(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n const p = platform.trim()\n const u = userId.trim()\n if (!p || !u) return\n try {\n await addAdmin.mutateAsync({ platform: p, userId: u })\n toast.success(t('admins.toast.added'))\n setPlatform('')\n setUserId('')\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onConfirmRemove(): Promise<void> {\n if (!removeTarget) return\n try {\n await removeAdmin.mutateAsync(removeTarget)\n toast.success(t('admins.toast.removed'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n throw err\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-4xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('admins.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => listQuery.refetch()}\n disabled={listQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {listQuery.isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('admins.subtitle')}</p>\n </header>\n\n {data && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {data.configured ? (\n <Badge variant=\"success\">{t('admins.configured')}</Badge>\n ) : (\n <Badge variant=\"warning\">{t('admins.notConfigured')}</Badge>\n )}\n {data.bootstrapAvailable && (\n <Badge variant=\"info\" title={data.bootstrapTokenPath}>\n {t('admins.bootstrapAvailable')}\n </Badge>\n )}\n </div>\n )}\n\n {listQuery.isLoading ? (\n <div className=\"h-32 rounded-md bg-surface-2 animate-pulse\" />\n ) : data && data.admins.length === 0 ? (\n <EmptyState icon={<Shield />} title={t('admins.empty')} />\n ) : data ? (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-40\">{t('admins.col.platform')}</TableHead>\n <TableHead>{t('admins.col.userId')}</TableHead>\n <TableHead className=\"w-24\" />\n </TableRow>\n </TableHeader>\n <TableBody>\n {data.admins.map((a) => (\n <TableRow key={`${a.platform}:${a.userId}`}>\n <TableCell className=\"font-mono\">{a.platform}</TableCell>\n <TableCell className=\"font-mono text-xs\">{a.userId}</TableCell>\n <TableCell>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setRemoveTarget(a)}\n disabled={removeAdmin.isPending}\n aria-label={t('admins.remove.label')}\n >\n <Trash2 className=\"h-3 w-3\" />\n <span className=\"sr-only sm:not-sr-only sm:ml-1\">{t('admins.remove.label')}</span>\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n ) : null}\n\n {/* Add form */}\n <form\n onSubmit={(e) => void onAdd(e)}\n className=\"rounded-md border border-border bg-surface p-4\"\n >\n <div className=\"mb-3 text-sm font-medium\">{t('admins.add.title')}</div>\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-[180px_1fr_auto] sm:items-end\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"admin-platform\" className=\"text-xs text-text-dim\">\n {t('admins.add.platform')}\n </Label>\n <Input\n id=\"admin-platform\"\n value={platform}\n onChange={(e) => setPlatform(e.target.value)}\n placeholder=\"wechat\"\n className=\"font-mono text-xs\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"admin-user\" className=\"text-xs text-text-dim\">\n {t('admins.add.userId')}\n </Label>\n <Input\n id=\"admin-user\"\n value={userId}\n onChange={(e) => setUserId(e.target.value)}\n placeholder=\"wxid_abc123\"\n className=\"font-mono text-xs\"\n />\n </div>\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={addAdmin.isPending || !platform.trim() || !userId.trim()}\n >\n {addAdmin.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <UserPlus className=\"h-4 w-4\" />}\n {t('admins.add.submit')}\n </Button>\n </div>\n </form>\n\n <ConfirmDialog\n open={removeTarget != null}\n onOpenChange={(open) => { if (!open) setRemoveTarget(null) }}\n title={t('admins.remove.confirmTitle')}\n description={t('admins.remove.confirmDescription')}\n intent=\"danger\"\n confirmLabel={t('admins.remove.label')}\n onConfirm={onConfirmRemove}\n />\n </div>\n )\n}\n"],"names":["Shield","createLucideIcon","UserPlus","SettingsAdminsRoute","t","useTranslation","listQuery","useAdminAllowlist","data","addAdmin","useAddAdmin","removeAdmin","useRemoveAdmin","platform","setPlatform","useState","userId","setUserId","removeTarget","setRemoveTarget","onAdd","e","p","u","toast","err","describeError","onConfirmRemove","jsxs","jsx","Button","Loader2","RefreshCcw","Badge","EmptyState","Table","TableHeader","TableRow","TableHead","TableBody","TableCell","Trash2","Label","Input","ConfirmDialog","open"],"mappings":"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","x_google_ignoreList":[0,1]}