chainlesschain 0.162.155 → 0.162.156

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 (166) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-Cth_zZeA.js → AIOps-DjBXlypQ.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-zfwA3Oxn.js → ActionButton-Cv9er9bp.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-FeKc4aU2.js → Analytics-CLKDjSNs.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-C6WIrDZk.js → AppLayout-CfyZNzmJ.js} +3 -3
  7. package/src/assets/web-panel/assets/{Audit-C2gRq5Qi.js → Audit-CXafD178.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-TeTIFiW-.js → BackgroundAgents-CP5c-GSd.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-CLJk3k6i.js → Backup-BbYLQfyt.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-5ms537NY.js → BaseInput-Bqe0MwZL.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-4Nr5U9PJ.js → Chat-jNA_yUPH.js} +4 -4
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-BOFLF01s.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-B2Bca5ev.js → Checkbox-Dlzz-zD1.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-D6Uysdbv.js → Codegen-BAsDQjGf.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-B3XQ8xc7.js → Col-Ju0HrAuS.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CqwKtoPz.js → Community-DynJd43Z.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BZZINTus.js → Compact-CabbZVww.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Dr3BXkWA.js → Compliance-DW4BmAoh.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-rx_x9Wqc.js → Cowork-Bk1S_7X-.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-BpZr7rHc.js → Cron-By4sh_NM.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CeV5EYVg.js → Crosschain-DdZdbS1C.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-fe2Qaowz.js → DID-CkL-sQyS.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-Fh_EdWVa.js → Dashboard-g_mOpumg.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-N1PIwWYf.js → Dropdown-DtHyE7Ao.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-B6vK93Ed.js → EmailListRenderer-Kpvov5Wr.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-e3iUZhAg.js → FamilyGuardDashboard-C4kZoePR.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-uInc9YcN.js → Federation-BAwWoK2N.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-DmQZSX0z.js → FormItemContext-DeI0i5f8.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-CV_Z8OAo.js → GenericCardRenderer-CkcKRtos.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-jXAhNN8d.js → Git-kX6jjI9y.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Blw1esBB.js → Governance-BXJCBm6x.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-CoK8Ia0Z.js → Inference-ujD2JSKo.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-5xrglMTK.js → KnowledgeGraph-3Dnuf1Wh.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-BGIG9798.js → Logs-lVAZCtUB.js} +2 -2
  35. package/src/assets/web-panel/assets/{Marketplace-DFqhJMuY.js → Marketplace-qnzNPm-A.js} +1 -1
  36. package/src/assets/web-panel/assets/{McpTools-7U8tEhwK.js → McpTools-CqjzefRU.js} +4 -4
  37. package/src/assets/web-panel/assets/{Memory-BrvboPLE.js → Memory-BFiPAxk6.js} +2 -2
  38. package/src/assets/web-panel/assets/{MobileBridge-nzcd7d1H.js → MobileBridge-D0O43VwF.js} +1 -1
  39. package/src/assets/web-panel/assets/{MobileProjects-DETVNKa7.js → MobileProjects-B3now48t.js} +1 -1
  40. package/src/assets/web-panel/assets/{Mtc-SZcCYec3.js → Mtc-DybhtaCS.js} +2 -2
  41. package/src/assets/web-panel/assets/{MtcAudit-Cx_d3N17.js → MtcAudit-D7MmY4F0.js} +2 -2
  42. package/src/assets/web-panel/assets/{Multisig-DtcmSUo-.js → Multisig-wZvGJnB8.js} +3 -3
  43. package/src/assets/web-panel/assets/{NLProgramming-Dgx2QHl-.js → NLProgramming-BNPpgfvn.js} +1 -1
  44. package/src/assets/web-panel/assets/{Notes-oHTGEHoJ.js → Notes-B6FS3KBj.js} +3 -3
  45. package/src/assets/web-panel/assets/{NotificationSettings-qKD-IlOl.js → NotificationSettings-CK0yla9U.js} +1 -1
  46. package/src/assets/web-panel/assets/OrderTableRenderer-CXfPHIpy.js +1 -0
  47. package/src/assets/web-panel/assets/{Organization-BBNXnltP.js → Organization-geqgwN1T.js} +4 -4
  48. package/src/assets/web-panel/assets/{Overflow-Df2fDbvT.js → Overflow-BWJYZFbC.js} +1 -1
  49. package/src/assets/web-panel/assets/{P2P-DUHj6zjO.js → P2P-DnU1505F.js} +2 -2
  50. package/src/assets/web-panel/assets/{PdhVaultBrowser-B2nWgdoV.js → PdhVaultBrowser-BGY74KnC.js} +4 -4
  51. package/src/assets/web-panel/assets/{Permissions-CiW0afny.js → Permissions-CgArrWtQ.js} +3 -3
  52. package/src/assets/web-panel/assets/{PersonalDataHub-cc1mHU_D.js → PersonalDataHub-C2vYE61a.js} +2 -2
  53. package/src/assets/web-panel/assets/{Pipeline-B93zTapU.js → Pipeline-CBYLI4yW.js} +1 -1
  54. package/src/assets/web-panel/assets/{Privacy-Db1jXWfd.js → Privacy-B-PdW9aN.js} +1 -1
  55. package/src/assets/web-panel/assets/{ProjectInit-DFoZ1h9U.js → ProjectInit-CuWQegbV.js} +2 -2
  56. package/src/assets/web-panel/assets/{ProjectSettings-BkkUnmYs.js → ProjectSettings-4d32m_cS.js} +2 -2
  57. package/src/assets/web-panel/assets/{Projects-Xa779XLC.js → Projects-VLA7ttwd.js} +1 -1
  58. package/src/assets/web-panel/assets/{Providers-DOF01IEN.js → Providers-B_Izb_oa.js} +1 -1
  59. package/src/assets/web-panel/assets/{QrScannerModal-TohRsKd0.js → QrScannerModal-C6B_ndXV.js} +1 -1
  60. package/src/assets/web-panel/assets/{QuickAsk-DjLcr1ZU.js → QuickAsk-C6tavL-y.js} +1 -1
  61. package/src/assets/web-panel/assets/{Recommend--Ism6bMx.js → Recommend-CF-LaZ6x.js} +1 -1
  62. package/src/assets/web-panel/assets/{RemoteSession-B8CL3YHM.js → RemoteSession-DBqTTQ9_.js} +2 -2
  63. package/src/assets/web-panel/assets/{Reputation-CaRxB3Ep.js → Reputation-B01FALUi.js} +1 -1
  64. package/src/assets/web-panel/assets/{Row-BioxZBBH.js → Row-DO0fd48A.js} +1 -1
  65. package/src/assets/web-panel/assets/{RssFeed-B2LipwH3.js → RssFeed-BV5LDzFR.js} +2 -2
  66. package/src/assets/web-panel/assets/{Search-BpjLBV8u.js → Search-CTti4_MP.js} +1 -1
  67. package/src/assets/web-panel/assets/{Security-TibHuJWP.js → Security-DwSrWRCw.js} +4 -4
  68. package/src/assets/web-panel/assets/{Services-DtkuWseW.js → Services-BEf1QyM4.js} +2 -2
  69. package/src/assets/web-panel/assets/{Skeleton-BIcPQae6.js → Skeleton-LZXTpovy.js} +1 -1
  70. package/src/assets/web-panel/assets/Skills-SKgc0Zug.js +1 -0
  71. package/src/assets/web-panel/assets/{Sla-uUSU185m.js → Sla-C_QVOtkN.js} +1 -1
  72. package/src/assets/web-panel/assets/{SpeechSettings-B7Bgc9mk.js → SpeechSettings-v5TW2V-X.js} +1 -1
  73. package/src/assets/web-panel/assets/{SyncSettings-K-XrJ2s9.js → SyncSettings-CQPjHdqU.js} +2 -2
  74. package/src/assets/web-panel/assets/Tasks-DCd-uYcI.js +1 -0
  75. package/src/assets/web-panel/assets/{Templates-CaFnyGDK.js → Templates-62VDIjtj.js} +1 -1
  76. package/src/assets/web-panel/assets/{Tenant-C2X0PtEC.js → Tenant-BnFQ0pNy.js} +1 -1
  77. package/src/assets/web-panel/assets/{Terminal-CKU5yVsT.js → Terminal-D3v0MGSj.js} +2 -2
  78. package/src/assets/web-panel/assets/{TimelineRenderer-8trZeYDC.js → TimelineRenderer-BI1Ka-cu.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tokens-BUEEe9US.js → Tokens-BwX1jXYP.js} +1 -1
  80. package/src/assets/web-panel/assets/{Trigger-COU97I7Y.js → Trigger-CSA8TqNx.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trust-DNWQChaP.js → Trust-Bn3IjCx7.js} +1 -1
  82. package/src/assets/web-panel/assets/{UkeySign-DWX_VtCp.js → UkeySign-pUbOAqNi.js} +1 -1
  83. package/src/assets/web-panel/assets/{VideoEditing-D9eIDhsp.js → VideoEditing-Db2RercF.js} +1 -1
  84. package/src/assets/web-panel/assets/{Wallet-BOnCCgIL.js → Wallet-CpR1BVAl.js} +4 -4
  85. package/src/assets/web-panel/assets/{WebAuthn-DN4dD-W8.js → WebAuthn-Yxtkn7Zp.js} +5 -5
  86. package/src/assets/web-panel/assets/{WorkflowEditor-ClvDb_jX.js → WorkflowEditor-CYLe9a2E.js} +1 -1
  87. package/src/assets/web-panel/assets/{chat-DIxQ_Eeb.js → chat-gsOGdak0.js} +1 -1
  88. package/src/assets/web-panel/assets/{colors-BOX3WKcP.js → colors-D9fN299a.js} +1 -1
  89. package/src/assets/web-panel/assets/{compact-item-Bny82VDi.js → compact-item-vkd7s-ay.js} +1 -1
  90. package/src/assets/web-panel/assets/{createContext-Cnoy3enS.js → createContext-C7YkbMyy.js} +1 -1
  91. package/src/assets/web-panel/assets/devWarning-DEcR2h6k.js +1 -0
  92. package/src/assets/web-panel/assets/{hasIn-BJ7fkx3F.js → hasIn-ig7reRSU.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-CZCTan8Q.js → index-9TxdMYju.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-7GLXvG8p.js → index-B7QRpKif.js} +1 -1
  95. package/src/assets/web-panel/assets/index-BEibanjg.js +1 -0
  96. package/src/assets/web-panel/assets/{index-CEPTiBWy.js → index-BHHN_KTS.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DBhkJqVF.js → index-BMw48d19.js} +1 -1
  98. package/src/assets/web-panel/assets/{index--CcGiwAI.js → index-BYe9HRSt.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-qOBKrw-g.js → index-BfpVcXKa.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BcmXbIwv.js → index-BhftELHI.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-C--PPqwi.js → index-BkP17Z95.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Kio1ekYg.js → index-BpGlLbRv.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CZ6CHiCQ.js → index-Bt-9ZhIu.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BM0mQhVv.js → index-BvDEukXe.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BJ8-oLHI.js → index-C7AY39sg.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-2N9Y1cLx.js → index-C8HZMygt.js} +1 -1
  107. package/src/assets/web-panel/assets/{index--Xb2lq6E.js → index-CAkz1f1r.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BbZynivw.js → index-CDWTycrg.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BDkN6YOI.js → index-CGzGe5tv.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D2qNdrNW.js → index-Co2NYyew.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BWPey0Uf.js → index-CspGymmg.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C1nHEOFE.js → index-D2yhtk6a.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CEq5Vh0i.js → index-D6s_kbjt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-D9QEc7Tq.js → index-DFM1oNe1.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Bk5yST66.js → index-DFfxF7Vt.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Ty4w18mR.js → index-DPguq3X7.js} +3 -3
  117. package/src/assets/web-panel/assets/{index-CQ-xLCVb.js → index-DQ8U7kzC.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-B6WoW8DJ.js → index-DZAxCnjS.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CnjtAKdw.js → index-DhdXbsXX.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-OaNFXV8N.js → index-DuwbKHoS.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CN6emwbq.js → index-DvCJXmrx.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-rn6xd12s.js → index-Dy_TKZ9h.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CW6n-y1L.js → index-FzGr6CVk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-ceH9DsAi.js → index-PkH39qsp.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DxX8hhmL.js → index-SDrcQXO1.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B7Fah_BX.js → index-W52sHRdr.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DSRIjAWO.js → index-bVbgYBhv.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BP7HFsAK.js → index-gj8kxcAi.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-B1-h2QrC.js → index-gpurplyq.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bvheiep2.js → index-nX8YE6cj.js} +1 -1
  131. package/src/assets/web-panel/assets/index-z_25tU3p.js +1 -0
  132. package/src/assets/web-panel/assets/{initDefaultProps-BmxMBuUZ.js → initDefaultProps-BrgfVRg9.js} +1 -1
  133. package/src/assets/web-panel/assets/{motion-DnXNwo2k.js → motion-D_3xmwac.js} +1 -1
  134. package/src/assets/web-panel/assets/{move-WnIJwmZN.js → move-DDDJdlxw.js} +1 -1
  135. package/src/assets/web-panel/assets/{mtc-parser-DAto-c2w.js → mtc-parser-BK2uEWwn.js} +1 -1
  136. package/src/assets/web-panel/assets/{omit-BtvW9W0H.js → omit-BPHKbDcf.js} +1 -1
  137. package/src/assets/web-panel/assets/{pickAttrs-DFqI9-_C.js → pickAttrs-LNnTscuz.js} +1 -1
  138. package/src/assets/web-panel/assets/{placementArrow-Dax6wOK3.js → placementArrow-CvmTZll5.js} +1 -1
  139. package/src/assets/web-panel/assets/{responsiveObserve-BUFWWC83.js → responsiveObserve-eBj7qi2J.js} +1 -1
  140. package/src/assets/web-panel/assets/{slide-DyARyuSz.js → slide-D68hHkrM.js} +1 -1
  141. package/src/assets/web-panel/assets/{statusUtils-BZSDugpi.js → statusUtils-daTlaeo0.js} +1 -1
  142. package/src/assets/web-panel/assets/{styleChecker-B7o_K-4R.js → styleChecker-DtyKMtHB.js} +1 -1
  143. package/src/assets/web-panel/assets/{useFlexGapSupport-Dg7Bg8VG.js → useFlexGapSupport-ekFwFs9h.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFs-DQYXo5Rk.js → useFs-jRaSEoF4.js} +1 -1
  145. package/src/assets/web-panel/assets/{usePersonalDataHub-E8NBAnkq.js → usePersonalDataHub-DD5nGzjA.js} +1 -1
  146. package/src/assets/web-panel/assets/{vnode-DD71_w1b.js → vnode-KcgLUiom.js} +1 -1
  147. package/src/assets/web-panel/assets/{zoom-zc9EMd3q.js → zoom-Cyk2PQ-s.js} +1 -1
  148. package/src/assets/web-panel/index.html +1 -1
  149. package/src/command-manifest.json +15 -1
  150. package/src/commands/agenda.js +228 -0
  151. package/src/commands/batch.js +345 -0
  152. package/src/data/changelog.json +7 -2
  153. package/src/index.js +12 -0
  154. package/src/lib/agent-batch.js +235 -0
  155. package/src/lib/agent-notify.js +66 -0
  156. package/src/lib/agent-schedule-store.js +330 -0
  157. package/src/runtime/agent-core.js +104 -0
  158. package/src/runtime/coding-agent-contract-shared.cjs +104 -0
  159. package/src/runtime/coding-agent-policy.cjs +28 -0
  160. package/src/assets/web-panel/assets/ChatBubbleRenderer-BFEnA8LN.js +0 -1
  161. package/src/assets/web-panel/assets/OrderTableRenderer-CiU4Sy1J.js +0 -1
  162. package/src/assets/web-panel/assets/Skills-DoTWIQOX.js +0 -1
  163. package/src/assets/web-panel/assets/Tasks-B3hEXNcI.js +0 -1
  164. package/src/assets/web-panel/assets/devWarning-Dr9dzlQ5.js +0 -1
  165. package/src/assets/web-panel/assets/index-B92M3t6B.js +0 -1
  166. package/src/assets/web-panel/assets/index-d2UcGpK-.js +0 -1
