chainlesschain 0.162.32 → 0.162.34

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 (163) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-Cg_uWAVl.js → AIOps-BYfi9NYS.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DSFtQ1c2.js → ActionButton-BiS_tAN7.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-BMxpkw8y.js → Analytics-jiWl_p-B.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-tgVxlmsx.js → AppLayout-m4sIzDot.js} +3 -3
  6. package/src/assets/web-panel/assets/{Audit-DwzGllcp.js → Audit-CPla3Erm.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-BG28Y2MV.js → Backup-BGeQzTaB.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-TXthbazl.js → BaseInput-DTf7Z1iU.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-D096SxaD.js → Chat-DPTlQlD-.js} +4 -4
  10. package/src/assets/web-panel/assets/ChatBubbleRenderer-BgRXce4e.js +1 -0
  11. package/src/assets/web-panel/assets/{Checkbox-Czttw1JS.js → Checkbox-DY-XuQMu.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-DZtMgv4q.js → Codegen-B6oxPiZI.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-D3DnfExY.js → Col-Dqxb4wSE.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-Bj5AdwqY.js → Community-DCIX514p.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-BQ8Zszub.js → Compact-BGtCzDoJ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-DXacb34n.js → Compliance-zcOYd55o.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-BgMUBTkw.js → Cowork-DVTtdIdM.js} +4 -4
  18. package/src/assets/web-panel/assets/{Cron-fqBWOqlN.js → Cron-CPUaR69k.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-E4oa1MWy.js → Crosschain-DnjUS6QH.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-pwgfYZaV.js → DID-Dnz8VDmx.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-n8mdLFIR.js → Dashboard-CtWf27j7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown--6DYqxk7.js → Dropdown-B4GC1ZV4.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-CkjQluz3.js → EmailListRenderer-wjij3kzr.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-u-QTQ-OC.js → FamilyGuardDashboard-rS-2W4u5.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-D219M5Qc.js → Federation-90p5Tnoz.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-BBU_aopC.js → FormItemContext-Cnrw7gzq.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-pTMCIHcM.js → GenericCardRenderer-C85NsWa3.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-ClcCARWt.js → Git-BFAVM9F8.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-CvUi3I93.js → Governance-DBoRonpq.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-DT-a4pVg.js → Inference-DHRyD66j.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-DHMs2LY8.js → KnowledgeGraph-CTvUKecD.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-D2s4eV1N.js → Logs-CB0dv_Ts.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-YC5-fx-6.js → Marketplace-CN7Hm5Uw.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-7JHTEC4T.js → McpTools-q5H25_8L.js} +5 -5
  35. package/src/assets/web-panel/assets/{Memory-BudotVLD.js → Memory-BCV3pZ1d.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-CAiRyLVU.js → MobileBridge-C04Mngt4.js} +2 -2
  37. package/src/assets/web-panel/assets/MobileProjects-CUxONYre.js +1 -0
  38. package/src/assets/web-panel/assets/{Mtc-d0iY0CeK.js → Mtc-ByAMz2DN.js} +2 -2
  39. package/src/assets/web-panel/assets/{MtcAudit-aI2cG1UP.js → MtcAudit-B7V7byJq.js} +4 -4
  40. package/src/assets/web-panel/assets/{Multisig-4bF70khG.js → Multisig-DtKmcVQV.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-CwLib1S7.js → NLProgramming-CaMbT5SC.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-Wt7AuFRU.js → Notes-DRjbSTCU.js} +4 -4
  43. package/src/assets/web-panel/assets/{NotificationSettings-D081vV_7.js → NotificationSettings-B9YbJID5.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-DCPei1L9.js → OrderTableRenderer-BcI_-vGS.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-BNEsUNdP.js → Organization-oTask4BE.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-B_1iUXDD.js → Overflow-Bab06ey7.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-Dbc-kNwJ.js → P2P--wlBeU0N.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-D8Xh289k.js → PdhVaultBrowser-D4t77Pwc.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-C77mM6-n.js → Permissions-B3sf6CJ3.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-Dj0J3r_K.js → PersonalDataHub-BXOojk63.js} +4 -4
  51. package/src/assets/web-panel/assets/{Pipeline-B6F0WQ2C.js → Pipeline-DReqtBFN.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-eDKOkyyq.js → Privacy-cT1GwKLx.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-DAWwhr5_.js → ProjectInit-BhTAzVhH.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-DwdK8k6I.js → ProjectSettings-CK-D8Fyj.js} +2 -2
  55. package/src/assets/web-panel/assets/Projects-CbHiwen6.js +1 -0
  56. package/src/assets/web-panel/assets/{Providers--DcYxQfN.js → Providers-B-ftiXa8.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-DU268niT.js → QuickAsk-CT5XPwTF.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-ChnflhV1.js → Recommend-CohhlBZ_.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-DSsY3bQG.js → Reputation-CrgbixFz.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-Zb-EjmgQ.js → Row-ClExmBn3.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-CGLiixZB.js → RssFeed-VV0qizCJ.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-Dhr_po-U.js → Search-CqJapSiL.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-GMYNhGsR.js → Security-DY66Zie6.js} +2 -2
  64. package/src/assets/web-panel/assets/{Services-DiOpnVY0.js → Services-RQwxat7-.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-DG3ez6ME.js → Skeleton-0v37UTU_.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-DZGptytP.js → Skills-B4Vm4DxN.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-CtGpE3xA.js → Sla-CggphTlo.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-DQFw6Cf9.js → SpeechSettings-BAOU08C7.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-C8X78RpX.js → SyncSettings-DmtC4J1w.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-CExqxzL6.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-SF9_ZWsV.js → Templates-C1QK0YoU.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-BbIQSVZz.js → Tenant-CieOfmqp.js} +1 -1
  73. package/src/assets/web-panel/assets/{Terminal-DKr5zDwu.js → Terminal-DWdhrxRq.js} +2 -2
  74. package/src/assets/web-panel/assets/{TimelineRenderer-BtLaNaWr.js → TimelineRenderer-CjFVUUDU.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-CfYbk2NG.js → Tokens-Bwbk3id9.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-BLX_XDP0.js → Trigger-uJle_yj4.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-BWxUv9PR.js → Trust-BcOuxAA5.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-DRwTyQD4.js → UkeySign-DUu7Ufg6.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-BsC4VOSo.js → VideoEditing-Ck8JtQ2n.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-CSsO1NJU.js → Wallet-B3jw43on.js} +2 -2
  81. package/src/assets/web-panel/assets/{WebAuthn-z1MxiFzS.js → WebAuthn-Baf9K0y7.js} +4 -4
  82. package/src/assets/web-panel/assets/{WorkflowEditor-B1vV7uuJ.js → WorkflowEditor-CTEDl_83.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-C0NJRaL2.js → chat-CKV51quV.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-CHRiteWF.js → colors-BO_RP_yz.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-2XmBBKPD.js → compact-item-BZsxw_ZG.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-DkedHC38.js → createContext-CAbvtzVL.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-DQYatsRR.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-Bpn9Xrlw.js → hasIn-QmHT8zDz.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-CyJpmSHZ.js → index-5hlO2-JQ.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-DAFLFMXQ.js → index-8BMLlHCv.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-De5vOO9V.js → index-9IqJODII.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-DtU4qZRF.js → index-B2aiE8jk.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-NuBsCRaR.js → index-B3fwyCjJ.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BYUd69vM.js → index-B5zhcul9.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CdR7RfRP.js → index-B9Z83FTS.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-De49R7TX.js → index-BCsZiq4i.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BveL_4n3.js → index-BEJa1FiF.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BYmwEaIk.js → index-BL7gQAuB.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DMbF-Euw.js → index-BNvTNZ1V.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-i4W_EAuh.js → index-BPZHeug4.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BN068mCR.js → index-BRNYA0BV.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CJOoo72F.js → index-BnPBG3Tr.js} +1 -1
  103. package/src/assets/web-panel/assets/index-Bv_y1Ud7.js +1 -0
  104. package/src/assets/web-panel/assets/{index-DUBsq_1G.js → index-C3K1eHDd.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BfY9U3X5.js → index-C6AA-xB2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Dk7P-q3n.js → index-C6i3reUS.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cljnfuxu.js → index-CEh2Ry_A.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-cfSUlOfY.js → index-CSaI8R_7.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DM9JrnYi.js → index-CVoYeZ5Q.js} +1 -1
  110. package/src/assets/web-panel/assets/index-CZZnSJEX.js +1 -0
  111. package/src/assets/web-panel/assets/{index-alGjpoM1.js → index-CqiKnXtL.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Sk3-3tKa.js → index-CsBx0u5G.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BZ1gOoiG.js → index-D8CHQnPl.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-uHGxyZtQ.js → index-DBCYOypV.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-D9mNfpxi.js → index-DC1CFfQU.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CCg6ZY4t.js → index-DKnngF_f.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BItcSqan.js → index-DKquNxL2.js} +3 -3
  118. package/src/assets/web-panel/assets/{index-D7U411hK.js → index-DRK0oAV5.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CToQxpWz.js → index-DeC7lehI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DryKGM_t.js → index-DjrDGJP2.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B5NGWgHp.js → index-Dln_vjSY.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BOsIgPge.js → index-Dob6B6qS.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DAeHmElB.js → index-GPY0LjCu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DDy_RDjs.js → index-Ha2_56mf.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CWgWrrWs.js → index-fnDgExTu.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CxvA72CP.js → index-jd2r-T4p.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DE5Qm9UI.js → index-qPafbZmr.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-DlDE-QgI.js → initDefaultProps-Bc2GWeWe.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-CodUbIRF.js → motion-BI-Rxw6o.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-DaLwsHeR.js → move-DRPdwDQB.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-DdVg-3rL.js → omit-B4XTl3jW.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-KLR1EVCo.js → pickAttrs-Do5d86Wr.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-ChV7HvNw.js → placementArrow-B8VGZ0ZF.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-BB_A8dBt.js → responsiveObserve-Cf0kI_vN.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Bc1tQnIK.js → slide-Cb0psjSL.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-CgrveSb0.js → statusUtils-Bjuo5Oal.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-vXAYhhjz.js → styleChecker-BLMhoHJ5.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-BCIMPfq9.js → useFlexGapSupport-BdCwAfNU.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-DMZGdr6G.js → useFs-9Jhaz5gG.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-118tWI_Z.js → usePersonalDataHub-xYFyXKwD.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-Z7O2Y7JP.js → vnode-CVhepE6Z.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-BXym6zmD.js → zoom-IbbtJ4Zr.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +39 -0
  145. package/src/commands/command.js +187 -0
  146. package/src/commands/context.js +189 -0
  147. package/src/index.js +4 -0
  148. package/src/lib/goal-assess.js +228 -0
  149. package/src/lib/goal-store.js +33 -0
  150. package/src/lib/slash-commands.js +197 -0
  151. package/src/repl/agent-repl.js +42 -1
  152. package/src/runtime/agent-core.js +275 -0
  153. package/src/runtime/headless-runner.js +151 -0
  154. package/src/runtime/headless-stream.js +86 -0
  155. package/src/runtime/mcp-config.js +239 -0
  156. package/src/runtime/policies/agent-policy.js +1 -0
  157. package/src/assets/web-panel/assets/ChatBubbleRenderer-PIx0Eu9I.js +0 -1
  158. package/src/assets/web-panel/assets/MobileProjects-CrJJOCFw.js +0 -1
  159. package/src/assets/web-panel/assets/Projects-Cb3p5QAP.js +0 -1
  160. package/src/assets/web-panel/assets/Tasks-DtVkhWCV.js +0 -1
  161. package/src/assets/web-panel/assets/devWarning-DmNpkOdC.js +0 -1
  162. package/src/assets/web-panel/assets/index-7nAysteg.js +0 -1
  163. package/src/assets/web-panel/assets/index-BKWSQilQ.js +0 -1
@@ -26,12 +26,18 @@ import {
26
26
  agentLoop as coreAgentLoop,
27
27
  formatToolArgs,
28
28
  } from "./agent-core.js";
29
+ import {
30
+ loadMcpConfig,
31
+ resolvePermissionPromptTool,
32
+ makePermissionPromptConfirmer,
33
+ } from "./mcp-config.js";
29
34
  import { IterationBudget } from "../lib/iteration-budget.js";
30
35
  import {
31
36
  startSession as jsonlStartSession,
32
37
  appendUserMessage as jsonlAppendUserMessage,
33
38
  appendAssistantMessage as jsonlAppendAssistantMessage,
34
39
  appendTokenUsage as jsonlAppendTokenUsage,
40
+ appendCompactEvent as jsonlAppendCompactEvent,
35
41
  rebuildMessages as jsonlRebuildMessages,
36
42
  sessionExists as jsonlSessionExists,
37
43
  getLastSessionId as jsonlGetLastSessionId,
@@ -245,6 +251,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
245
251
  appendAssistantMessage:
246
252
  deps.appendAssistantMessage || jsonlAppendAssistantMessage,
247
253
  appendTokenUsage: deps.appendTokenUsage || jsonlAppendTokenUsage,
254
+ appendCompactEvent: deps.appendCompactEvent || jsonlAppendCompactEvent,
248
255
  getLastSessionId: deps.getLastSessionId || jsonlGetLastSessionId,
249
256
  };
250
257
  const isStream = outputFormat === "stream-json";
@@ -367,6 +374,51 @@ export async function runAgentHeadless(options = {}, deps = {}) {
367
374
  }
368
375
  }
