chainlesschain 0.162.118 → 0.162.120

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/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-D4dNL7oX.js → AIOps-MUE7jVfi.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DqMM3fea.js → ActionButton-DKkJNgJW.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DMep218S.js → Analytics-DcHt5MVA.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-TdTGCiOR.js → AppLayout-BjF0MsBB.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-1Dml711-.js → Audit-CybGKBUd.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-DbHx9UYj.js → Backup-CzZoTRnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-C2ahEcJR.js → BaseInput-CG8BgY54.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-5ZjuBfuS.js → Chat-S6AcW4T2.js} +5 -5
  10. package/src/assets/web-panel/assets/ChatBubbleRenderer-XpONY6wA.js +1 -0
  11. package/src/assets/web-panel/assets/{Checkbox-Dg6tGe59.js → Checkbox-DZ_LDoVZ.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-CNDPJTao.js → Codegen-DN2ZYd_4.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-DWU7gipF.js → Col-Cidm2Ykv.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-5nkmoyvL.js → Community-ByNGbzcY.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-BzCJj8eL.js → Compact-Dj9vY8yk.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-DbZq8BJH.js → Compliance-_0ipnnBf.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-BK7yKRsT.js → Cowork-BNdunLG9.js} +2 -2
  18. package/src/assets/web-panel/assets/{Cron-BSbTeh9k.js → Cron-BvzsO_i-.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-BIyLL_7v.js → Crosschain-BSR_odwN.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-DeLWtwx2.js → DID-AsJk_1HF.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-SGbCH8zO.js → Dashboard-tYbIuKgu.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-CmsCZDkh.js → Dropdown-CVuLEkIH.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-Tfc7sbeH.js → EmailListRenderer-C4DBbxZ8.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-K2YlYDx7.js → FamilyGuardDashboard-DNX_oWxL.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-kLpstbZZ.js → Federation-Cl5fg-2b.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-BBFI-PfE.js → FormItemContext-sMFqQO5g.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-D0xM21cK.js → GenericCardRenderer-qZpi2wH1.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-DoRk-Z87.js → Git-uO96e0En.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-DLpgG6NJ.js → Governance-CAkQyU1W.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-DhXCaVnC.js → Inference-kQgYGwuX.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-DY9bjNvM.js → KnowledgeGraph-B3r3qbm6.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-0hjq8gkO.js → Logs-BhnUcQP2.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-BiwZtXvR.js → Marketplace-cSrDXJRg.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-FQPVVxpt.js → McpTools-D7tn-iuQ.js} +3 -3
  35. package/src/assets/web-panel/assets/{Memory-DFx_G11g.js → Memory-YfMrETfK.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-CffhLXKL.js → MobileBridge-QYTJAlGR.js} +2 -2
  37. package/src/assets/web-panel/assets/MobileProjects-hulCHsOG.js +1 -0
  38. package/src/assets/web-panel/assets/{Mtc-CZYjK-51.js → Mtc-C6a2fTit.js} +5 -5
  39. package/src/assets/web-panel/assets/{MtcAudit-Da34fMPk.js → MtcAudit-tPoY6xsu.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-Bd_rBnNq.js → Multisig-VVdmiLTB.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-C5gqAWjv.js → NLProgramming-BuI8pzz1.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-Dhu_Cm2p.js → Notes-f_coT28Z.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-DtJcANAI.js → NotificationSettings-D8Beg8OP.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-BSZfBr8T.js → OrderTableRenderer-C9PxKWwg.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-BUr7Rir7.js → Organization-fUX97U1w.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-DWshgXbT.js → Overflow-vVjV0pGU.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-CyD_epxc.js → P2P-DGM6VCzC.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-5XCiifmp.js → PdhVaultBrowser-j01q6J9e.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-7f399Gvr.js → Permissions-Q7NYy0Wv.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-DxlSJUU3.js → PersonalDataHub-Bdp3MI1-.js} +4 -4
  51. package/src/assets/web-panel/assets/{Pipeline-DgEcnlAm.js → Pipeline-CB1xH835.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-zisFH3nX.js → Privacy-DIbp3aJd.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-CJoxhT5P.js → ProjectInit-DzEtaFH9.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-PiZfKRl5.js → ProjectSettings-CiciM4K4.js} +2 -2
  55. package/src/assets/web-panel/assets/Projects-C7KoEuf4.js +1 -0
  56. package/src/assets/web-panel/assets/{Providers-BNZjDnSc.js → Providers-CXgLwW2L.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-khmv9SgN.js → QuickAsk-nzHdN2F2.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-BDY0V36V.js → Recommend-BicIztEZ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-C4wPt5Hv.js → Reputation-C_Y8oRqf.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-B9kpAVZb.js → Row-CkNhTYCZ.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-CiyeJRzB.js → RssFeed-D_fjy-vQ.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-BAJIzXKP.js → Search-CCsIRDKU.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-_SyGiA39.js → Security-CHJPSsH6.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-CpCisy2A.js → Services-BQr5Adu-.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-BbgLYFnt.js → Skeleton-BQtvUIf2.js} +1 -1
  66. package/src/assets/web-panel/assets/Skills-Dc0LU3LK.js +1 -0
  67. package/src/assets/web-panel/assets/{Sla-BXoqLXMq.js → Sla-BO5j3PAQ.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-BY9Kooi0.js → SpeechSettings-BmPQTYAi.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-CcArvVNF.js → SyncSettings-BnobmeAo.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-DFFcr6Zm.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-C7uVsXry.js → Templates-RZh0Oh_Q.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-YTp4gRv1.js → Tenant-BD6D6Ak7.js} +1 -1
  73. package/src/assets/web-panel/assets/{Terminal-CVyqc079.js → Terminal-BSuShSOU.js} +2 -2
  74. package/src/assets/web-panel/assets/TimelineRenderer-DmwdA_BU.js +1 -0
  75. package/src/assets/web-panel/assets/{Tokens-CDsEqDT7.js → Tokens-CMgdZ-HW.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-CpDIhVvj.js → Trigger-Ckz3UHfh.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-CjEWMLXs.js → Trust-AKEeF68u.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-CMuYjFkp.js → UkeySign-y_PA8Ugs.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-L76OwoPT.js → VideoEditing-BDCHMoYT.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-CfhcIudB.js → Wallet-BUPNjLDa.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-BhxSf50j.js → WebAuthn-BSkgJ_ej.js} +4 -4
  82. package/src/assets/web-panel/assets/{WorkflowEditor-CkYQGytv.js → WorkflowEditor-Cly_vJCn.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-Bke-Axcb.js → chat-B2upy0kk.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-DDm7sxvR.js → colors-DRymaRcw.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-ptIaR2VC.js → compact-item-BjlECmvE.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-neR1onYf.js → createContext-NByPo135.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-BQpi8pDO.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-CdoIzexs.js → hasIn-CnapAb4N.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-9dyEaJ48.js → index-3N2bkUYM.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-BGAoMIiF.js → index-69yznrDs.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-Cg7TMjLf.js → index-B0IxW10q.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-B3RhcGp2.js → index-B1l9stj4.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-DpqA23qT.js → index-B7EkRJNQ.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-8RY-s8Eq.js → index-B8mHLG8W.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-rZfX7ufl.js → index-BC3lHdGe.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BsReT8kE.js → index-BCIn3-zn.js} +3 -3
  97. package/src/assets/web-panel/assets/{index-CBE4OYiN.js → index-BdsQCfwD.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CLhzHIgs.js → index-Bl67igbC.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-f59BFqsD.js → index-BlVSeRLX.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-KyM68byr.js → index-BnYbOEQ5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BN_GcJv-.js → index-BuMhmoLi.js} +1 -1
  102. package/src/assets/web-panel/assets/index-BvYGiwBG.js +1 -0
  103. package/src/assets/web-panel/assets/{index-DRA35MTY.js → index-C35ewkvS.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CMk4reDk.js → index-C4Je7eKb.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BEjcGiW_.js → index-C5QIx6d1.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B22DApaF.js → index-C8mpo9w0.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DxabeJjC.js → index-CBqC10Mz.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CC_4NPrV.js +1 -0
  109. package/src/assets/web-panel/assets/{index-DL-dAbq1.js → index-CQ6Td4oP.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DKJrSY7a.js → index-CmdbB6n1.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DCmaPYWj.js → index-CoZgzgDg.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Chu6dERk.js → index-DDOEPs_e.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Bt8YI0Pg.js → index-DQRbttWF.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-m7gmhBks.js → index-DSNzuCKY.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BSrWChEg.js → index-DUZ5OBUP.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-li06k0zQ.js → index-DaQVzr6e.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BnujNUf1.js → index-DdWH7Nnq.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BB8JlhPb.js → index-DfV7ozPn.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BYVMCbtn.js → index-DpVmeNyO.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-C4kWzHqC.js → index-DrJVa6Gk.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-5mAbzuWz.js → index-KbNiEQkd.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DUPpvFG3.js → index-MtPi9EHn.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-C83TTo0Y.js → index-aV-LQt0K.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D5oDZ8S7.js → index-iFODT6oN.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DpMZQawE.js → index-o8nqsumS.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Dl_I2P_E.js → index-qVEh-o74.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-0ZL7FjnB.js → index-sX1MbnSU.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-DoRyafUY.js → initDefaultProps-o1fFt3V7.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-CXAFczEQ.js → motion-Bwj9ZiqO.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-DNDMmkdZ.js → move-DoTSIAxU.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-D2wfCEns.js → omit-DkO-otLG.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-Dq7W_NtB.js → pickAttrs-7dqbsVWT.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-CkNHdTmz.js → placementArrow-WPFcCNIM.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-j6LiN9K2.js → responsiveObserve-DqQxE3aN.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-BKHHLvp8.js → slide-CyzizbNB.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-B3sdEvM3.js → statusUtils-C71vV6Kb.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-g4UCWzKN.js → styleChecker-DVrLfHrc.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-D_0KlvEp.js → useFlexGapSupport-DVNyuXrQ.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-ePxeifdP.js → useFs-BpBz_yQJ.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-4JoLBqJY.js → usePersonalDataHub-CYHp2Bn2.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-na-HJjyy.js → vnode-CXAL4PQ0.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-Wmkm0KcD.js → zoom-mrlkZmnn.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/doctor.js +15 -0
  145. package/src/commands/note.js +13 -10
  146. package/src/commands/update.js +20 -0
  147. package/src/lib/instinct-manager.js +8 -2
  148. package/src/lib/memory-manager.js +7 -3
  149. package/src/lib/sql-like.js +23 -0
  150. package/src/lib/update-notice.js +34 -10
  151. package/src/lib/version-skew.js +29 -0
  152. package/src/repl/agent-repl.js +23 -9
  153. package/src/runtime/__tests__/message-roles.test.js +142 -0
  154. package/src/runtime/diagnostics.js +23 -1
  155. package/src/runtime/headless-runner.js +8 -2
  156. package/src/runtime/headless-stream.js +34 -1
  157. package/src/runtime/message-roles.js +94 -0
  158. package/src/assets/web-panel/assets/ChatBubbleRenderer-B-1BKOW2.js +0 -1
  159. package/src/assets/web-panel/assets/MobileProjects-Ch6cai8d.js +0 -1
  160. package/src/assets/web-panel/assets/Projects-DsJd6uTW.js +0 -1
  161. package/src/assets/web-panel/assets/Skills-BetfsfpF.js +0 -1
  162. package/src/assets/web-panel/assets/Tasks-DqLoEIis.js +0 -1
  163. package/src/assets/web-panel/assets/TimelineRenderer-oJ9q5LkF.js +0 -1
  164. package/src/assets/web-panel/assets/devWarning-CQxKChUH.js +0 -1
  165. package/src/assets/web-panel/assets/index-DBA6F-Kp.js +0 -1
  166. package/src/assets/web-panel/assets/index-ffyvqxd5.js +0 -1
@@ -0,0 +1,142 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ mergeConsecutiveMessages,
4
+ _internal,
5
+ } from "../message-roles.js";
6
+
7
+ describe("mergeConsecutiveMessages", () => {
8
+ it("is a no-op on a healthy alternating transcript", () => {
9
+ const msgs = [
10
+ { role: "system", content: "sys" },
11
+ { role: "user", content: "a" },
12
+ { role: "assistant", content: "b" },
13
+ { role: "user", content: "c" },
14
+ ];
15
+ expect(mergeConsecutiveMessages(msgs)).toEqual(msgs);
16
+ });
17
+
18
+ it("merges two consecutive user turns (the --resume no-response bug)", () => {
19
+ // history ended with a bare `user` (prior run produced no assistant
20
+ // response); a new user prompt was spliced after it.
21
+ const out = mergeConsecutiveMessages([
22
+ { role: "system", content: "sys" },
23
+ { role: "user", content: "original task" },
24
+ { role: "user", content: "continue please" },
25
+ ]);
26
+ expect(out).toEqual([
27
+ { role: "system", content: "sys" },
28
+ { role: "user", content: "original task\n\ncontinue please" },
29
+ ]);
30
+ });
31
+
32
+ it("merges three-plus consecutive same-role turns", () => {
33
+ const out = mergeConsecutiveMessages([
34
+ { role: "user", content: "one" },
35
+ { role: "user", content: "two" },
36
+ { role: "user", content: "three" },
37
+ ]);
38
+ expect(out).toEqual([{ role: "user", content: "one\n\ntwo\n\nthree" }]);
39
+ });
40
+
41
+ it("merges consecutive assistant turns defensively", () => {
42
+ const out = mergeConsecutiveMessages([
43
+ { role: "assistant", content: "x" },
44
+ { role: "assistant", content: "y" },
45
+ ]);
46
+ expect(out).toEqual([{ role: "assistant", content: "x\n\ny" }]);
47
+ });
48
+
49
+ it("never merges system messages (leading base + context pair kept distinct)", () => {
50
+ const msgs = [
51
+ { role: "system", content: "base" },
52
+ { role: "system", content: "session-context" },
53
+ { role: "user", content: "hi" },
54
+ ];
55
+ expect(mergeConsecutiveMessages(msgs)).toEqual(msgs);
56
+ });
57
+
58
+ it("preserves the user turn after a healthy assistant tail", () => {
59
+ const out = mergeConsecutiveMessages([
60
+ { role: "assistant", content: "done" },
61
+ { role: "user", content: "next" },
62
+ ]);
63
+ expect(out).toEqual([
64
+ { role: "assistant", content: "done" },
65
+ { role: "user", content: "next" },
66
+ ]);
67
+ });
68
+
69
+ it("combines multimodal content arrays when merging user turns", () => {
70
+ const out = mergeConsecutiveMessages([
71
+ {
72
+ role: "user",
73
+ content: [
74
+ { type: "text", text: "look" },
75
+ { type: "image", source: "x" },
76
+ ],
77
+ },
78
+ { role: "user", content: "and describe" },
79
+ ]);
80
+ expect(out).toHaveLength(1);
81
+ expect(out[0].role).toBe("user");
82
+ expect(out[0].content).toEqual([
83
+ { type: "text", text: "look" },
84
+ { type: "image", source: "x" },
85
+ { type: "text", text: "and describe" },
86
+ ]);
87
+ });
88
+
89
+ it("treats an empty-string content as nothing when merging", () => {
90
+ const out = mergeConsecutiveMessages([
91
+ { role: "user", content: "" },
92
+ { role: "user", content: "real" },
93
+ ]);
94
+ expect(out).toEqual([{ role: "user", content: "real" }]);
95
+ });
96
+
97
+ it("does not mutate the input array or its messages", () => {
98
+ const input = [
99
+ { role: "user", content: "a" },
100
+ { role: "user", content: "b" },
101
+ ];
102
+ const snapshot = JSON.parse(JSON.stringify(input));
103
+ mergeConsecutiveMessages(input);
104
+ expect(input).toEqual(snapshot);
105
+ });
106
+
107
+ it("passes through falsy / role-less entries verbatim without crashing", () => {
108
+ const out = mergeConsecutiveMessages([
109
+ null,
110
+ { content: "no role" },
111
+ { role: "user", content: "a" },
112
+ { role: "user", content: "b" },
113
+ ]);
114
+ expect(out).toEqual([
115
+ null,
116
+ { content: "no role" },
117
+ { role: "user", content: "a\n\nb" },
118
+ ]);
119
+ });
120
+
121
+ it("returns the argument unchanged when not an array", () => {
122
+ expect(mergeConsecutiveMessages(null)).toBe(null);
123
+ expect(mergeConsecutiveMessages(undefined)).toBe(undefined);
124
+ });
125
+
126
+ describe("_internal.joinContent", () => {
127
+ const { joinContent } = _internal;
128
+ it("joins two strings with a blank line", () => {
129
+ expect(joinContent("a", "b")).toBe("a\n\nb");
130
+ });
131
+ it("returns the non-empty side when one string is empty", () => {
132
+ expect(joinContent("", "b")).toBe("b");
133
+ expect(joinContent("a", "")).toBe("a");
134
+ });
135
+ it("promotes a string to a text block when joining with an array", () => {
136
+ expect(joinContent("hi", [{ type: "image", source: "x" }])).toEqual([
137
+ { type: "text", text: "hi" },
138
+ { type: "image", source: "x" },
139
+ ]);
140
+ });
141
+ });
142
+ });
@@ -13,7 +13,8 @@
13
13
  */
14
14
 
15
15
  import { execSync } from "node:child_process";
16
- import { existsSync, readdirSync } from "node:fs";
16
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
17
+ import { join as pathJoin } from "node:path";
17
18
  import { createRequire } from "node:module";
18
19
  import { createConnection } from "node:net";
19
20
  import semver from "semver";
@@ -28,6 +29,17 @@ import {
28
29
  } from "../lib/service-manager.js";
29
30
  import { loadConfig } from "../lib/config-manager.js";
30
31
  import { isAppRunning, getAppPid } from "../lib/process-manager.js";
32
+ import { readDiskVersion, versionDiagnosis } from "../lib/version-skew.js";
33
+
34
+ /** Best-effort read of the npm `latest` cached by the startup update notice. */
35
+ function readCachedLatest() {
36
+ try {
37
+ const p = pathJoin(getHomeDir() || "", "update-check.json");
38
+ return JSON.parse(readFileSync(p, "utf-8"))?.latest || null;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
31
43
 
32
44
  /**
33
45
  * Probe a TCP port. Resolves true if something is listening.
@@ -250,9 +262,19 @@ export async function collectDoctorReport() {
250
262
  const failed = checks.filter((c) => !c.ok);
251
263
  const criticalFailed = failed.filter((c) => !c.optional);
252
264
 
265
+ // Three-way version check: running (this process) vs installed (on disk) vs
266
+ // latest (npm, from the update-notice cache). Tells the user whether they need
267
+ // `npm i -g` (a new release) or just a restart (already updated on disk).
268
+ const versionCheck = versionDiagnosis({
269
+ running: VERSION,
270
+ installed: readDiskVersion(),
271
+ latest: readCachedLatest(),
272
+ });
273
+
253
274
  return {
254
275
  schema: "chainlesschain.doctor.v1",
255
276
  version: VERSION,
277
+ versionCheck,
256
278
  generatedAt: new Date().toISOString(),
257
279
  checks,
258
280
  ports,
@@ -46,6 +46,7 @@ import {
46
46
  import { expandFileRefsAsync } from "./file-ref-expander.js";
47
47
  import { composeSystemPrompt } from "./system-prompt.js";
48
48
  import { buildUserContent } from "../lib/image-input.js";
49
+ import { mergeConsecutiveMessages } from "./message-roles.js";
49
50
  import { isHeadlessConfigCommand } from "../lib/headless-config-command.js";
50
51
  import { withQuietStdout } from "./quiet-stdout.js";
51
52
  import { CostBudget } from "../lib/cost-budget.js";
@@ -610,14 +611,19 @@ export async function runAgentHeadless(options = {}, deps = {}) {
610
611
  // content array (agent-core converts it per-provider for ollama/anthropic).
611
612
  const userMessageContent = buildUserContent(userContent, options.images);
612
613
 
613
- const messages = [
614
+ // Merge consecutive same-role turns so a resumed session whose previous run
615
+ // produced NO assistant response (history ends with a bare `user` turn) does
616
+ // not yield two adjacent `user` messages — which Anthropic/Bedrock reject as
617
+ // "roles must alternate", failing the resume (Claude Code 2.1.187 parity).
618
+ // No-op on a healthy alternating transcript.
619
+ const messages = mergeConsecutiveMessages([
614
620
  { role: "system", content: systemContent },
615
621
  ...(sessionStartContext
616
622
  ? [{ role: "system", content: sessionStartContext }]
617
623
  : []),
618
624
  ...history,
619
625
  { role: "user", content: userMessageContent },
620
- ];
626
+ ]);
621
627
 
622
628
  // Persist the user turn up front (best-effort) so a session is recoverable
623
629
  // even if the run crashes mid-loop. startSession is append-safe: only seed
@@ -19,6 +19,7 @@
19
19
  import { bootstrap } from "./bootstrap.js";
20
20
  import { buildSystemPrompt, agentLoop as coreAgentLoop } from "./agent-core.js";
21
21
  import { composeSystemPrompt } from "./system-prompt.js";
22
+ import { mergeConsecutiveMessages } from "./message-roles.js";
22
23
  import { expandFileRefsAsync } from "./file-ref-expander.js";
23
24
  import { detectImagePaths } from "../lib/image-input.js";
24
25
  import { detectVersionSkew, versionSkewMessage } from "../lib/version-skew.js";
@@ -259,7 +260,22 @@ async function runTurn(messages, loopOptions, { runLoop, emit, costBudget }) {
259
260
  let endReason = "complete";
260
261
  let stopForCost = false;
261
262
 
262
- for await (const event of runLoop(messages, loopOptions)) {
263
+ // Merge consecutive same-role turns before the model call ONLY when the
264
+ // caller flags a resume-degenerate transcript (`mergeRoles`): a resumed
265
+ // session whose previous run produced NO assistant response leaves a trailing
266
+ // bare `user` turn, so splicing the first live prompt after it sends two
267
+ // adjacent `user` messages — which Anthropic/Bedrock reject as "roles must
268
+ // alternate" (Claude Code 2.1.187 parity). It is GATED rather than applied
269
+ // every turn because the live turn loop legitimately produces consecutive
270
+ // `user` messages — an interrupted turn's dangling prompt, a PDH feedback
271
+ // note (§3.5.13) — that must reach the model distinctly and must not be
272
+ // folded (folding the interrupt-dangling turn even resurrects the abandoned
273
+ // request). Non-mutating: the persistent `messages` array is untouched; only
274
+ // the provider payload is sanitized.
275
+ const modelMessages = loopOptions.mergeRoles
276
+ ? mergeConsecutiveMessages(messages)
277
+ : messages;
278
+ for await (const event of runLoop(modelMessages, loopOptions)) {
263
279
  switch (event.type) {
264
280
  case "tool-executing":
265
281
  toolCalls.push({ tool: event.tool, args: event.args });
@@ -642,6 +658,15 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
642
658
  }
643
659
  }
644
660
 
661
+ // Resume-degenerate role sanitation (Claude Code 2.1.187 parity): when the
662
+ // replayed history ends with a bare `user` turn (the prior run produced no
663
+ // assistant response), the FIRST live prompt would make two adjacent `user`
664
+ // messages. Arm a one-shot flag consumed by the first model call so the merge
665
+ // fires exactly once — the live turn loop's intentional consecutive-`user`
666
+ // states (interrupt-dangling turn, PDH feedback note) are never folded.
667
+ let sanitizeRolesNextTurn =
668
+ resumedMessages > 0 && messages[messages.length - 1]?.role === "user";
669
+
645
670
  emit({
646
671
  type: "system",
647
672
  subtype: "init",
@@ -1294,6 +1319,12 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1294
1319
  ? AbortSignal.any([options.signal, currentAbort.signal])
1295
1320
  : currentAbort.signal;
1296
1321
 
1322
+ // Consume the one-shot resume-degeneracy flag for THIS turn (see
1323
+ // sanitizeRolesNextTurn) so the role merge fires exactly once, whether the
1324
+ // model call completes or is interrupted.
1325
+ const mergeRolesThisTurn = sanitizeRolesNextTurn;
1326
+ sanitizeRolesNextTurn = false;
1327
+
1297
1328
  let outcome;
1298
1329
  try {
1299
1330
  outcome = await runTurn(
@@ -1339,6 +1370,8 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
1339
1370
  : {}),
1340
1371
  iterationBudget: budget,
1341
1372
  signal: turnSignal,
1373
+ // Resume-degenerate role merge for the first live model call only.
1374
+ mergeRoles: mergeRolesThisTurn,
1342
1375
  },
1343
1376
  { runLoop, emit, costBudget },
1344
1377
  );
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Conversation role sanitation shared by the headless runner and the
3
+ * stream-json runtime.
4
+ *
5
+ * Providers that strictly enforce alternating roles — Anthropic, Bedrock, and
6
+ * some OpenAI-compatible gateways — reject a payload with two consecutive
7
+ * messages of the same non-system role ("messages: roles must alternate").
8
+ *
9
+ * A degenerate transcript reaches that state on `--resume` when the ORIGINAL
10
+ * run produced NO assistant response (the model errored, the turn was
11
+ * interrupted, or the provider was down): the persisted JSONL ends with a bare
12
+ * `user` turn. Splicing the new resume prompt after it yields
13
+ * `[…, {role:"user"}, {role:"user"}]` → the provider 400s and resume fails.
14
+ *
15
+ * `mergeConsecutiveMessages` folds adjacent same-role (non-system) turns into a
16
+ * single message so the transcript always alternates, regardless of how it
17
+ * degenerated. This mirrors Claude Code 2.1.187 ("Fixed --resume failing when
18
+ * original run produced no model responses"). It is a no-op on a well-formed
19
+ * alternating transcript, so healthy sessions are byte-for-byte unchanged.
20
+ *
21
+ * @module runtime/message-roles
22
+ */
23
+
24
+ /**
25
+ * Normalize a message `content` field to an array of content blocks. A plain
26
+ * string becomes a single `text` block; an empty string contributes nothing;
27
+ * an existing array is returned as-is; any other object is wrapped as a single
28
+ * opaque block so unknown shapes survive a merge.
29
+ * @param {*} content
30
+ * @returns {Array}
31
+ */
32
+ function toBlocks(content) {
33
+ if (Array.isArray(content)) return content;
34
+ if (content == null) return [];
35
+ if (typeof content === "string") {
36
+ return content === "" ? [] : [{ type: "text", text: content }];
37
+ }
38
+ return [content];
39
+ }
40
+
41
+ /**
42
+ * Join two message `content` values. When both are plain strings the result
43
+ * stays a string (joined by a blank line) — the overwhelmingly common case, so
44
+ * a text-only resume keeps a string payload. When either side is a multimodal
45
+ * content array, both are normalized to block arrays and concatenated.
46
+ * @param {*} a
47
+ * @param {*} b
48
+ * @returns {string|Array}
49
+ */
50
+ function joinContent(a, b) {
51
+ if (typeof a === "string" && typeof b === "string") {
52
+ if (a === "") return b;
53
+ if (b === "") return a;
54
+ return `${a}\n\n${b}`;
55
+ }
56
+ return [...toBlocks(a), ...toBlocks(b)];
57
+ }
58
+
59
+ /**
60
+ * Merge consecutive same-role, non-system messages so the conversation
61
+ * alternates roles for the provider. System messages are passed through
62
+ * untouched and never participate in a merge (a leading base + session-context
63
+ * system pair stays distinct). Falsy / role-less entries are passed through
64
+ * verbatim rather than dropped.
65
+ *
66
+ * Returns a NEW array; the input is not mutated.
67
+ *
68
+ * @param {Array<object>} messages
69
+ * @returns {Array<object>}
70
+ */
71
+ export function mergeConsecutiveMessages(messages) {
72
+ if (!Array.isArray(messages)) return messages;
73
+ const out = [];
74
+ for (const msg of messages) {
75
+ const prev = out[out.length - 1];
76
+ if (
77
+ prev &&
78
+ msg &&
79
+ typeof msg.role === "string" &&
80
+ msg.role !== "system" &&
81
+ prev.role === msg.role
82
+ ) {
83
+ out[out.length - 1] = {
84
+ ...prev,
85
+ content: joinContent(prev.content, msg.content),
86
+ };
87
+ } else {
88
+ out.push(msg);
89
+ }
90
+ }
91
+ return out;
92
+ }
93
+
94
+ export const _internal = { toBlocks, joinContent };
@@ -1 +0,0 @@
1
- import{I as v,P as u,J as y,U as n,R as a,S,K as C,Q as x,V as w,_ as B,b as s}from"./vendor-BvqAck49.js";import{_ as k}from"./index-BsReT8kE.js";import"./icons-DP3uiYxy.js";const N={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=s(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=s(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=s(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=s(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=s(()=>{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:s};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},R={class:"bubble"},T={class:"meta"},M={class:"actor"},V={class:"time"},q={class:"body"};function D(c,d,t,r,i,l){const o=v("a-tag");return u(),y("div",{class:B(["chat-row",{mine:r.isMine}])},[n("div",R,[n("div",T,[n("span",M,a(r.actorLabel),1),n("span",V,a(r.formattedTime),1)]),n("div",q,a(r.messageText),1),t.event.source.adapter?(u(),S(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(a(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const A=k(N,[["render",D],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-R5yrKU/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{A as default};
@@ -1 +0,0 @@
1
- import{I as n,J as g,c as l,K as r,N as u,P as h,U as o,R as t,Q as b}from"./vendor-BvqAck49.js";import{_ as v,b as m}from"./index-BsReT8kE.js";import{a7 as y,M}from"./icons-DP3uiYxy.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return M},get FolderOutlined(){return y}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",k,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",w,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),b(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),b(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const N=v(B,[["render",T],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-R5yrKU/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};
@@ -1 +0,0 @@
1
- import{I as i,J as A,U as I,R as s,Q as r,c as t,K as a,V as _,S as x,o as oe,b as ee,r as u,P as p,F as ne,a2 as ge}from"./vendor-BvqAck49.js";import{_ as we,b as re,u as ie,d}from"./index-BsReT8kE.js";import{u as de}from"./useShellMode-CgR0wCYM.js";import{aM as ke,aN as Fe,aO as be,f as je,a4 as Ce,a7 as xe,as as Oe,R as Se}from"./icons-DP3uiYxy.js";const Pe={__name:"Projects",setup(se,{expose:l}){l();const{t:te}=re(),e=ie(),{isEmbedded:W}=de();async function w(o,f,ye,ae=8e3){if(W){const Z=await e.sendRaw({...f,type:o},ae);if(!Z?.ok){const $=Z?.error;throw new Error(typeof $=="string"?$:$?.message||`${o} failed`)}return Z.result}return e.executeJson(ye,ae)}const B=u(!1),y=u([]),O=u(""),S=u(""),P=u(!1),v=u(null),h=u([]),k=u(!1),E=u(!1),L=u(!1),F=u({name:"",description:"",type:"document",rootPath:""}),z=[{title:"ID",key:"id",width:110},{title:"名称",key:"name"},{title:"类型",key:"project_type",width:120},{title:"状态",key:"status",width:100},{title:"同步",key:"sync_status",width:100},{title:"更新",key:"updated_at",width:160},{title:"操作",key:"actions",width:180,fixed:"right"}],M=ee(()=>{const o={active:0,draft:0,completed:0,archived:0};for(const f of y.value)o[f.status]!==void 0&&(o[f.status]+=1);return o}),J=ee(()=>y.value.filter(o=>!(O.value&&o.status!==O.value||S.value&&!o.name.toLowerCase().includes(S.value.toLowerCase()))));function g(o){switch(o){case"active":return"green";case"draft":return"default";case"completed":return"cyan";case"archived":return"gold";default:return"default"}}function K(o){switch(o){case"synced":return"green";case"pending":return"orange";case"conflict":return"red";case"error":return"red";default:return"default"}}function Q(o){return!o&&o!==0?"-":new Date(typeof o=="number"?o:parseInt(o,10)).toLocaleString("zh-CN",{hour12:!1})}async function C(){B.value=!0;try{const o=await w("project.list",{limit:500},"project list --limit 500 --json",1e4);y.value=Array.isArray(o?.projects)?o.projects:Array.isArray(o)?o:[]}catch(o){d.error("加载失败: "+(o.message||o)),y.value=[]}finally{B.value=!1}}function G(o){return{onClick:()=>V(o)}}async function V(o){v.value=o,P.value=!0,k.value=!0,h.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);h.value=Array.isArray(f?.files)?f.files:[]}catch{h.value=[]}finally{k.value=!1}}async function H(o){try{(await w("project.delete",{id:o.id},`project delete ${o.id} --json`,8e3))?.ok?(d.success(`已删除项目 '${o.name}'`),P.value=!1,await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}function X(){F.value={name:"",description:"",type:"document",rootPath:""},E.value=!0}async function T(){if(!F.value.name.trim()){d.warning("请输入项目名称");return}L.value=!0;try{const o=await w("project.init",{name:F.value.name.trim(),description:F.value.description||null,projectType:F.value.type,rootPath:F.value.rootPath||null},`project init "${F.value.name.trim()}" --type ${F.value.type} --json`,8e3);o?.id?(d.success(`已创建项目 '${o.name}'`),E.value=!1,await C()):d.error("创建失败")}catch(o){d.error(o.message||String(o))}finally{L.value=!1}}const b=u(!1),D=u(!1),j=u({path:"",content:""}),U=u(!1),m=u(!1),R=u({path:""}),n=u(!1),c=u(null),q=u(""),Y=u(!1);function ue(){j.value={path:"",content:""},b.value=!0}function ce(){R.value={path:""},U.value=!0}async function N(){if(v.value){k.value=!0;try{const o=await w("project.listFiles",{projectId:v.value.id,limit:200},`project list-files ${v.value.id} --json`,8e3);h.value=Array.isArray(o?.files)?o.files:[]}catch(o){d.error("刷新文件失败: "+(o.message||o))}finally{k.value=!1}}}async function fe(){if(!j.value.path.trim()){d.warning("请输入文件路径");return}if(v.value){D.value=!0;try{const o=await w("project.createFile",{projectId:v.value.id,filePath:j.value.path.trim(),content:j.value.content||""},`project create-file ${v.value.id} "${j.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件 '${o.file_name}'`),b.value=!1,await N(),await C()):d.error("创建文件失败")}catch(o){d.error(o.message||String(o))}finally{D.value=!1}}}async function pe(){if(!R.value.path.trim()){d.warning("请输入文件夹路径");return}if(v.value){m.value=!0;try{const o=await w("project.createFolder",{projectId:v.value.id,folderPath:R.value.path.trim()},`project create-folder ${v.value.id} "${R.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件夹 '${o.file_name}'`),U.value=!1,await N(),await C()):d.error("创建文件夹失败")}catch(o){d.error(o.message||String(o))}finally{m.value=!1}}}async function ve(o){try{(await w("project.deleteFile",{fileId:o.id},`project delete-file ${o.id} --json`,8e3))?.deleted?(d.success(`已删除 '${o.file_name}'`),await N(),await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}async function me(o){if(o.is_folder){d.info("文件夹无内容可编辑");return}try{const f=await w("project.getFile",{fileId:o.id},`project get-file ${o.id} --json`,8e3);c.value=o,q.value=f?.content||"",n.value=!0}catch(f){d.error("读取文件失败: "+(f.message||f))}}async function _e(){if(c.value){Y.value=!0;try{(await w("project.writeFile",{fileId:c.value.id,content:q.value},`project write-file ${c.value.id} --json`,8e3))?.id?(d.success("已保存"),n.value=!1,await N()):d.error("保存失败")}catch(o){d.error(o.message||String(o))}finally{Y.value=!1}}}oe(()=>{C()});const le={t:te,ws:e,isEmbedded:W,callProjectTopic:w,loading:B,projects:y,statusFilter:O,nameFilter:S,detailOpen:P,detail:v,files:h,filesLoading:k,createOpen:E,creating:L,newProject:F,columns:z,countByStatus:M,filteredProjects:J,statusColor:g,syncColor:K,formatTime:Q,loadAll:C,onRowClick:G,openDetail:V,onDelete:H,onShowCreate:X,onCreate:T,createFileOpen:b,creatingFile:D,newFile:j,createFolderOpen:U,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:N,onCreateFile:fe,onCreateFolder:pe,onDeleteFile:ve,openEditFile:me,onSaveFile:_e,ref:u,computed:ee,onMounted:oe,get ReloadOutlined(){return Se},get PlusOutlined(){return Oe},get FolderOutlined(){return xe},get FileTextOutlined(){return Ce},get CheckCircleOutlined(){return je},get CheckSquareOutlined(){return be},get FileAddOutlined(){return Fe},get FolderAddOutlined(){return ke},get message(){return d},get useI18n(){return re},get useWsStore(){return ie},get useShellMode(){return de}};return Object.defineProperty(le,"__isScriptSetup",{enumerable:!1,value:!0}),le}},ze={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},Ue={class:"page-title"},Ae={class:"page-sub"},Ie={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},he={key:0,style:{"font-size":"12px",color:"#888"}},De={key:0,style:{color:"#888","font-size":"12px"}},Re={key:0},Te={key:1,style:{color:"#888"}},Be=["onClick"],Ee={key:0,style:{color:"#888","font-size":"12px"}};function Le(se,l,te,e,W,w){const B=i("router-link"),y=i("a-button"),O=i("a-space"),S=i("a-statistic"),P=i("a-card"),v=i("a-col"),h=i("a-row"),k=i("a-radio-button"),E=i("a-radio-group"),L=i("a-input-search"),F=i("a-alert"),z=i("a-tag"),M=i("a-popconfirm"),J=i("a-table"),g=i("a-descriptions-item"),K=i("a-descriptions"),Q=i("a-divider"),C=i("a-empty"),G=i("a-list-item"),V=i("a-list"),H=i("a-spin"),X=i("a-drawer"),T=i("a-input"),b=i("a-form-item"),D=i("a-textarea"),j=i("a-form"),U=i("a-modal"),m=i("a-select-option"),R=i("a-select");return p(),A("div",null,[I("div",ze,[I("div",null,[I("h2",Ue,s(e.t("projects.title")),1),I("p",Ae,[l[17]||(l[17]=r("桌面 / CLI / 手机 三端共享同一份项目数据,Phase 3d sync 自动同步 (",-1)),t(B,{to:"/project-init"},{default:a(()=>[...l[16]||(l[16]=[r("项目初始化 / 环境设置",-1)])]),_:1}),l[18]||(l[18]=r(")",-1))])]),t(O,null,{default:a(()=>[t(y,{loading:e.loading,onClick:e.loadAll},{icon:a(()=>[t(e.ReloadOutlined)]),default:a(()=>[l[19]||(l[19]=r(" 刷新 ",-1))]),_:1},8,["loading"]),t(y,{type:"primary",onClick:e.onShowCreate},{icon:a(()=>[t(e.PlusOutlined)]),default:a(()=>[l[20]||(l[20]=r(" 新建项目 ",-1))]),_:1})]),_:1})]),_(" Stats "),t(h,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:a(()=>[t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"总项目",value:e.projects.length,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:a(()=>[t(e.FolderOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"活跃",value:e.countByStatus.active,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckCircleOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"草稿",value:e.countByStatus.draft,"value-style":{color:"#8c8c8c",fontSize:"20px"}},{prefix:a(()=>[t(e.FileTextOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"已完成",value:e.countByStatus.completed,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckSquareOutlined)]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),_(" Filter "),I("div",Ie,[t(E,{value:e.statusFilter,"onUpdate:value":l[0]||(l[0]=n=>e.statusFilter=n),size:"small","button-style":"solid"},{default:a(()=>[t(k,{value:""},{default:a(()=>[...l[21]||(l[21]=[r("全部",-1)])]),_:1}),t(k,{value:"active"},{default:a(()=>[...l[22]||(l[22]=[r("活跃",-1)])]),_:1}),t(k,{value:"draft"},{default:a(()=>[...l[23]||(l[23]=[r("草稿",-1)])]),_:1}),t(k,{value:"completed"},{default:a(()=>[...l[24]||(l[24]=[r("已完成",-1)])]),_:1}),t(k,{value:"archived"},{default:a(()=>[...l[25]||(l[25]=[r("已归档",-1)])]),_:1})]),_:1},8,["value"]),t(L,{value:e.nameFilter,"onUpdate:value":l[1]||(l[1]=n=>e.nameFilter=n),placeholder:"按名称过滤",style:{"max-width":"260px"},"allow-clear":""},null,8,["value"])]),!e.projects.length&&!e.loading?(p(),x(F,{key:0,type:"info",message:"还没有项目",description:'运行 `cc project init <name>` 或点击右上角"新建项目"按钮创建。桌面 / CLI / 手机三端共享同一份数据。',"show-icon":"",style:{"margin-bottom":"16px"}})):_("v-if",!0),e.projects.length||e.loading?(p(),x(J,{key:1,columns:e.columns,"data-source":e.filteredProjects,loading:e.loading,pagination:{pageSize:20,showSizeChanger:!0},"row-key":"id","custom-row":e.onRowClick},{bodyCell:a(({column:n,record:c})=>[n.key==="id"?(p(),A("code",he,s(c.id.slice(0,8))+"…",1)):n.key==="name"?(p(),A(ne,{key:1},[I("strong",null,s(c.name),1),c.description?(p(),A("div",De,s(c.description),1)):_("v-if",!0)],64)):n.key==="project_type"?(p(),x(z,{key:2},{default:a(()=>[r(s(c.project_type),1)]),_:2},1024)):n.key==="status"?(p(),x(z,{key:3,color:e.statusColor(c.status)},{default:a(()=>[r(s(c.status),1)]),_:2},1032,["color"])):n.key==="sync_status"?(p(),x(z,{key:4,color:e.syncColor(c.sync_status)},{default:a(()=>[r(s(c.sync_status||"unknown"),1)]),_:2},1032,["color"])):n.key==="updated_at"?(p(),A(ne,{key:5},[r(s(e.formatTime(c.updated_at)),1)],64)):n.key==="actions"?(p(),x(O,{key:6,onClick:l[2]||(l[2]=ge(()=>{},["stop"]))},{default:a(()=>[t(y,{size:"small",onClick:q=>e.openDetail(c)},{default:a(()=>[...l[26]||(l[26]=[r("详情",-1)])]),_:1},8,["onClick"]),t(M,{title:`删除项目 '${c.name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:q=>e.onDelete(c)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[27]||(l[27]=[r("删除",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)):_("v-if",!0)]),_:1},8,["data-source","loading"])):_("v-if",!0),_(" Detail drawer "),t(X,{open:e.detailOpen,"onUpdate:open":l[3]||(l[3]=n=>e.detailOpen=n),title:e.detail?.name||"项目详情",width:"640",placement:"right"},{default:a(()=>[e.detail?(p(),x(K,{key:0,column:1,bordered:"",size:"small"},{default:a(()=>[t(g,{label:"ID"},{default:a(()=>[I("code",null,s(e.detail.id),1)]),_:1}),t(g,{label:"名称"},{default:a(()=>[r(s(e.detail.name),1)]),_:1}),t(g,{label:"描述"},{default:a(()=>[r(s(e.detail.description||"-"),1)]),_:1}),t(g,{label:"类型"},{default:a(()=>[t(z,null,{default:a(()=>[r(s(e.detail.project_type),1)]),_:1})]),_:1}),t(g,{label:"状态"},{default:a(()=>[t(z,{color:e.statusColor(e.detail.status)},{default:a(()=>[r(s(e.detail.status),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"同步状态"},{default:a(()=>[t(z,{color:e.syncColor(e.detail.sync_status)},{default:a(()=>[r(s(e.detail.sync_status||"unknown"),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"用户"},{default:a(()=>[r(s(e.detail.user_id),1)]),_:1}),t(g,{label:"根路径"},{default:a(()=>[e.detail.root_path?(p(),A("code",Re,s(e.detail.root_path),1)):(p(),A("span",Te,"(无)"))]),_:1}),t(g,{label:"文件数"},{default:a(()=>[r(s(e.detail.file_count||0),1)]),_:1}),t(g,{label:"创建"},{default:a(()=>[r(s(e.formatTime(e.detail.created_at)),1)]),_:1}),t(g,{label:"更新"},{default:a(()=>[r(s(e.formatTime(e.detail.updated_at)),1)]),_:1})]),_:1})):_("v-if",!0),t(Q,null,{default:a(()=>[...l[28]||(l[28]=[r("文件",-1)])]),_:1}),_(" Sub-phase 7.3 (2026-05-17): 文件 CRUD toolbar "),t(O,{style:{"margin-bottom":"12px"}},{default:a(()=>[t(y,{size:"small",type:"primary",disabled:!e.detail,onClick:e.openCreateFile},{default:a(()=>[t(e.FileAddOutlined),l[29]||(l[29]=r(" 新建文件 ",-1))]),_:1},8,["disabled"]),t(y,{size:"small",disabled:!e.detail,onClick:e.openCreateFolder},{default:a(()=>[t(e.FolderAddOutlined),l[30]||(l[30]=r(" 新建文件夹 ",-1))]),_:1},8,["disabled"])]),_:1}),t(H,{spinning:e.filesLoading},{default:a(()=>[!e.files.length&&!e.filesLoading?(p(),x(C,{key:0,description:"无文件 (点上方按钮新建)"})):(p(),x(V,{key:1,size:"small","data-source":e.files},{renderItem:a(({item:n})=>[t(G,null,{extra:a(()=>[t(O,null,{default:a(()=>[n.file_size?(p(),A("span",Ee,s(n.file_size)+" B",1)):_("v-if",!0),t(M,{title:`删除 ${n.is_folder?"文件夹":"文件"} '${n.file_name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:c=>e.onDeleteFile(n)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[31]||(l[31]=[r("×",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)]),default:a(()=>[I("span",{style:{cursor:"pointer"},onClick:c=>e.openEditFile(n)},s(n.is_folder?"📁":"📄")+" "+s(n.file_path),9,Be)]),_:2},1024)]),_:1},8,["data-source"]))]),_:1},8,["spinning"])]),_:1},8,["open","title"]),_(" Sub-phase 7.3: Create file modal "),t(U,{open:e.createFileOpen,"onUpdate:open":l[6]||(l[6]=n=>e.createFileOpen=n),title:"新建文件","confirm-loading":e.creatingFile,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFile},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFile.path,"onUpdate:value":l[4]||(l[4]=n=>e.newFile.path=n),placeholder:"例如 README.md 或 src/main.kt"},null,8,["value"])]),_:1}),t(b,{label:"初始内容(可选)"},{default:a(()=>[t(D,{value:e.newFile.content,"onUpdate:value":l[5]||(l[5]=n=>e.newFile.content=n),rows:6,placeholder:"留空创建空文件"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Create folder modal "),t(U,{open:e.createFolderOpen,"onUpdate:open":l[8]||(l[8]=n=>e.createFolderOpen=n),title:"新建文件夹","confirm-loading":e.creatingFolder,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFolder},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件夹路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFolder.path,"onUpdate:value":l[7]||(l[7]=n=>e.newFolder.path=n),placeholder:"例如 src/utils"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Edit file content modal "),t(U,{open:e.editFileOpen,"onUpdate:open":l[10]||(l[10]=n=>e.editFileOpen=n),title:`编辑 ${e.editingFile?.file_name||""}`,"confirm-loading":e.savingFile,"ok-text":"保存","cancel-text":"取消",onOk:e.onSaveFile,width:"720"},{default:a(()=>[t(D,{value:e.editFileContent,"onUpdate:value":l[9]||(l[9]=n=>e.editFileContent=n),rows:18,"auto-size":{minRows:12,maxRows:24},style:{"font-family":"monospace"}},null,8,["value"])]),_:1},8,["open","title","confirm-loading"]),_(" Create modal "),t(U,{open:e.createOpen,"onUpdate:open":l[15]||(l[15]=n=>e.createOpen=n),title:"新建项目","confirm-loading":e.creating,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreate},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"项目名称",required:""},{default:a(()=>[t(T,{value:e.newProject.name,"onUpdate:value":l[11]||(l[11]=n=>e.newProject.name=n),placeholder:"例如:旅行计划-上海"},null,8,["value"])]),_:1}),t(b,{label:"描述"},{default:a(()=>[t(D,{value:e.newProject.description,"onUpdate:value":l[12]||(l[12]=n=>e.newProject.description=n),rows:2},null,8,["value"])]),_:1}),t(b,{label:"类型"},{default:a(()=>[t(R,{value:e.newProject.type,"onUpdate:value":l[13]||(l[13]=n=>e.newProject.type=n)},{default:a(()=>[t(m,{value:"document"},{default:a(()=>[...l[32]||(l[32]=[r("文档 (document)",-1)])]),_:1}),t(m,{value:"data"},{default:a(()=>[...l[33]||(l[33]=[r("数据 (data)",-1)])]),_:1}),t(m,{value:"web"},{default:a(()=>[...l[34]||(l[34]=[r("Web",-1)])]),_:1}),t(m,{value:"app"},{default:a(()=>[...l[35]||(l[35]=[r("应用 (app)",-1)])]),_:1}),t(m,{value:"presentation"},{default:a(()=>[...l[36]||(l[36]=[r("演示文稿",-1)])]),_:1}),t(m,{value:"spreadsheet"},{default:a(()=>[...l[37]||(l[37]=[r("表格",-1)])]),_:1}),t(m,{value:"design"},{default:a(()=>[...l[38]||(l[38]=[r("设计",-1)])]),_:1}),t(m,{value:"code"},{default:a(()=>[...l[39]||(l[39]=[r("代码",-1)])]),_:1}),t(m,{value:"workflow"},{default:a(()=>[...l[40]||(l[40]=[r("工作流",-1)])]),_:1}),t(m,{value:"knowledge"},{default:a(()=>[...l[41]||(l[41]=[r("知识库",-1)])]),_:1})]),_:1},8,["value"])]),_:1}),t(b,{label:"根路径 (可选)"},{default:a(()=>[t(T,{value:e.newProject.rootPath,"onUpdate:value":l[14]||(l[14]=n=>e.newProject.rootPath=n),placeholder:"留空则仅元数据"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"])])}const We=we(Pe,[["render",Le],["__scopeId","data-v-019ac5aa"],["__file","/tmp/cc-web-panel-R5yrKU/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
@@ -1 +0,0 @@
1
- import{E as I,b as w,r as b,I as m,J as y,U as a,R as g,c as i,K as u,V as h,F as C,Z as L,N as O,o as M,P as p,Q as S,S as R}from"./vendor-BvqAck49.js";import{u as E,_ as N}from"./index-BsReT8kE.js";import{u as P}from"./useShellMode-CgR0wCYM.js";import{p as V}from"./parsers-UEvh_ShA.js";import{u as z}from"./chat-Bke-Axcb.js";import{a9 as j,ap as q,R as B}from"./icons-DP3uiYxy.js";const A=I("skills",()=>{const _=b(!1),t=b([]),n=b(""),e=b("all"),k=w(()=>{const o=new Set(["all"]);return t.value.forEach(l=>{l.category&&o.add(l.category),l.executionMode&&o.add(l.executionMode)}),[...o]}),v=w(()=>{let o=t.value;if(e.value!=="all"&&(o=o.filter(l=>l.category===e.value||l.executionMode===e.value)),n.value){const l=n.value.toLowerCase();o=o.filter(d=>d.name?.toLowerCase().includes(l)||d.description?.toLowerCase().includes(l)||d.title?.toLowerCase().includes(l))}return o});async function f(){const o=E();_.value=!0;try{if(P().isEmbedded){const c=await o.sendRaw({type:"skill.list"},2e4);c?.ok&&Array.isArray(c.result?.skills)?t.value=c.result.skills:(console.error("skill.list custom topic failed:",c?.error),t.value=[]);return}const{output:l}=await o.execute("skill list",2e4),d=V(l);t.value=d}catch(l){console.error("Failed to load skills:",l)}finally{_.value=!1}}return{loading:_,allSkills:t,searchQuery:n,selectedCategory:e,categories:k,filteredSkills:v,loadSkills:f}}),F={__name:"Skills",setup(_,{expose:t}){t();const n=A(),e=z(),k=O(),v=w(()=>n.categories.filter(r=>r!=="all").slice(0,6));function f(r){return{"built-in":"内置","cli-direct":"CLI",agent:"Agent","llm-query":"LLM",hybrid:"混合",workspace:"工作区",marketplace:"市场"}[r]||r}function o(r){return{"cli-direct":"CLI",agent:"Agent","llm-query":"LLM",hybrid:"混合","built-in":"内置"}[r]||r||"未知"}function l(r){return{"cli-direct":"cyan",agent:"purple","llm-query":"blue",hybrid:"orange","built-in":"green"}[r]||"default"}async function d(r){await e.createSession("agent"),k.push("/chat"),setTimeout(()=>{e.currentSessionId&&e.sendMessage(e.currentSessionId,`/skill run ${r}`)},300)}M(()=>{n.allSkills.length||n.loadSkills()});const c={skillsStore:n,chatStore:e,router:k,displayCategories:v,catLabel:f,modeLabel:o,modeColor:l,runSkill:d,computed:w,onMounted:M,get useRouter(){return O},get ReloadOutlined(){return B},get PlayCircleOutlined(){return q},get AppstoreOutlined(){return j},get useSkillsStore(){return A},get useChatStore(){return z}};return Object.defineProperty(c,"__isScriptSetup",{enumerable:!1,value:!0}),c}},Q={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},U={class:"page-sub"},K={style:{display:"flex",gap:"12px","margin-bottom":"20px","flex-wrap":"wrap"}},T={key:0,style:{"text-align":"center",padding:"60px"}},D={class:"skills-grid"},G={style:{display:"flex","justify-content":"space-between","align-items":"flex-start"}},J={style:{flex:"1","min-width":"0"}},W={style:{"font-weight":"500",color:"#e0e0e0","font-size":"14px","margin-bottom":"4px","font-family":"monospace"}},Z={style:{color:"var(--text-secondary)","font-size":"12px","line-height":"1.5"}},H={style:{"margin-left":"12px","flex-shrink":"0"}},X={style:{"margin-top":"10px",display:"flex","justify-content":"flex-end"}},Y={style:{"text-align":"center",padding:"60px",color:"var(--text-muted)"}};function $(_,t,n,e,k,v){const f=m("a-button"),o=m("a-input-search"),l=m("a-radio-button"),d=m("a-radio-group"),c=m("a-spin"),r=m("a-tag"),x=m("a-card");return p(),y("div",null,[a("div",Q,[a("div",null,[t[3]||(t[3]=a("h2",{class:"page-title"},"技能管理",-1)),a("p",U,g(e.skillsStore.allSkills.length)+" 个可用技能",1)]),i(f,{type:"primary",ghost:"",loading:e.skillsStore.loading,onClick:t[0]||(t[0]=s=>e.skillsStore.loadSkills())},{icon:u(()=>[i(e.ReloadOutlined)]),default:u(()=>[t[4]||(t[4]=S(" 刷新 ",-1))]),_:1},8,["loading"])]),h(" Search & Filter "),a("div",K,[i(o,{value:e.skillsStore.searchQuery,"onUpdate:value":t[1]||(t[1]=s=>e.skillsStore.searchQuery=s),placeholder:"搜索技能名称或描述...",style:{width:"300px"},"allow-clear":""},null,8,["value"]),i(d,{value:e.skillsStore.selectedCategory,"onUpdate:value":t[2]||(t[2]=s=>e.skillsStore.selectedCategory=s),"button-style":"solid"},{default:u(()=>[i(l,{value:"all"},{default:u(()=>[...t[5]||(t[5]=[S("全部",-1)])]),_:1}),(p(!0),y(C,null,L(e.displayCategories,s=>(p(),R(l,{key:s,value:s},{default:u(()=>[S(g(e.catLabel(s)),1)]),_:2},1032,["value"]))),128))]),_:1},8,["value"])]),h(" Loading State "),e.skillsStore.loading?(p(),y("div",T,[i(c,{size:"large"}),t[6]||(t[6]=a("div",{style:{color:"var(--text-muted)","margin-top":"12px"}},"加载技能中...",-1))])):e.skillsStore.filteredSkills.length?(p(),y(C,{key:1},[h(" Skills Grid "),a("div",D,[(p(!0),y(C,null,L(e.skillsStore.filteredSkills,s=>(p(),R(x,{key:s.name,class:"skill-card",size:"small",hoverable:"",style:{background:"var(--bg-card)","border-color":"var(--border-color)",cursor:"default"}},{default:u(()=>[a("div",G,[a("div",J,[a("div",W,g(s.name),1),a("div",Z,g(s.description||"暂无描述"),1)]),a("div",H,[i(r,{color:e.modeColor(s.executionMode),style:{"font-size":"10px"}},{default:u(()=>[S(g(e.modeLabel(s.executionMode)),1)]),_:2},1032,["color"])])]),a("div",X,[i(f,{size:"small",type:"primary",ghost:"",onClick:ee=>e.runSkill(s.name)},{icon:u(()=>[i(e.PlayCircleOutlined)]),default:u(()=>[t[7]||(t[7]=S(" 运行 ",-1))]),_:1},8,["onClick"])])]),_:2},1024))),128))])],2112)):(p(),y(C,{key:2},[h(" Empty State "),a("div",Y,[i(e.AppstoreOutlined,{style:{"font-size":"48px","margin-bottom":"16px",display:"block"}}),a("div",null,g(e.skillsStore.allSkills.length?"没有匹配的技能":"点击刷新加载技能列表"),1)])],2112))])}const ie=N(F,[["render",$],["__scopeId","data-v-d64d43f5"],["__file","/tmp/cc-web-panel-R5yrKU/repo/packages/web-panel/src/views/Skills.vue"]]);export{ie as default};
@@ -1 +0,0 @@
1
- import{E as F,b as D,r as R,I as p,J as c,U as _,c as n,K as a,S as C,V as x,o as I,x as V,P as i,Q as k,R as r,F as T,Z as O}from"./vendor-BvqAck49.js";import{u as P,_ as U}from"./index-BsReT8kE.js";import{R as E}from"./icons-DP3uiYxy.js";const B=F("tasks",()=>{const y=R([]),l=R(!1);let u=null,t=null,d=null;const b=D(()=>y.value.filter(e=>e.status==="running")),v=D(()=>y.value.filter(e=>e.status==="pending")),w=D(()=>y.value.filter(e=>e.status==="completed"||e.status==="failed"||e.status==="timeout"));async function s(){const e=P();l.value=!0;try{const g=await e.sendRaw({type:"tasks-list"});g&&Array.isArray(g.tasks)&&(y.value=g.tasks)}catch{}finally{l.value=!1}}async function m(e){const g=P();try{await g.sendRaw({type:"tasks-stop",taskId:e})}catch{}finally{await s()}}const f=R(null);function h(e=5e3){N(),s(),u=setInterval(s,e),S()}function N(){u&&(clearInterval(u),u=null),t&&(t(),t=null),d&&(clearTimeout(d),d=null)}function S(){const e=P();if(t)return;const g=z=>{z.type==="task:notification"&&z.payload?.task&&(f.value=z.payload.task,s(),d&&clearTimeout(d),d=setTimeout(()=>{f.value=null,d=null},8e3))};t=e.onRuntimeEvent(g)}function A(e){return!e||e<0?"-":e<1e3?`${e}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${(e/6e4).toFixed(1)}m`}function o(e){switch(e){case"running":return"processing";case"pending":return"default";case"completed":return"success";case"failed":return"error";case"timeout":return"warning";default:return"default"}}return{tasks:y,loading:l,running:b,pending:v,completed:w,lastNotification:f,fetchTasks:s,stopTask:m,startPolling:h,stopPolling:N,formatDuration:A,getStatusColor:o}}),K={__name:"Tasks",setup(y,{expose:l}){l();const u=B(),t=[{title:"状态",key:"status",width:90},{title:"描述",key:"description",ellipsis:!0},{title:"类型",dataIndex:"type",width:100},{title:"耗时",key:"duration",width:90},{title:"创建时间",key:"createdAt",width:180},{title:"结果",key:"result",ellipsis:!0},{title:"操作",key:"action",width:80}];function d(s){return s.status==="running"&&s.startedAt?u.formatDuration(Date.now()-s.startedAt):s.completedAt&&s.startedAt?u.formatDuration(s.completedAt-s.startedAt):"-"}function b(s){return s?new Date(s).toLocaleString():"-"}function v(s,m){return s?s.length>m?`${s.slice(0,m)}...`:s:""}I(()=>u.startPolling(5e3)),V(()=>u.stopPolling());const w={store:u,columns:t,getDuration:d,formatTime:b,truncate:v,onMounted:I,onUnmounted:V,get ReloadOutlined(){return E},get useTasksStore(){return B}};return Object.defineProperty(w,"__isScriptSetup",{enumerable:!1,value:!0}),w}},L={class:"page-header"},j={key:0,class:"error-text"},J={key:1},M={class:"task-header"},Q={class:"task-desc"},W={class:"task-id"},Z={class:"task-meta"},q=["title"],G={key:0,class:"error-text"},H={key:1,class:"success-text"},X={key:2,class:"muted-text"};function Y(y,l,u,t,d,b){const v=p("a-button"),w=p("a-space"),s=p("a-alert"),m=p("a-statistic"),f=p("a-card"),h=p("a-col"),N=p("a-row"),S=p("a-tag"),A=p("a-table");return i(),c("div",null,[_("div",L,[l[3]||(l[3]=_("div",null,[_("h2",{class:"page-title"},"后台任务"),_("p",{class:"page-sub"},"查看后台任务队列、实时通知和任务执行结果。")],-1)),n(w,null,{default:a(()=>[n(v,{ghost:"",loading:t.store.loading,onClick:l[0]||(l[0]=o=>t.store.fetchTasks())},{icon:a(()=>[n(t.ReloadOutlined)]),default:a(()=>[l[2]||(l[2]=k(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),t.store.lastNotification?(i(),C(s,{key:0,type:t.store.lastNotification.status==="completed"?"success":"error","show-icon":"",closable:"",class:"banner",onClose:l[1]||(l[1]=o=>t.store.lastNotification=null)},{message:a(()=>[k(" 任务"+r(t.store.lastNotification.status==="completed"?"完成":"结束")+": "+r(t.store.lastNotification.description||t.store.lastNotification.id.slice(0,16)),1)]),description:a(()=>[t.store.lastNotification.error?(i(),c("span",j,r(t.store.lastNotification.error),1)):t.store.lastNotification.result?(i(),c("span",J,r(t.truncate(String(t.store.lastNotification.result),120)),1)):x("v-if",!0)]),_:1},8,["type"])):x("v-if",!0),n(N,{gutter:[16,16],class:"stats-row"},{default:a(()=>[n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"全部任务",value:t.store.tasks.length},null,8,["value"])]),_:1})]),_:1}),n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"运行中",value:t.store.running.length},null,8,["value"])]),_:1})]),_:1}),n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"等待中",value:t.store.pending.length},null,8,["value"])]),_:1})]),_:1}),n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"已完成",value:t.store.completed.length},null,8,["value"])]),_:1})]),_:1})]),_:1}),t.store.running.length>0?(i(),C(f,{key:1,title:"运行中的任务",class:"panel-card",size:"small"},{default:a(()=>[(i(!0),c(T,null,O(t.store.running,o=>(i(),c("div",{key:o.id,class:"task-item running"},[_("div",M,[n(S,{color:t.store.getStatusColor(o.status)},{default:a(()=>[k(r(o.status.toUpperCase()),1)]),_:2},1032,["color"]),_("span",Q,r(o.description),1),_("span",W,r(o.id.slice(0,16)),1)]),_("div",Z,[_("span",null,"类型: "+r(o.type||"-"),1),_("span",null,"已运行: "+r(t.store.formatDuration(Date.now()-o.startedAt)),1),n(v,{size:"small",danger:"",onClick:e=>t.store.stopTask(o.id)},{default:a(()=>[...l[4]||(l[4]=[k("停止",-1)])]),_:1},8,["onClick"])])]))),128))]),_:1})):x("v-if",!0),n(f,{class:"panel-card"},{default:a(()=>[n(A,{columns:t.columns,"data-source":t.store.tasks,pagination:{pageSize:15,size:"small"},loading:t.store.loading,"row-key":"id",size:"small"},{bodyCell:a(({column:o,record:e})=>[o.key==="status"?(i(),C(S,{key:0,color:t.store.getStatusColor(e.status)},{default:a(()=>[k(r(e.status),1)]),_:2},1032,["color"])):o.key==="description"?(i(),c("span",{key:1,title:e.command},r(e.description),9,q)):o.key==="duration"?(i(),c(T,{key:2},[k(r(t.getDuration(e)),1)],64)):o.key==="createdAt"?(i(),c(T,{key:3},[k(r(t.formatTime(e.createdAt)),1)],64)):o.key==="result"?(i(),c(T,{key:4},[e.error?(i(),c("span",G,r(t.truncate(e.error,60)),1)):e.result?(i(),c("span",H,r(t.truncate(String(e.result),60)),1)):(i(),c("span",X,"-"))],64)):o.key==="action"?(i(),c(T,{key:5},[e.status==="running"?(i(),C(v,{key:0,size:"small",danger:"",onClick:g=>t.store.stopTask(e.id)},{default:a(()=>[...l[5]||(l[5]=[k(" 停止 ",-1)])]),_:1},8,["onClick"])):x("v-if",!0)],64)):x("v-if",!0)]),_:1},8,["data-source","loading"])]),_:1})])}const st=U(K,[["render",Y],["__scopeId","data-v-da5ff6a2"],["__file","/tmp/cc-web-panel-R5yrKU/repo/packages/web-panel/src/views/Tasks.vue"]]);export{st as default};
@@ -1 +0,0 @@
1
- import{I as S,P as n,J as i,U as l,S as h,R as o,c,K as d,Q as u,V as g,b as a}from"./vendor-BvqAck49.js";import{_ as b}from"./index-BsReT8kE.js";import{aD as O,aH as D}from"./icons-DP3uiYxy.js";const C={__name:"TimelineRenderer",props:{event:{type:Object,required:!0}},setup(v,{expose:_}){_();const r=v,e=a(()=>r.event.content||{}),p=a(()=>{const t=r.event.source.adapter||"";return t.startsWith("travel-12306")||t.startsWith("travel-ctrip")}),m=a(()=>e.value.from&&e.value.to?`${e.value.from} → ${e.value.to}`:e.value.origin&&e.value.destination?`${e.value.origin} → ${e.value.destination}`:null),s=a(()=>r.event.place||e.value.placeName||e.value.poi),N=a(()=>e.value.trainNo),y=a(()=>e.value.flightNo),T=a(()=>e.value.title||e.value.text||e.value.description||"—"),k=a(()=>{const t=[];return e.value.departureTime&&t.push(`出发 ${e.value.departureTime}`),e.value.arrivalTime&&t.push(`到达 ${e.value.arrivalTime}`),e.value.duration&&t.push(`${e.value.duration}`),e.value.distance&&t.push(`${e.value.distance}`),t.length?t.join(" · "):null}),x=a(()=>{if(!r.event.occurredAt)return"";const t=new Date(r.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")}`}),f={props:r,c:e,isTravel:p,route:m,placeName:s,trainNo:N,flightNo:y,fallbackText:T,extraDetail:k,formattedTime:x,computed:a,get CarOutlined(){return D},get EnvironmentOutlined(){return O}};return Object.defineProperty(f,"__isScriptSetup",{enumerable:!1,value:!0}),f}},R={class:"timeline-event"},V={class:"dot"},w={class:"card"},B={class:"head"},E={class:"time"},j={class:"primary"},A={key:0},H={key:1},I={key:2},K={key:0,class:"trip-no"},M={key:1,class:"extra"};function P(v,_,r,e,p,m){const s=S("a-tag");return n(),i("div",R,[l("div",V,[e.isTravel?(n(),h(e.CarOutlined,{key:0})):(n(),h(e.EnvironmentOutlined,{key:1}))]),l("div",w,[l("div",B,[l("span",E,o(e.formattedTime),1),c(s,{color:"cyan"},{default:d(()=>[u(o(r.event.source.adapter),1)]),_:1}),c(s,null,{default:d(()=>[u(o(r.event.subtype),1)]),_:1})]),l("div",j,[e.route?(n(),i("span",A,o(e.route),1)):e.placeName?(n(),i("span",H,"📍 "+o(e.placeName),1)):(n(),i("span",I,o(e.fallbackText),1))]),e.trainNo||e.flightNo?(n(),i("div",K,[c(s,{color:"blue"},{default:d(()=>[u(o(e.trainNo||e.flightNo),1)]),_:1})])):g("v-if",!0),e.extraDetail?(n(),i("div",M,o(e.extraDetail),1)):g("v-if",!0)])])}const F=b(C,[["render",P],["__scopeId","data-v-18400280"],["__file","/tmp/cc-web-panel-R5yrKU/repo/packages/web-panel/src/components/pdh/renderers/TimelineRenderer.vue"]]);export{F as default};
@@ -1 +0,0 @@
1
- import{O as r}from"./index-BsReT8kE.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-DWU7gipF.js";import{U as t}from"./index-BsReT8kE.js";import"./vendor-BvqAck49.js";import"./index-0ZL7FjnB.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-B9kpAVZb.js";import{U as t}from"./index-BsReT8kE.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-j6LiN9K2.js";import"./useFlexGapSupport-D_0KlvEp.js";import"./styleChecker-g4UCWzKN.js";import"./index-0ZL7FjnB.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};