@@ -0,0 +1,66 @@
1
+ /**
2
+ * agent-notify — shared backing for the `notify` agent tool + `cc agenda`
3
+ * monitor firing (gap-analysis 第四阶段 #3).
4
+ *
5
+ * Fans a notification out over the user's configured multi-channel notifiers
6
+ * (Telegram / WeCom / DingTalk / Feishu, via NotificationManager.fromEnv) and,
7
+ * when a paired-device push descriptor exists, the mobile push bridge. Pure
8
+ * over injected deps so it is unit-testable without any network.
9
+ */
10
+
11
+ import { NotificationManager } from "./notifiers/index.js";
12
+
13
+ /**
14
+ * @param {{title:string, body?:string, level?:"info"|"success"|"failure"}} msg
15
+ * @param {{env?:object, manager?:object}} [deps]
16
+ * @returns {Promise<{delivered:string[], failed:string[], channels:number, results:Array}>}
17
+ */
18
+ export async function sendAgentNotification(msg, deps = {}) {
19
+ const title = String(msg?.title || "").trim();
20
+ if (!title) throw new Error("notify requires a title");
21
+ const body = msg?.body ? String(msg.body) : "";
22
+ const level = ["info", "success", "failure"].includes(msg?.level)
23
+ ? msg.level
24
+ : "info";
25
+
26
+ const manager =
27
+ deps.manager ||
28
+ NotificationManager.fromEnv({ env: deps.env || process.env });
29
+ if (!manager.isConfigured) {
30
+ return {
31
+ delivered: [],
32
+ failed: [],
33
+ channels: 0,
34
+ results: [],
35
+ note: "No notification channels configured (set TELEGRAM_BOT_TOKEN / WECOM_WEBHOOK_URL / DINGTALK_WEBHOOK_URL / FEISHU_WEBHOOK_URL).",
36
+ };
37
+ }
38
+
39
+ const summary = {
40
+ taskId: msg?.taskId || null,
41
+ description: title,
42
+ detail: body,
43
+ message: body || title,
44
+ title,
45
+ };
46
+ const method =
47
+ level === "success"
48
+ ? "notifySuccess"
49
+ : level === "failure"
50
+ ? "notifyFailure"
51
+ : "notifyStart";
52
+ const results = await manager[method](summary);
53
+
54
+ const delivered = [];
55
+ const failed = [];
56
+ for (const r of results || []) {
57
+ if (r && r.ok !== false) delivered.push(r.channel);
58
+ else failed.push(r?.channel || "unknown");
59
+ }
60
+ return {
61
+ delivered,
62
+ failed,
63
+ channels: (manager.activeChannels || []).length,
64
+ results: results || [],
65
+ };
66
+ }
@@ -0,0 +1,330 @@
1
+ /**
2
+ * AgentScheduleStore — persistent backing for the agent-callable Monitor /
3
+ * Cron / Wakeup tools (gap-analysis 第四阶段 #3).
4
+ *
5
+ * A one-shot `cc agent` turn cannot itself keep a timer alive, so these tools
6
+ * PERSIST their intent to a JSONL store under
7
+ * `~/.chainlesschain/agent-schedule/<kind>.jsonl`; a supervising loop / cron
8
+ * (`cc agenda run`) reads due entries and acts. This mirrors how Claude Code's
9
+ * Monitor/CronCreate/ScheduleWakeup outlive a single turn.
10
+ *
11
+ * Three entry kinds share one store:
12
+ * - wakeup one-shot: run `prompt` (a `cc agent -p`) once at/after `dueAt`.
13
+ * - cron recurring: run `prompt` on a cron schedule; `nextAt` advances.
14
+ * - monitor recurring watch: run `command` (shell) every `intervalMs`;
15
+ * fire the `notify` payload when `stopWhen` regex matches output.
16
+ *
17
+ * Pure over an injected clock + directory so it is fully unit-testable. Cron
18
+ * parsing is a compact 5-field evaluator (min hour dom mon dow) supporting
19
+ * `* , - /` — enough for the scheduling the agent actually asks for.
20
+ */
21
+
22
+ import fs from "fs";
23
+ import os from "os";
24
+ import path from "path";
25
+ import { randomUUID } from "crypto";
26
+
27
+ export const SCHEDULE_KINDS = Object.freeze(["wakeup", "cron", "monitor"]);
28
+
29
+ export function agentScheduleDir(homedir = os.homedir()) {
30
+ return path.join(homedir, ".chainlesschain", "agent-schedule");
31
+ }
32
+
33
+ // ─── cron (5-field) ────────────────────────────────────────────────────────
34
+
35
+ const CRON_RANGES = [
36
+ [0, 59], // minute
37
+ [0, 23], // hour
38
+ [1, 31], // day of month
39
+ [1, 12], // month
40
+ [0, 6], // day of week (0/7 = Sunday)
41
+ ];
42
+
43
+ function parseCronField(field, [min, max]) {
44
+ const values = new Set();
45
+ for (const part of String(field).split(",")) {
46
+ const [rangePart, stepPart] = part.split("/");
47
+ const step = stepPart ? parseInt(stepPart, 10) : 1;
48
+ if (!Number.isFinite(step) || step < 1) {
49
+ throw new Error(`invalid cron step in "${field}"`);
50
+ }
51
+ let lo = min;
52
+ let hi = max;
53
+ if (rangePart !== "*" && rangePart !== "") {
54
+ const bounds = rangePart.split("-");
55
+ lo = parseInt(bounds[0], 10);
56
+ hi = bounds.length > 1 ? parseInt(bounds[1], 10) : lo;
57
+ if (!Number.isFinite(lo) || !Number.isFinite(hi)) {
58
+ throw new Error(`invalid cron range in "${field}"`);
59
+ }
60
+ }
61
+ for (let v = lo; v <= hi; v += step) {
62
+ if (v < min || v > max) throw new Error(`cron value out of range: ${v}`);
63
+ values.add(v);
64
+ }
65
+ }
66
+ return values;
67
+ }
68
+
69
+ /** Parse a 5-field cron expression into per-field value sets. Throws on junk. */
70
+ export function parseCron(expr) {
71
+ const fields = String(expr).trim().split(/\s+/);
72
+ if (fields.length !== 5) {
73
+ throw new Error(
74
+ `cron expression must have 5 fields (min hour dom mon dow), got ${fields.length}`,
75
+ );
76
+ }
77
+ return fields.map((field, i) => parseCronField(field, CRON_RANGES[i]));
78
+ }
79
+
80
+ function cronMatches(sets, date) {
81
+ const dow = date.getDay(); // 0-6, Sun=0
82
+ return (
83
+ sets[0].has(date.getMinutes()) &&
84
+ sets[1].has(date.getHours()) &&
85
+ sets[2].has(date.getDate()) &&
86
+ sets[3].has(date.getMonth() + 1) &&
87
+ (sets[4].has(dow) || (sets[4].has(7) && dow === 0))
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Next epoch-ms at which `expr` fires strictly after `fromMs` (local time,
93
+ * minute granularity). Scans up to ~366 days then gives up (returns null) so a
94
+ * never-matching expression can't loop forever.
95
+ */
96
+ export function nextCronTime(expr, fromMs) {
97
+ const sets = parseCron(expr);
98
+ const cursor = new Date(fromMs);
99
+ cursor.setSeconds(0, 0);
100
+ cursor.setMinutes(cursor.getMinutes() + 1);
101
+ const limit = 366 * 24 * 60;
102
+ for (let i = 0; i < limit; i += 1) {
103
+ if (cronMatches(sets, cursor)) return cursor.getTime();
104
+ cursor.setMinutes(cursor.getMinutes() + 1);
105
+ }
106
+ return null;
107
+ }
108
+
109
+ // ─── store ───────────────────────────────────────────────────────────────
110
+
111
+ export class AgentScheduleStore {
112
+ constructor({ dir = null, now = () => Date.now() } = {}) {
113
+ this.dir = dir || agentScheduleDir();
114
+ this._now = typeof now === "function" ? now : () => now;
115
+ }
116
+
117
+ _file(kind) {
118
+ return path.join(this.dir, `${kind}.jsonl`);
119
+ }
120
+
121
+ _ensureDir() {
122
+ fs.mkdirSync(this.dir, { recursive: true, mode: 0o700 });
123
+ }
124
+
125
+ _readAll(kind) {
126
+ let raw;
127
+ try {
128
+ raw = fs.readFileSync(this._file(kind), "utf-8");
129
+ } catch {
130
+ return [];
131
+ }
132
+ const entries = [];
133
+ for (const line of raw.split("\n")) {
134
+ const trimmed = line.trim();
135
+ if (!trimmed) continue;
136
+ try {
137
+ entries.push(JSON.parse(trimmed));
138
+ } catch {
139
+ // Skip a corrupt line rather than throwing — one bad append must not
140
+ // poison the whole store (per-row resilience, like the JSON.parse sweep).
141
+ }
142
+ }
143
+ return entries;
144
+ }
145
+
146
+ _writeAll(kind, entries) {
147
+ this._ensureDir();
148
+ const body = entries.map((entry) => JSON.stringify(entry)).join("\n");
149
+ fs.writeFileSync(this._file(kind), body ? body + "\n" : "", {
150
+ encoding: "utf-8",
151
+ mode: 0o600,
152
+ });
153
+ }
154
+
155
+ // ── create ──────────────────────────────────────────────────────────────
156
+
157
+ scheduleWakeup({ prompt, delayMs = 0, dueAt = null, label = null } = {}) {
158
+ if (!prompt || typeof prompt !== "string") {
159
+ throw new Error("wakeup requires a prompt");
160
+ }
161
+ const now = this._now();
162
+ const entry = {
163
+ id: randomUUID(),
164
+ kind: "wakeup",
165
+ prompt,
166
+ label: label || null,
167
+ dueAt:
168
+ dueAt != null ? Number(dueAt) : now + Math.max(0, Number(delayMs) || 0),
169
+ createdAt: now,
170
+ status: "pending",
171
+ };
172
+ const entries = this._readAll("wakeup");
173
+ entries.push(entry);
174
+ this._writeAll("wakeup", entries);
175
+ return entry;
176
+ }
177
+
178
+ createCron({ prompt, cron, label = null } = {}) {
179
+ if (!prompt || typeof prompt !== "string") {
180
+ throw new Error("cron requires a prompt");
181
+ }
182
+ const now = this._now();
183
+ const nextAt = nextCronTime(cron, now); // validates the expression too
184
+ if (nextAt == null) {
185
+ throw new Error(`cron "${cron}" has no upcoming match`);
186
+ }
187
+ const entry = {
188
+ id: randomUUID(),
189
+ kind: "cron",
190
+ prompt,
191
+ cron,
192
+ label: label || null,
193
+ nextAt,
194
+ createdAt: now,
195
+ lastRunAt: null,
196
+ runs: 0,
197
+ status: "active",
198
+ };
199
+ const entries = this._readAll("cron");
200
+ entries.push(entry);
201
+ this._writeAll("cron", entries);
202
+ return entry;
203
+ }
204
+
205
+ createMonitor({
206
+ command,
207
+ intervalMs,
208
+ stopWhen = null,
209
+ notify = null,
210
+ maxChecks = null,
211
+ label = null,
212
+ } = {}) {
213
+ if (!command || typeof command !== "string") {
214
+ throw new Error("monitor requires a command");
215
+ }
216
+ const interval = Math.max(1000, Number(intervalMs) || 60000);
217
+ if (stopWhen != null) {
218
+ // Validate the regex up-front so a bad pattern errors at creation, not
219
+ // silently at the first check.
220
+ // eslint-disable-next-line no-new
221
+ new RegExp(stopWhen);
222
+ }
223
+ const now = this._now();
224
+ const entry = {
225
+ id: randomUUID(),
226
+ kind: "monitor",
227
+ command,
228
+ intervalMs: interval,
229
+ stopWhen: stopWhen || null,
230
+ notify: notify || null,
231
+ maxChecks: maxChecks != null ? Number(maxChecks) : null,
232
+ label: label || null,
233
+ nextAt: now + interval,
234
+ createdAt: now,
235
+ checks: 0,
236
+ status: "active",
237
+ };
238
+ const entries = this._readAll("monitor");
239
+ entries.push(entry);
240
+ this._writeAll("monitor", entries);
241
+ return entry;
242
+ }
243
+
244
+ // ── query ─────────────────────────────────────────────────────────────────
245
+
246
+ list(kind = null) {
247
+ const kinds = kind ? [kind] : SCHEDULE_KINDS;
248
+ const out = [];
249
+ for (const k of kinds) out.push(...this._readAll(k));
250
+ return out;
251
+ }
252
+
253
+ /** Entries whose time has come (pending wakeup / active cron|monitor). */
254
+ due(kind = null, atMs = null) {
255
+ const now = atMs != null ? atMs : this._now();
256
+ return this.list(kind).filter((entry) => {
257
+ if (entry.kind === "wakeup") {
258
+ return entry.status === "pending" && entry.dueAt <= now;
259
+ }
260
+ return entry.status === "active" && entry.nextAt <= now;
261
+ });
262
+ }
263
+
264
+ cancel(id) {
265
+ for (const kind of SCHEDULE_KINDS) {
266
+ const entries = this._readAll(kind);
267
+ const idx = entries.findIndex((entry) => entry.id === id);
268
+ if (idx >= 0) {
269
+ const [removed] = entries.splice(idx, 1);
270
+ this._writeAll(kind, entries);
271
+ return removed;
272
+ }
273
+ }
274
+ return null;
275
+ }
276
+
277
+ // ── lifecycle mutations (used by `cc agenda run`) ──────────────────────────
278
+
279
+ /** Mark a one-shot wakeup fired (keeps history; due() skips it). */
280
+ markWakeupFired(id, atMs = null) {
281
+ return this._mutate("wakeup", id, (entry) => {
282
+ entry.status = "fired";
283
+ entry.firedAt = atMs != null ? atMs : this._now();
284
+ });
285
+ }
286
+
287
+ /** Advance a cron entry to its next fire time after running once. */
288
+ advanceCron(id, atMs = null) {
289
+ const now = atMs != null ? atMs : this._now();
290
+ return this._mutate("cron", id, (entry) => {
291
+ entry.lastRunAt = now;
292
+ entry.runs = (entry.runs || 0) + 1;
293
+ const next = nextCronTime(entry.cron, now);
294
+ if (next == null) {
295
+ entry.status = "exhausted";
296
+ } else {
297
+ entry.nextAt = next;
298
+ }
299
+ });
300
+ }
301
+
302
+ /**
303
+ * Record a monitor check. `matched` ends the monitor (done); otherwise it is
304
+ * re-armed for the next interval, or exhausted once maxChecks is hit.
305
+ */
306
+ recordMonitorCheck(id, { matched = false, atMs = null } = {}) {
307
+ const now = atMs != null ? atMs : this._now();
308
+ return this._mutate("monitor", id, (entry) => {
309
+ entry.checks = (entry.checks || 0) + 1;
310
+ entry.lastCheckAt = now;
311
+ if (matched) {
312
+ entry.status = "matched";
313
+ entry.matchedAt = now;
314
+ } else if (entry.maxChecks != null && entry.checks >= entry.maxChecks) {
315
+ entry.status = "exhausted";
316
+ } else {
317
+ entry.nextAt = now + entry.intervalMs;
318
+ }
319
+ });
320
+ }
321
+
322
+ _mutate(kind, id, fn) {
323
+ const entries = this._readAll(kind);
324
+ const entry = entries.find((e) => e.id === id);
325
+ if (!entry) return null;
326
+ fn(entry);
327
+ this._writeAll(kind, entries);
328
+ return entry;
329
+ }
330
+ }
@@ -3010,6 +3010,100 @@ async function executeToolInner(
3010
3010
  }
3011
3011
  }
3012
3012
 
3013
+ case "notify": {
3014
+ try {
3015
+ const { sendAgentNotification } =
3016
+ await import("../lib/agent-notify.js");
3017
+ const outcome = await sendAgentNotification({
3018
+ title: args.title,
3019
+ body: args.body,
3020
+ level: args.level,
3021
+ });
3022
+ return attachDescriptor(outcome);
3023
+ } catch (err) {
3024
+ return attachDescriptor({ error: `notify failed: ${err.message}` });
3025
+ }
3026
+ }
3027
+
3028
+ case "schedule": {
3029
+ try {
3030
+ const { AgentScheduleStore } =
3031
+ await import("../lib/agent-schedule-store.js");
3032
+ const { parseDuration } = await import("../lib/loop.js");
3033
+ const store = new AgentScheduleStore();
3034
+ const action = String(args.action || "").toLowerCase();
3035
+ if (action === "wakeup") {
3036
+ if (!args.prompt) {
3037
+ return attachDescriptor({
3038
+ error: "schedule wakeup requires a prompt",
3039
+ });
3040
+ }
3041
+ const delayMs = args.delay ? parseDuration(args.delay) : 0;
3042
+ const entry = store.scheduleWakeup({
3043
+ prompt: args.prompt,
3044
+ delayMs,
3045
+ label: args.label || null,
3046
+ });
3047
+ return attachDescriptor({
3048
+ scheduled: entry,
3049
+ hint: "Run `cc agenda run` (e.g. via cron or `cc loop`) to fire due entries.",
3050
+ });
3051
+ }
3052
+ if (action === "cron") {
3053
+ if (!args.prompt || !args.cron) {
3054
+ return attachDescriptor({
3055
+ error: "schedule cron requires a prompt and a cron expression",
3056
+ });
3057
+ }
3058
+ const entry = store.createCron({
3059
+ prompt: args.prompt,
3060
+ cron: args.cron,
3061
+ label: args.label || null,
3062
+ });
3063
+ return attachDescriptor({ scheduled: entry });
3064
+ }
3065
+ if (action === "monitor") {
3066
+ if (!args.command) {
3067
+ return attachDescriptor({
3068
+ error: "schedule monitor requires a command",
3069
+ });
3070
+ }
3071
+ const intervalMs = args.interval
3072
+ ? parseDuration(args.interval)
3073
+ : 60000;
3074
+ const entry = store.createMonitor({
3075
+ command: args.command,
3076
+ intervalMs,
3077
+ stopWhen: args.stop_when || null,
3078
+ notify: args.notify_title ? { title: args.notify_title } : null,
3079
+ maxChecks: args.max_checks ?? null,
3080
+ label: args.label || null,
3081
+ });
3082
+ return attachDescriptor({ scheduled: entry });
3083
+ }
3084
+ if (action === "list") {
3085
+ return attachDescriptor({ entries: store.list() });
3086
+ }
3087
+ if (action === "cancel") {
3088
+ if (!args.id) {
3089
+ return attachDescriptor({
3090
+ error: "schedule cancel requires an id",
3091
+ });
3092
+ }
3093
+ const removed = store.cancel(args.id);
3094
+ return attachDescriptor({
3095
+ cancelled: removed ? removed.id : null,
3096
+ found: Boolean(removed),
3097
+ });
3098
+ }
3099
+ return attachDescriptor({
3100
+ error: `unknown schedule action "${args.action}". Valid: wakeup, cron, monitor, list, cancel.`,
3101
+ });
3102
+ } catch (err) {
3103
+ return attachDescriptor({ error: `schedule failed: ${err.message}` });
3104
+ }
3105
+ }
3106
+
3013
3107
  case "search_files": {
3014
3108
  // An explicit directory scopes the search to one root; otherwise span
3015
3109
  // cwd plus any --add-dir roots so cross-package searches find matches.
@@ -6342,6 +6436,16 @@ export function formatToolArgs(name, args) {
6342
6436
  return `[${args.role}] ${(args.task || "").substring(0, 60)}`;
6343
6437
  case "search_sessions":
6344
6438
  return `"${(args.query || "").substring(0, 60)}"`;
6439
+ case "notify":
6440
+ return `${args.level || "info"}: ${(args.title || "").substring(0, 50)}`;
6441
+ case "schedule":
6442
+ return args.action === "cron"
6443
+ ? `cron ${args.cron || ""}`.trim()
6444
+ : args.action === "monitor"
6445
+ ? `monitor ${(args.command || "").substring(0, 40)}`.trim()
6446
+ : args.action === "wakeup"
6447
+ ? `wakeup +${args.delay || "0s"}`
6448
+ : String(args.action || "");
6345
6449
  default:
6346
6450
  return JSON.stringify(args).substring(0, 60);
6347
6451
  }
@@ -849,6 +849,110 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
849
849
  tags: ["tool:search_sessions", "contract:coding-agent", "tier:extension"],
850
850
  },
851
851
  },