369
376
 
377
+ // --mcp-config: connect ad-hoc MCP servers for this run and expose their
378
+ // tools to the LLM (Claude-Code parity). Connection is best-effort — a server
379
+ // that fails to connect is logged to stderr and contributes no tools; a
380
+ // missing/empty config file fails fast (the user explicitly asked for MCP).
381
+ let mcp = null;
382
+ if (options.mcpConfig) {
383
+ const doLoadMcp = deps.loadMcpConfig || loadMcpConfig;
384
+ try {
385
+ mcp = await doLoadMcp(options.mcpConfig, { writeErr });
386
+ if (isText) {
387
+ for (const c of mcp.connected) {
388
+ writeErr(` mcp: ${c.server} (${c.tools} tools)\n`);
389
+ }
390
+ }
391
+ } catch (err) {
392
+ writeErr(`Error: ${err.message}\n`);
393
+ return { exitCode: 1, result: err.message, isError: true };
394
+ }
395
+ }
396
+
397
+ // --permission-prompt-tool: route every CONFIRM-tier approval to an MCP tool
398
+ // (loaded via --mcp-config) instead of headless fail-closed. Overrides the
399
+ // permission-mode confirmer on the gate for this session.
400
+ if (options.permissionPromptTool) {
401
+ let ppt;
402
+ try {
403
+ ppt = resolvePermissionPromptTool(mcp, options.permissionPromptTool);
404
+ } catch (err) {
405
+ writeErr(`Error: ${err.message}\n`);
406
+ if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
407
+ return { exitCode: 1, result: err.message, isError: true };
408
+ }
409
+ if (approvalGate && typeof approvalGate.setConfirmer === "function") {
410
+ approvalGate.setConfirmer(
411
+ makePermissionPromptConfirmer({
412
+ mcpClient: mcp.mcpClient,
413
+ server: ppt.server,
414
+ tool: ppt.tool,
415
+ writeErr,
416
+ isText,
417
+ }),
418
+ );
419
+ }
420
+ }
421
+
370
422
  const loopOptions = {
371
423
  model,
372
424
  provider,
@@ -382,11 +434,48 @@ export async function runAgentHeadless(options = {}, deps = {}) {
382
434
  enabledToolNames,
383
435
  disabledTools,
384
436
  iterationBudget: budget,
437
+ // --mcp-config wiring: tool defs for the LLM + dispatch map + live client.
438
+ mcpClient: mcp?.mcpClient || null,
439
+ extraToolDefinitions: mcp?.extraToolDefinitions || undefined,
440
+ externalToolExecutors: mcp?.externalToolExecutors || undefined,
441
+ externalToolDescriptors: mcp?.externalToolDescriptors || undefined,
385
442
  // chatFn passthrough lets tests drive the loop deterministically.
386
443
  chatFn: deps.chatFn || options.chatFn || undefined,
387
444
  signal: options.signal || undefined,
388
445
  };
389
446
 
447
+ // Goal binding (cc goal, Phase 1). `--goal <id>` binds explicitly; `--goal`
448
+ // with no value (options.goal === true) auto-resolves from active/session.
449
+ // When omitted, headless stays goal-free (no behavior change). Best-effort:
450
+ // a failure here must never fail the run.
451
+ let boundGoalId = null;
452
+ if (options.goal !== undefined && options.goal !== false) {
453
+ try {
454
+ const explicitId = typeof options.goal === "string" ? options.goal : null;
455
+ const { resolveActiveGoal, linkSession } =
456
+ await import("../lib/goal-store.js");
457
+ const goal = (deps.resolveActiveGoal || resolveActiveGoal)({
458
+ explicitId,
459
+ sessionId,
460
+ });
461
+ if (goal) {
462
+ const { goalPrepareCall } = await import("../lib/goal-context.js");
463
+ loopOptions.prepareCall = goalPrepareCall(goal);
464
+ boundGoalId = goal.id;
465
+ // Link the session so a later `--continue`/`--resume` keeps this goal.
466
+ if (explicitId && persist !== false) {
467
+ try {
468
+ linkSession(goal.id, sessionId);
469
+ } catch {
470
+ /* linking is optional polish — never fatal */
471
+ }
472
+ }
473
+ }
474
+ } catch {
475
+ /* goal binding is best-effort — proceed without it */
476
+ }
477
+ }
478
+
390
479
  const startedAt = deps.now ? deps.now() : Date.now();
391
480
  const toolCalls = [];
392
481
  const usage = { input_tokens: 0, output_tokens: 0 };
@@ -424,6 +513,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
424
513
  resumed_from: resumeId,
425
514
  history_messages: history.length,
426
515
  additional_directories: additionalDirectories,
516
+ goal_id: boundGoalId,
427
517
  });