852
+ {
853
+ name: "notify",
854
+ title: "Send Notification",
855
+ kind: "notify",
856
+ tier: "extension",
857
+ description:
858
+ "Push a notification to the user's configured channels (Telegram / WeCom / DingTalk / Feishu) and/or a paired mobile device. Use for long-running tasks: report completion, flag that you need a human decision, or surface an error. Best-effort: reports which channels delivered.",
859
+ inputSchema: {
860
+ type: "object",
861
+ properties: {
862
+ title: { type: "string", description: "Short notification title" },
863
+ body: { type: "string", description: "Notification body text" },
864
+ level: {
865
+ type: "string",
866
+ enum: ["info", "success", "failure"],
867
+ description: "Severity (default: info)",
868
+ },
869
+ },
870
+ required: ["title"],
871
+ },
872
+ ...TOOL_POLICY_METADATA.notify,
873
+ permissions: {
874
+ level: "standard",
875
+ scopes: ["network:notify"],
876
+ },
877
+ telemetry: {
878
+ category: "notify",
879
+ tags: ["tool:notify", "contract:coding-agent", "tier:extension"],
880
+ },
881
+ },
882
+ {
883
+ name: "schedule",
884
+ title: "Schedule / Monitor",
885
+ kind: "schedule",
886
+ tier: "extension",
887
+ description:
888
+ "Set up work that outlives this turn (persisted for `cc agenda run` to execute). Actions: `wakeup` — run a prompt once after a delay; `cron` — run a prompt on a 5-field cron schedule; `monitor` — run a shell command every interval and notify when its output matches a regex; `list` — show scheduled items; `cancel` — remove one by id.",
889
+ inputSchema: {
890
+ type: "object",
891
+ properties: {
892
+ action: {
893
+ type: "string",
894
+ enum: ["wakeup", "cron", "monitor", "list", "cancel"],
895
+ description: "What to do",
896
+ },
897
+ prompt: {
898
+ type: "string",
899
+ description:
900
+ "For wakeup/cron: the agent prompt to run (via `cc agent -p`) when it fires",
901
+ },
902
+ delay: {
903
+ type: "string",
904
+ description:
905
+ "For wakeup: how long from now before it fires (e.g. 30s, 5m, 1h)",
906
+ },
907
+ cron: {
908
+ type: "string",
909
+ description:
910
+ 'For cron: a 5-field cron expression, e.g. "0 9 * * 1" (09:00 every Monday)',
911
+ },
912
+ command: {
913
+ type: "string",
914
+ description: "For monitor: the shell command to run each interval",
915
+ },
916
+ interval: {
917
+ type: "string",
918
+ description:
919
+ "For monitor: how often to run the command (e.g. 30s, 5m)",
920
+ },
921
+ stop_when: {
922
+ type: "string",
923
+ description:
924
+ "For monitor: a regex; when the command output matches, the monitor fires its notification and stops",
925
+ },
926
+ notify_title: {
927
+ type: "string",
928
+ description: "For monitor: notification title sent when it matches",
929
+ },
930
+ max_checks: {
931
+ type: "number",
932
+ description:
933
+ "For monitor: give up after this many checks (optional safety cap)",
934
+ },
935
+ label: {
936
+ type: "string",
937
+ description: "Optional human label for list/cancel",
938
+ },
939
+ id: {
940
+ type: "string",
941
+ description: "For cancel: the schedule entry id to remove",
942
+ },
943
+ },
944
+ required: ["action"],
945
+ },
946
+ ...TOOL_POLICY_METADATA.schedule,
947
+ permissions: {
948
+ level: "standard",
949
+ scopes: ["schedule:write"],
950
+ },
951
+ telemetry: {
952
+ category: "schedule",
953
+ tags: ["tool:schedule", "contract:coding-agent", "tier:extension"],
954
+ },
955
+ },
852
956
  ]);
853
957
 
854
958
  const CODING_AGENT_MVP_TOOL_NAMES = Object.freeze(
@@ -261,6 +261,34 @@ const TOOL_POLICY_METADATA = Object.freeze({
261
261
  approvalFlow: "auto",
262
262
  isReadOnly: true,
263
263
  },
264
+ // Sends an outbound notification to the user's own channels/device. No
265
+ // workspace mutation and no un-gated shell; blocked in plan mode (an
266
+ // external side effect) but otherwise auto — it targets the user, not a
267
+ // third party.
268
+ notify: {
269
+ riskLevel: RISK_LEVELS.LOW,
270
+ category: TOOL_CATEGORIES.WRITE,
271
+ availableInPlanMode: false,
272
+ planModeBehavior: "blocked",
273
+ requiresPlanApproval: false,
274
+ requiresConfirmation: false,
275
+ approvalFlow: "auto",
276
+ isReadOnly: false,
277
+ },
278
+ // Persists a wakeup/cron/monitor entry for `cc agenda run` to execute later.
279
+ // Writing the schedule is itself harmless (a JSONL row under the user's
280
+ // config dir); the eventual `cc agent`/shell run is gated when the agenda
281
+ // consumer executes it. Blocked in plan mode (schedules future side effects).
282
+ schedule: {
283
+ riskLevel: RISK_LEVELS.LOW,
284
+ category: TOOL_CATEGORIES.WRITE,
285
+ availableInPlanMode: false,
286
+ planModeBehavior: "blocked",
287
+ requiresPlanApproval: false,
288
+ requiresConfirmation: false,
289
+ approvalFlow: "auto",
290
+ isReadOnly: false,
291
+ },
264
292
  });