428
518
 
429
519
  try {
@@ -522,6 +612,17 @@ export async function runAgentHeadless(options = {}, deps = {}) {
522
612
  writeErr(`Error: ${message}\n`);
523
613
  }
524
614
  return { exitCode: 1, result: message, isError: true };
615
+ } finally {
616
+ // Tear down ad-hoc MCP servers (--mcp-config) before returning, whether the
617
+ // loop completed or threw. Best-effort: a failed disconnect never masks the
618
+ // run's own outcome.
619
+ if (mcp?.mcpClient) {
620
+ try {
621
+ await mcp.mcpClient.disconnectAll();
622
+ } catch {
623
+ // ignore — disconnect is best-effort
624
+ }
625
+ }
525
626
  }
526
627
 
527
628
  // coreAgentLoop emits run-ended reason "budget-exhausted" when the iteration
@@ -543,6 +644,56 @@ export async function runAgentHeadless(options = {}, deps = {}) {
543
644
  }
544
645
  }
545
646
 
647
+ // Run-end goal self-assessment (cc goal Phase 2, opt-in via --goal-assess).
648
+ // Spends one extra completion to judge whether the run advanced the bound
649
+ // goal, then persists progress / key-result / drift updates. Best-effort: it
650
+ // must never change the run's own outcome.
651
+ if (options.goalAssess && boundGoalId && !isError) {
652
+ try {
653
+ const { getGoal } = await import("../lib/goal-store.js");
654
+ const goal = (deps.getGoal || getGoal)(boundGoalId);
655
+ if (goal) {
656
+ const { assessGoalProgress } = await import("../lib/goal-assess.js");
657
+ const doAssess = deps.assessGoalProgress || assessGoalProgress;
658
+ const assessChat =
659
+ deps.assessChat ||
660
+ (async (assessPrompt) => {
661
+ const { chatWithTools } = await import("./agent-core.js");
662
+ const r = await chatWithTools(
663
+ [{ role: "user", content: assessPrompt }],
664
+ { model, provider, baseUrl, apiKey, enabledToolNames: [] },
665
+ );
666
+ return r?.message?.content || "";
667
+ });
668
+ const { assessment } = await doAssess({
669
+ goal,
670
+ transcript: { prompt: options.prompt, finalText, toolCalls },
671
+ chat: assessChat,
672
+ });
673
+ if (assessment) {
674
+ if (isText) {
675
+ writeErr(
676
+ ` ◎ goal ${boundGoalId}: ${assessment.advanced ? "advanced" : "no progress"}` +
677
+ (assessment.progress != null
678
+ ? ` (${assessment.progress}%)`
679
+ : "") +
680
+ "\n",
681
+ );
682
+ }
683
+ emitStream({
684
+ type: "goal_assessment",
685
+ goal_id: boundGoalId,
686
+ advanced: assessment.advanced,
687
+ progress: assessment.progress,
688
+ note: assessment.note,
689
+ });
690
+ }
691
+ }
692
+ } catch {
693
+ /* assessment is best-effort — never affect the run outcome */
694
+ }
695
+ }
696
+
546
697
  if (isStream) {
547
698
  emitStream({
548
699
  type: "result",
@@ -20,6 +20,11 @@ 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
22
  import { expandFileRefs } from "./file-ref-expander.js";
23
+ import {
24
+ loadMcpConfig,
25
+ resolvePermissionPromptTool,
26
+ makePermissionPromptConfirmer,
27
+ } from "./mcp-config.js";
23
28
  import { IterationBudget } from "../lib/iteration-budget.js";
24
29
  import {
25
30
  resolvePermissionMode,
@@ -207,6 +212,72 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
207
212
  additional_directories: additionalDirectories,
208
213
  });
209
214
 
215
+ // Goal binding (cc goal, Phase 1) — resolved once and injected on every turn.
216
+ // `--goal <id>` binds explicitly; `--goal` with no value auto-resolves.
217
+ let goalPrepareCallFn;
218
+ if (options.goal !== undefined && options.goal !== false) {
219
+ try {
220
+ const explicitId = typeof options.goal === "string" ? options.goal : null;
221
+ const { resolveActiveGoal } = await import("../lib/goal-store.js");
222
+ const goal = (deps.resolveActiveGoal || resolveActiveGoal)({
223
+ explicitId,
224
+ sessionId,
225
+ });
226
+ if (goal) {
227
+ const { goalPrepareCall } = await import("../lib/goal-context.js");
228
+ goalPrepareCallFn = goalPrepareCall(goal);
229
+ }
230
+ } catch {
231
+ /* goal binding is best-effort — proceed without it */
232
+ }
233
+ }
234
+
235
+ // --mcp-config: connect ad-hoc MCP servers for the whole stream session and
236
+ // expose their tools to the LLM (Claude-Code parity). Best-effort connect; a
237
+ // missing/empty config fails the session up front.
238
+ let mcp = null;
239
+ if (options.mcpConfig) {
240
+ const doLoadMcp = deps.loadMcpConfig || loadMcpConfig;
241
+ try {
242
+ mcp = await doLoadMcp(options.mcpConfig, { writeErr });
243
+ } catch (err) {
244
+ emit({
245
+ type: "result",
246
+ subtype: "error",
247
+ is_error: true,
248
+ error: err.message,
249
+ });
250
+ return { exitCode: 1, turns: 0 };
251
+ }
252
+ }
253
+
254
+ // --permission-prompt-tool: defer CONFIRM-tier approvals to an MCP tool
255
+ // (loaded via --mcp-config) instead of headless fail-closed.
256
+ if (options.permissionPromptTool) {
257
+ let ppt;
258
+ try {
259
+ ppt = resolvePermissionPromptTool(mcp, options.permissionPromptTool);
260
+ } catch (err) {
261
+ emit({
262
+ type: "result",
263
+ subtype: "error",
264
+ is_error: true,
265
+ error: err.message,
266
+ });
267
+ if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
268
+ return { exitCode: 1, turns: 0 };
269
+ }
270
+ if (approvalGate && typeof approvalGate.setConfirmer === "function") {
271
+ approvalGate.setConfirmer(
272
+ makePermissionPromptConfirmer({
273
+ mcpClient: mcp.mcpClient,
274
+ server: ppt.server,
275
+ tool: ppt.tool,
276
+ }),
277
+ );
278
+ }
279
+ }
280
+
210
281
  const loopOptionsBase = {
211
282
  model,
212
283
  provider,
@@ -219,6 +290,12 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
219
290
  approvalGate,
220
291
  enabledToolNames,
221
292
  disabledTools,
293
+ prepareCall: goalPrepareCallFn,
294
+ // --mcp-config wiring (tool defs + dispatch map + live client).
295
+ mcpClient: mcp?.mcpClient || null,
296
+ extraToolDefinitions: mcp?.extraToolDefinitions || undefined,
297
+ externalToolExecutors: mcp?.externalToolExecutors || undefined,
298
+ externalToolDescriptors: mcp?.externalToolDescriptors || undefined,
222
299
  chatFn: deps.chatFn || options.chatFn || undefined,
223
300
  signal: options.signal || undefined,
224
301
  // --include-partial-messages: stream live assistant-text deltas as
@@ -310,6 +387,15 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
310
387
  });
311
388
  }