265
293
 
266
294
  function normalizeGitCommand(command) {
@@ -1 +0,0 @@
1
- import{I as v,P as u,J as S,U as s,R as n,S as y,K as C,Q as x,V as w,_ as k,b as a}from"./vendor-Bn1JzzAn.js";import{_ as B}from"./index-Ty4w18mR.js";import"./icons-DEmcnxBf.js";const N={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=a(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=a(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=a(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=a(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=a(()=>{if(!t.event.occurredAt)return"";try{const e=new Date(t.event.occurredAt),p=e.getFullYear(),f=String(e.getMonth()+1).padStart(2,"0"),g=String(e.getDate()).padStart(2,"0"),b=String(e.getHours()).padStart(2,"0"),h=String(e.getMinutes()).padStart(2,"0");return`${p}-${f}-${g} ${b}:${h}`}catch{return""}}),_={props:t,messageText:r,actorLabel:i,isMine:l,adapterColor:o,formattedTime:m,computed:a};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},T={class:"bubble"},L={class:"meta"},M={class:"actor"},R={class:"time"},V={class:"body"};function q(c,d,t,r,i,l){const o=v("a-tag");return u(),S("div",{class:k(["chat-row",{mine:r.isMine}])},[s("div",T,[s("div",L,[s("span",M,n(r.actorLabel),1),s("span",R,n(r.formattedTime),1)]),s("div",V,n(r.messageText),1),t.event.source.adapter?(u(),y(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(n(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const A=B(N,[["render",q],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-lLEaak/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{A as default};
@@ -1 +0,0 @@
1
- import{I as k,P as d,J as u,U as s,R as n,c as i,K as v,Q as _,V as g,b as a}from"./vendor-Bn1JzzAn.js";import{_ as w}from"./index-Ty4w18mR.js";import"./icons-DEmcnxBf.js";const S={__name:"OrderTableRenderer",props:{event:{type:Object,required:!0}},setup(p,{expose:r}){r();const o=p,e=a(()=>o.event.content||{}),l=a(()=>o.event.extra||{}),m=a(()=>l.value.merchant||e.value.merchant||e.value.counterparty||"—"),c=a(()=>e.value.title||e.value.name||e.value.itemName||e.value.text||"—"),y=a(()=>{const t=e.value.amount??e.value.price??e.value.total;return t==null?"—":`${e.value.currency||"¥"} ${typeof t=="number"?t.toFixed(2):t}`}),T=a(()=>l.value.orderNo||e.value.orderNo||e.value.orderId),f=a(()=>e.value.status||e.value.state),b=a(()=>{const t=(f.value||"").toLowerCase();return t.includes("成功")||t.includes("succe")||t.includes("paid")?"green":t.includes("退")||t.includes("refund")?"orange":t.includes("失败")||t.includes("fail")?"red":"default"}),h=a(()=>{if(!o.event.occurredAt)return"";const t=new Date(o.event.occurredAt);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}),x={props:o,c:e,e:l,merchantText:m,itemText:c,amountText:y,orderNo:T,statusText:f,statusColor:b,formattedTime:h,computed:a};return Object.defineProperty(x,"__isScriptSetup",{enumerable:!1,value:!0}),x}},N={class:"order-card"},C={class:"head"},O={class:"time"},V={class:"row"},R={class:"val"},B={class:"row"},D={class:"val"},I={class:"row amount-row"},j={class:"val amount"},A={key:0,class:"row"},E={class:"val mono"},F={key:1,class:"row"};function L(p,r,o,e,l,m){const c=k("a-tag");return d(),u("div",N,[s("div",C,[s("span",O,n(e.formattedTime),1),i(c,{color:"gold"},{default:v(()=>[_(n(o.event.source.adapter),1)]),_:1}),i(c,null,{default:v(()=>[_(n(o.event.subtype),1)]),_:1})]),s("div",V,[r[0]||(r[0]=s("span",{class:"key"},"商户",-1)),s("span",R,n(e.merchantText),1)]),s("div",B,[r[1]||(r[1]=s("span",{class:"key"},"商品/项目",-1)),s("span",D,n(e.itemText),1)]),s("div",I,[r[2]||(r[2]=s("span",{class:"key"},"金额",-1)),s("span",j,n(e.amountText),1)]),e.orderNo?(d(),u("div",A,[r[3]||(r[3]=s("span",{class:"key"},"单号",-1)),s("span",E,n(e.orderNo),1)])):g("v-if",!0),e.statusText?(d(),u("div",F,[r[4]||(r[4]=s("span",{class:"key"},"状态",-1)),i(c,{color:e.statusColor},{default:v(()=>[_(n(e.statusText),1)]),_:1},8,["color"])])):g("v-if",!0)])}const J=w(S,[["render",L],["__scopeId","data-v-5ed5524d"],["__file","/tmp/cc-web-panel-lLEaak/repo/packages/web-panel/src/components/pdh/renderers/OrderTableRenderer.vue"]]);export{J as default};