312
389
 
390
+ // Tear down ad-hoc MCP servers (--mcp-config) when stdin closes.
391
+ if (mcp?.mcpClient) {
392
+ try {
393
+ await mcp.mcpClient.disconnectAll();
394
+ } catch {
395
+ // ignore — disconnect is best-effort
396
+ }
397
+ }
398
+
313
399
  emit({ type: "system", subtype: "end", session_id: sessionId, turns });
314
400
  return { exitCode: sawError ? 1 : 0, turns };
315
401
  }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Ad-hoc MCP config loader for headless agent runs (`cc agent --mcp-config`).
3
+ *
4
+ * Claude-Code parity: load a JSON file describing MCP servers, connect them for
5
+ * the duration of one headless run, and expose each server's tools to the LLM.
6
+ *
7
+ * The agent loop already knows how to *call* an MCP tool — it just needs three
8
+ * things wired into its options (see agent-core.js):
9
+ * - extraToolDefinitions → the LLM sees the tools (OpenAI function shape)
10
+ * - externalToolExecutors → name → {kind:"mcp", serverName, toolName}
11
+ * - mcpClient → executes mcpClient.callTool(server, tool, args)
12
+ *
13
+ * Tools are namespaced `mcp__<server>__<tool>` (Claude-Code convention) so they
14
+ * never collide with built-in agent tools or across servers.
15
+ */
16
+
17
+ import fs from "fs";
18
+ import { MCPClient } from "../harness/mcp-client.js";
19
+
20
+ /**
21
+ * Normalize a parsed config object into a `{ name: serverConfig }` map.
22
+ * Accepts the Claude-Code shape `{ "mcpServers": { ... } }`, the bundle shape
23
+ * `{ "servers": { ... } }`, or a bare `{ name: cfg }` map.
24
+ */
25
+ export function parseMcpServers(raw) {
26
+ const block =
27
+ (raw && typeof raw === "object" && (raw.mcpServers || raw.servers)) ||
28
+ raw ||
29
+ {};
30
+ const out = {};
31
+ for (const [name, cfg] of Object.entries(block)) {
32
+ if (!cfg || typeof cfg !== "object") continue;
33
+ out[name] = {
34
+ command: cfg.command,
35
+ args: Array.isArray(cfg.args) ? cfg.args : [],
36
+ env: cfg.env && typeof cfg.env === "object" ? cfg.env : {},
37
+ url: cfg.url,
38
+ transport: cfg.transport,
39
+ headers: cfg.headers && typeof cfg.headers === "object" ? cfg.headers : {},
40
+ };
41
+ }
42
+ return out;
43
+ }
44
+
45
+ /** Namespaced tool name exposed to the LLM. */
46
+ export function mcpToolName(server, tool) {
47
+ return `mcp__${server}__${tool}`;
48
+ }
49
+
50
+ /**
51
+ * Connect the given servers and build the agent-loop wiring. Connection
52
+ * failures are reported (writeErr) but never abort the run — a broken server
53
+ * just contributes no tools.
54
+ *
55
+ * @param {object} servers `{ name: { command|url, args, env, transport, headers } }`
56
+ * @param {object} [deps] { writeErr, createClient }
57
+ * @returns {Promise<{mcpClient, extraToolDefinitions, externalToolExecutors,
58
+ * externalToolDescriptors, connected}>}
59
+ */
60
+ export async function setupMcpFromConfig(servers, deps = {}) {
61
+ const writeErr = deps.writeErr || (() => {});
62
+ const createClient = deps.createClient || (() => new MCPClient());
63
+
64
+ const mcpClient = createClient();
65
+ const extraToolDefinitions = [];
66
+ const externalToolExecutors = {};
67
+ const externalToolDescriptors = {};
68
+ const connected = [];
69
+
70
+ for (const [name, cfg] of Object.entries(servers)) {
71
+ let result;
72
+ try {
73
+ result = await mcpClient.connect(name, cfg);
74
+ } catch (err) {
75
+ writeErr(` mcp: failed to connect "${name}": ${err.message}\n`);
76
+ continue;
77
+ }
78
+ const tools = Array.isArray(result?.tools) ? result.tools : [];
79
+ connected.push({ server: name, tools: tools.length });
80
+ for (const t of tools) {
81
+ if (!t || !t.name) continue;
82
+ const full = mcpToolName(name, t.name);
83
+ extraToolDefinitions.push({
84
+ type: "function",
85
+ function: {
86
+ name: full,
87
+ description: t.description || `MCP tool "${t.name}" on server "${name}"`,
88
+ parameters: t.inputSchema || { type: "object", properties: {} },
89
+ },
90
+ });
91
+ externalToolExecutors[full] = {
92
+ kind: "mcp",
93
+ serverName: name,
94
+ toolName: t.name,
95
+ };
96
+ externalToolDescriptors[full] = {
97
+ name: full,
98
+ kind: "mcp",
99
+ category: "mcp",
100
+ source: name,
101
+ };
102
+ }
103
+ }
104
+
105
+ return {
106
+ mcpClient,
107
+ extraToolDefinitions,
108
+ externalToolExecutors,
109
+ externalToolDescriptors,
110
+ connected,
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Read + parse a `--mcp-config` file and connect its servers.
116
+ * Throws on an unreadable/empty config (fail fast — the user asked for MCP).
117
+ *
118
+ * @param {string} filePath
119
+ * @param {object} [deps] { writeErr, createClient, readFile }
120
+ */
121
+ export async function loadMcpConfig(filePath, deps = {}) {
122
+ const readFile = deps.readFile || ((p) => fs.readFileSync(p, "utf-8"));
123
+ let raw;
124
+ try {
125
+ raw = JSON.parse(readFile(filePath));
126
+ } catch (err) {
127
+ throw new Error(
128
+ `--mcp-config: cannot read/parse "${filePath}": ${err.message}`,
129
+ );
130
+ }
131
+ const servers = parseMcpServers(raw);
132
+ if (Object.keys(servers).length === 0) {
133
+ throw new Error(
134
+ `--mcp-config: no servers found in "${filePath}" ` +
135
+ `(expected {"mcpServers": {"name": {"command": "..."}}}).`,
136
+ );
137
+ }
138
+ return setupMcpFromConfig(servers, deps);
139
+ }
140
+
141
+ // ─── --permission-prompt-tool (programmable headless approval) ──────────────
142
+ //
143
+ // Claude-Code parity: instead of headless fail-closed (auto-deny risky tools),
144
+ // route every CONFIRM-tier decision to an MCP tool that returns the verdict.
145
+ // The named tool must come from a server loaded via --mcp-config.
146
+
147
+ /**
148
+ * Resolve a `mcp__<server>__<tool>` permission-prompt-tool name to its server +
149
+ * tool, validating it was actually loaded. Throws (fail fast) otherwise.
150
+ */
151
+ export function resolvePermissionPromptTool(mcp, toolName) {
152
+ if (!mcp || !mcp.externalToolExecutors) {
153
+ throw new Error(
154
+ `--permission-prompt-tool "${toolName}" requires --mcp-config ` +
155
+ `(the tool must come from a loaded MCP server).`,
156
+ );
157
+ }
158
+ const exec = mcp.externalToolExecutors[toolName];
159
+ if (!exec || exec.kind !== "mcp") {
160
+ const avail = Object.keys(mcp.externalToolExecutors).join(", ") || "(none)";
161
+ throw new Error(
162
+ `--permission-prompt-tool "${toolName}" not found among loaded MCP ` +
163
+ `tools. Available: ${avail}`,
164
+ );
165
+ }
166
+ return { server: exec.serverName, tool: exec.toolName };
167
+ }
168
+
169
+ /**
170
+ * Interpret an MCP `tools/call` result as an allow/deny verdict. Liberal: reads
171
+ * a JSON `{behavior:"allow"|"deny"}` (Claude-Code shape) from a text content
172
+ * block, or a top-level `behavior`/`decision`/`allow`. Anything not clearly an
173
+ * allow is treated as deny (fail-closed).
174
+ */
175
+ export function parsePermissionDecision(result) {
176
+ if (!result || result.isError) {
177
+ return { allow: false, reason: "permission tool returned no/err result" };
178
+ }
179
+ let payload = result;
180
+ if (Array.isArray(result.content)) {
181
+ const textBlock = result.content.find(
182
+ (b) => b && b.type === "text" && typeof b.text === "string",
183
+ );
184
+ if (textBlock) {
185
+ try {
186
+ payload = JSON.parse(textBlock.text);
187
+ } catch {
188
+ payload = { behavior: textBlock.text.trim() };
189
+ }
190
+ }
191
+ }
192
+ const behavior =
193
+ payload?.behavior ??
194
+ payload?.decision ??
195
+ (payload?.allow === true ? "allow" : undefined);
196
+ const allow = behavior === "allow" || payload?.allow === true;
197
+ return {
198
+ allow,
199
+ reason: payload?.message || payload?.reason || null,
200
+ updatedInput: payload?.updatedInput,
201
+ };
202
+ }
203
+
204
+ /**
205
+ * Build an ApprovalGate confirmer that defers each CONFIRM-tier decision to the
206
+ * given MCP tool. Fail-closed: any tool error → deny.
207
+ *
208
+ * @param {object} args { mcpClient, server, tool, writeErr?, isText? }
209
+ * @returns {(ctx:{tool:string,args:object})=>Promise<boolean>}
210
+ */
211
+ export function makePermissionPromptConfirmer({
212
+ mcpClient,
213
+ server,
214
+ tool,
215
+ writeErr = () => {},
216
+ isText = false,
217
+ }) {
218
+ return async (ctx) => {
219
+ try {
220
+ const result = await mcpClient.callTool(server, tool, {
221
+ tool_name: ctx?.tool,
222
+ input: ctx?.args || {},
223
+ });
224
+ const { allow, reason } = parsePermissionDecision(result);
225
+ if (isText) {
226
+ writeErr(
227
+ ` permission(${ctx?.tool}): ${allow ? "allow" : "deny"}` +
228
+ `${reason ? " — " + reason : ""}\n`,
229
+ );
230
+ }
231
+ return allow;
232
+ } catch (err) {
233
+ if (isText) {
234
+ writeErr(` permission(${ctx?.tool}): deny (tool error: ${err.message})\n`);
235
+ }
236
+ return false; // fail-closed
237
+ }
238
+ };
239
+ }
@@ -33,6 +33,7 @@ export function resolveAgentPolicy({
33
33
  systemPrompt: overrides.systemPrompt || null,
34
34
  appendSystemPrompt: overrides.appendSystemPrompt || null,
35
35
  fallbackModel: overrides.fallbackModel || null,
36
+ mcpConfig: overrides.mcpConfig || null,
36
37
  };
37
38
  }
38
39
 
@@ -1 +0,0 @@
1
- import{I as v,P as u,J as S,U as s,R as a,S as y,K as C,Q as x,V as w,_ as B,b as n}from"./vendor-BvqAck49.js";import{_ as k}from"./index-BItcSqan.js";import"./icons-DP3uiYxy.js";const M={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=n(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=n(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=n(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=n(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=n(()=>{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:n};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},N={class:"bubble"},T={class:"meta"},R={class:"actor"},V={class:"time"},q={class:"body"};function D(c,d,t,r,i,l){const o=v("a-tag");return u(),S("div",{class:B(["chat-row",{mine:r.isMine}])},[s("div",N,[s("div",T,[s("span",R,a(r.actorLabel),1),s("span",V,a(r.formattedTime),1)]),s("div",q,a(r.messageText),1),t.event.source.adapter?(u(),y(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(M,[["render",D],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-v2hnMt/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-BItcSqan.js";import{a7 as M,M as y}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 y},get FolderOutlined(){return M}};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-v2hnMt/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-BItcSqan.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),U=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"}],N=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,U.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);U.value=Array.isArray(f?.files)?f.files:[]}catch{U.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:""}),h=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:""},h.value=!0}async function M(){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);U.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 M(),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}'`),h.value=!1,await M(),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 M(),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 M()):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:U,filesLoading:k,createOpen:E,creating:L,newProject:F,columns:z,countByStatus:N,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:h,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:M,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"}},he={class:"page-title"},Ae={class:"page-sub"},Ie={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},Ue={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"),U=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"),N=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"),h=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",he,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(U,{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",Ue,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(N,{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(N,{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(h,{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(h,{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(h,{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(h,{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-v2hnMt/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
@@ -1 +0,0 @@
1
- import{E as B,b as z,r as D,I as p,J as c,U as _,c as n,K as a,S as T,V as w,o as P,x as I,P as i,Q as g,R as r,F as h,Z as F}from"./vendor-BvqAck49.js";import{u as R,_ as O}from"./index-BItcSqan.js";import{R as E}from"./icons-DP3uiYxy.js";const V=B("tasks",()=>{const k=D([]),l=D(!1);let u=null,e=null;const x=z(()=>k.value.filter(t=>t.status==="running")),b=z(()=>k.value.filter(t=>t.status==="pending")),y=z(()=>k.value.filter(t=>t.status==="completed"||t.status==="failed"||t.status==="timeout"));async function f(){const t=R();l.value=!0;try{const s=await t.sendRaw({type:"tasks-list"});s&&Array.isArray(s.tasks)&&(k.value=s.tasks)}catch{}finally{l.value=!1}}async function o(t){const s=R();try{await s.sendRaw({type:"tasks-stop",taskId:t})}catch{}finally{await f()}}const d=D(null);function m(t=5e3){v(),f(),u=setInterval(f,t),C()}function v(){u&&(clearInterval(u),u=null),e&&(e(),e=null)}function C(){const t=R();if(e)return;const s=S=>{S.type==="task:notification"&&S.payload?.task&&(d.value=S.payload.task,f(),setTimeout(()=>{d.value=null},8e3))};e=t.onRuntimeEvent(s)}function N(t){return!t||t<0?"-":t<1e3?`${t}ms`:t<6e4?`${(t/1e3).toFixed(1)}s`:`${(t/6e4).toFixed(1)}m`}function A(t){switch(t){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:k,loading:l,running:x,pending:b,completed:y,lastNotification:d,fetchTasks:f,stopTask:o,startPolling:m,stopPolling:v,formatDuration:N,getStatusColor:A}}),U={__name:"Tasks",setup(k,{expose:l}){l();const u=V(),e=[{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 x(o){return o.status==="running"&&o.startedAt?u.formatDuration(Date.now()-o.startedAt):o.completedAt&&o.startedAt?u.formatDuration(o.completedAt-o.startedAt):"-"}function b(o){return o?new Date(o).toLocaleString():"-"}function y(o,d){return o?o.length>d?`${o.slice(0,d)}...`:o:""}P(()=>u.startPolling(5e3)),I(()=>u.stopPolling());const f={store:u,columns:e,getDuration:x,formatTime:b,truncate:y,onMounted:P,onUnmounted:I,get ReloadOutlined(){return E},get useTasksStore(){return V}};return Object.defineProperty(f,"__isScriptSetup",{enumerable:!1,value:!0}),f}},L={class:"page-header"},M={key:0,class:"error-text"},j={key:1},J={class:"task-header"},K={class:"task-desc"},Q={class:"task-id"},W={class:"task-meta"},Z=["title"],q={key:0,class:"error-text"},G={key:1,class:"success-text"},H={key:2,class:"muted-text"};function X(k,l,u,e,x,b){const y=p("a-button"),f=p("a-space"),o=p("a-alert"),d=p("a-statistic"),m=p("a-card"),v=p("a-col"),C=p("a-row"),N=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(f,null,{default:a(()=>[n(y,{ghost:"",loading:e.store.loading,onClick:l[0]||(l[0]=t=>e.store.fetchTasks())},{icon:a(()=>[n(e.ReloadOutlined)]),default:a(()=>[l[2]||(l[2]=g(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.store.lastNotification?(i(),T(o,{key:0,type:e.store.lastNotification.status==="completed"?"success":"error","show-icon":"",closable:"",class:"banner",onClose:l[1]||(l[1]=t=>e.store.lastNotification=null)},{message:a(()=>[g(" 任务"+r(e.store.lastNotification.status==="completed"?"完成":"结束")+": "+r(e.store.lastNotification.description||e.store.lastNotification.id.slice(0,16)),1)]),description:a(()=>[e.store.lastNotification.error?(i(),c("span",M,r(e.store.lastNotification.error),1)):e.store.lastNotification.result?(i(),c("span",j,r(e.truncate(String(e.store.lastNotification.result),120)),1)):w("v-if",!0)]),_:1},8,["type"])):w("v-if",!0),n(C,{gutter:[16,16],class:"stats-row"},{default:a(()=>[n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"全部任务",value:e.store.tasks.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"运行中",value:e.store.running.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"等待中",value:e.store.pending.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"已完成",value:e.store.completed.length},null,8,["value"])]),_:1})]),_:1})]),_:1}),e.store.running.length>0?(i(),T(m,{key:1,title:"运行中的任务",class:"panel-card",size:"small"},{default:a(()=>[(i(!0),c(h,null,F(e.store.running,t=>(i(),c("div",{key:t.id,class:"task-item running"},[_("div",J,[n(N,{color:e.store.getStatusColor(t.status)},{default:a(()=>[g(r(t.status.toUpperCase()),1)]),_:2},1032,["color"]),_("span",K,r(t.description),1),_("span",Q,r(t.id.slice(0,16)),1)]),_("div",W,[_("span",null,"类型: "+r(t.type||"-"),1),_("span",null,"已运行: "+r(e.store.formatDuration(Date.now()-t.startedAt)),1),n(y,{size:"small",danger:"",onClick:s=>e.store.stopTask(t.id)},{default:a(()=>[...l[4]||(l[4]=[g("停止",-1)])]),_:1},8,["onClick"])])]))),128))]),_:1})):w("v-if",!0),n(m,{class:"panel-card"},{default:a(()=>[n(A,{columns:e.columns,"data-source":e.store.tasks,pagination:{pageSize:15,size:"small"},loading:e.store.loading,"row-key":"id",size:"small"},{bodyCell:a(({column:t,record:s})=>[t.key==="status"?(i(),T(N,{key:0,color:e.store.getStatusColor(s.status)},{default:a(()=>[g(r(s.status),1)]),_:2},1032,["color"])):t.key==="description"?(i(),c("span",{key:1,title:s.command},r(s.description),9,Z)):t.key==="duration"?(i(),c(h,{key:2},[g(r(e.getDuration(s)),1)],64)):t.key==="createdAt"?(i(),c(h,{key:3},[g(r(e.formatTime(s.createdAt)),1)],64)):t.key==="result"?(i(),c(h,{key:4},[s.error?(i(),c("span",q,r(e.truncate(s.error,60)),1)):s.result?(i(),c("span",G,r(e.truncate(String(s.result),60)),1)):(i(),c("span",H,"-"))],64)):t.key==="action"?(i(),c(h,{key:5},[s.status==="running"?(i(),T(y,{key:0,size:"small",danger:"",onClick:S=>e.store.stopTask(s.id)},{default:a(()=>[...l[5]||(l[5]=[g(" 停止 ",-1)])]),_:1},8,["onClick"])):w("v-if",!0)],64)):w("v-if",!0)]),_:1},8,["data-source","loading"])]),_:1})])}const et=O(U,[["render",X],["__scopeId","data-v-da5ff6a2"],["__file","/tmp/cc-web-panel-v2hnMt/repo/packages/web-panel/src/views/Tasks.vue"]]);export{et as default};
@@ -1 +0,0 @@
1
- import{O as r}from"./index-BItcSqan.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-Zb-EjmgQ.js";import{U as t}from"./index-BItcSqan.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-BB_A8dBt.js";import"./useFlexGapSupport-BCIMPfq9.js";import"./styleChecker-vXAYhhjz.js";import"./index-CyJpmSHZ.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-D3DnfExY.js";import{U as t}from"./index-BItcSqan.js";import"./vendor-BvqAck49.js";import"./index-CyJpmSHZ.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};