chainlesschain 0.162.71 → 0.162.73

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 (176) hide show
  1. package/package.json +3 -2
  2. package/src/assets/web-panel/assets/{AIOps-pes7_jGr.js → AIOps-DTI_-iZ_.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DiHWdeH1.js → ActionButton-CtpbGicW.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-C51UX-V_.js → Analytics-C1HwMd7E.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BE6LJLw9.js → AppLayout-Db953rqB.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-CtTkLTe2.js → Audit-CuIi9Vup.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-lmpVwPxc.js → Backup-DwR7Wlve.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-Dr7DR1E1.js → BaseInput-B5wNMp7S.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-DXph6klA.js → Chat-DivalHgk.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-RefrXxqp.js → ChatBubbleRenderer-BwPSr02C.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-BF0aS5R9.js → Checkbox-CJrXPCJH.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-B-oHWNTV.js → Codegen-BieZvOkC.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-B6KdyRTE.js → Col-BzvPsQgb.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-D5ac0KyO.js → Community-CWcAMlpQ.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-Dc61O2eQ.js → Compact-Bj_BLBpw.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-a48qvNmd.js → Compliance-DKvo0WAi.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-CIF9lSRj.js → Cowork-DRajk8JO.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-C_gkf4xd.js → Cron-DPz9MoUo.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-CJt15PzW.js → Crosschain-BpSuvmns.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-D8I_okEj.js → DID-Co98G00H.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-O4q-qCF2.js → Dashboard-8TSG0W7f.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-flRziiaw.js → Dropdown-CKViu7w3.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-CnnkfGPw.js → EmailListRenderer-BqfdADvJ.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CYAJpGqd.js → FamilyGuardDashboard-aWu1imGZ.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-Dm3WqzQ_.js → Federation-w4YpT8EN.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-CpAIter6.js → FormItemContext-CAk4CXid.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-ChzXcyuN.js → GenericCardRenderer-MoJw4J2L.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-DElmMsL4.js → Git-HNU_a9Jz.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-EWmgn9io.js → Governance-BkIXWYUS.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-VtOR_sef.js → Inference-CnquB88h.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-OMqlGkMR.js → KnowledgeGraph-PGSMF-uq.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-CTgYDsTZ.js → Logs-DCc-nYzu.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-DZIUTbn8.js → Marketplace-CyGX8XEt.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-DWeOErCA.js → McpTools-DBkZ5yUL.js} +4 -4
  35. package/src/assets/web-panel/assets/{Memory-DwFBp-ev.js → Memory-DmYLRCwo.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-D42xBfE3.js → MobileBridge-CszJjeNc.js} +2 -2
  37. package/src/assets/web-panel/assets/{MobileProjects-BHCHauUl.js → MobileProjects-DWgtDsta.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-CabnNsyS.js → Mtc-Bmt_Pmg4.js} +3 -3
  39. package/src/assets/web-panel/assets/{MtcAudit-Ddx9Awu5.js → MtcAudit-BmG0ys0l.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-CJpYBZ8f.js → Multisig-DNd5iMmD.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-BvPJskVG.js → NLProgramming-yxbNl09B.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-92ELvJM2.js → Notes-CQ0qAzI4.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-CXz0SUzP.js → NotificationSettings-CIzkE4ao.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-4iWRkMr-.js → OrderTableRenderer-e1VMUxTi.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-DblqJPeY.js → Organization-BNBIlf_R.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-CHfS3HwD.js → Overflow-C5GzzJTq.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-DIg0pLIG.js → P2P-DjL2jIED.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-BhD3DGjk.js → PdhVaultBrowser-C2EYDmpW.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-Ct7bwrz8.js → Permissions-BVGCXxDp.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-DG9c1eas.js → PersonalDataHub-B1xBro16.js} +4 -4
  51. package/src/assets/web-panel/assets/{Pipeline-BwQnEqG0.js → Pipeline-DIYWiDnt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-BvWaf-Ba.js → Privacy--Qx3QdO1.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-BFzMHtiW.js → ProjectInit-DYOEcV04.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-DDpokSpH.js → ProjectSettings-BcOx5-KS.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-3IL8lyPl.js → Projects-CO69txk4.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-C6BsEzSR.js → Providers-Bj8pCgzo.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-Mh6690Ey.js → QuickAsk-Cukpq-4s.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-CJbZ6wgA.js → Recommend-DJB5wUfM.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-GDcyl6iQ.js → Reputation-B9t0-nT0.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-6p4DKFSi.js → Row-4cniRgxC.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-BLhrkoDq.js → RssFeed-Y4db_T9t.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-Ckiyt35t.js → Search-DggZDzlc.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-qhh-B5Qt.js → Security-C67A6kED.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-D7a2OwKm.js → Services-BocBjvaa.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-CSMxupKd.js → Skeleton-C9jI-iOy.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-CGpMng8w.js → Skills-2baFHKOW.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-CYtaU3Ar.js → Sla-CnowXeRb.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-BTCsu1uM.js → SpeechSettings-DWGBkmUt.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-Cnzx2L5I.js → SyncSettings-B89qwCgX.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-C1_WvNc0.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-Ccdx_C3w.js → Templates-P8dBhbxa.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-ZN8c86j3.js → Tenant-DHo0pxrm.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-Dr-HvjH-.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-CjgirE9d.js → TimelineRenderer-DM7dOaUR.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-QoRpi6Wf.js → Tokens-DnJxqOPM.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-CEQKJkhs.js → Trigger-C-FLgMzr.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-UTuAzV1q.js → Trust-CIT_RVqA.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-JDs9I7fl.js → UkeySign-Cg9VS6y6.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-BACYQQSd.js → VideoEditing-BzoxE8mA.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-C-SKluhH.js → Wallet-ZkmCII8R.js} +3 -3
  81. package/src/assets/web-panel/assets/{WebAuthn-9chizTFy.js → WebAuthn-CptQdp3u.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-0mF-LAUo.js → WorkflowEditor-Vkz28khO.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-Di7QINiP.js → chat-DXdmvvEA.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-SBmhHMM9.js → colors-De7FCj5l.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BmbETbNj.js → compact-item-DnT3XzME.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-C7hFnsJ7.js → createContext-ECZfCCqd.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-gaA8VqZf.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-CFtthKDD.js → hasIn-Uodg6pAt.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-DRBc1Ewn.js → index-1dWvOqru.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-WjZVyLn7.js → index-BC8SOuGi.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-CovTrPpI.js → index-BUMNJRCl.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-CSnTUPQx.js → index-Bg1RsfAJ.js} +3 -3
  93. package/src/assets/web-panel/assets/{index-NxxQTlPJ.js → index-Blo85ZKd.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-ClIp4Vin.js → index-BtJ8BHU0.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B4etIqbf.js → index-C01WM7Pk.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DWfObC0n.js → index-C4KhsGXo.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-sz0w-D-C.js → index-C6JgjkY7.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-lRVjtXeH.js → index-C9_Cnvha.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BCcCs7LJ.js → index-CCguvASR.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C6tZzsb9.js → index-CLzPxAp4.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-D0yO3vWh.js → index-CMuqxCVw.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BcawAm_i.js → index-COTabJQd.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-Cib-RTws.js → index-CPjI3AGE.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C07kpleB.js → index-CaDZ-LMg.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DEYnWiq1.js → index-CbbfcGeJ.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CgXQwqXr.js → index-CcLDjTgI.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-C2CN7coN.js → index-CffZBdA1.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-PN02VlUB.js → index-CwXP0KcT.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-_hO8-EnW.js → index-D2YOclGO.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Dk4ez5rf.js → index-DBsl2SuZ.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-D6vNUp6c.js → index-DCvmjxu9.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-sA4vr5WV.js → index-DGwgEqwl.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DI2xH1fU.js → index-DOIeo8Qs.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-_a2NG3iP.js → index-DPcpxSQt.js} +1 -1
  115. package/src/assets/web-panel/assets/index-DTpmiTGK.js +1 -0
  116. package/src/assets/web-panel/assets/{index-CWDk3nDZ.js → index-Db33l8Ix.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CNpb8m5a.js → index-Dbfj4QL5.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dww6gCzI.js → index-Dd9Bx3tJ.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bpo7UVJe.js → index-Dkvf5upf.js} +1 -1
  120. package/src/assets/web-panel/assets/index-DwpvMYUU.js +1 -0
  121. package/src/assets/web-panel/assets/{index-BT2uOwmA.js → index-Dy0AT-uc.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C2fhXmhW.js → index-FU8Zo5cp.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BcRTX_WO.js → index-JVwNC4yP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-Dps9xdE8.js → index-JqSxr1A7.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-D134XFWR.js → index-KV6dXwKC.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D8CeUlN0.js → index-LwNszM-5.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CcBhsVYn.js → index-cHnmjGqB.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-B1zCwkvT.js → initDefaultProps-B3H1sf95.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-BDGIV9KA.js → motion-DreYO5eb.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-BITqgluK.js → move-B0OVU04M.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-uD97QKBF.js → omit-PcEEXHLZ.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-CZpXhSIE.js → pickAttrs-DH6-hDkF.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-ByUvT_08.js → placementArrow-DFamUSEw.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-BQG9LlBs.js → responsiveObserve-DT1grAyh.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Bx9TyeEE.js → slide-41lCsY6d.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-XWaMqYM8.js → statusUtils-FzJ7j2T7.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-BZ-nMyDB.js → styleChecker-D0Zvn50h.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-D_iwA3vx.js → useFlexGapSupport-BTxsJE5n.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-DuvW_aRX.js → useFs-DRVttEr3.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-BO7orS0d.js → usePersonalDataHub-BSe7NVv0.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-Cc_fqAL4.js → vnode-D8O7tUXh.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-BGkBp90M.js → zoom-CMQc1RZ4.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +12 -0
  145. package/src/commands/cowork.js +8 -0
  146. package/src/commands/crosschain.js +32 -4
  147. package/src/commands/init.js +10 -10
  148. package/src/commands/loop.js +9 -3
  149. package/src/commands/memory.js +6 -4
  150. package/src/commands/orchestrate.js +5 -2
  151. package/src/commands/video.js +5 -1
  152. package/src/lib/agents.js +16 -5
  153. package/src/lib/cowork-workflow.js +357 -136
  154. package/src/lib/micro-compact.js +52 -0
  155. package/src/lib/output-styles.js +41 -7
  156. package/src/lib/permission-rules.cjs +39 -0
  157. package/src/lib/project-root.cjs +87 -0
  158. package/src/lib/settings-hooks.cjs +18 -6
  159. package/src/lib/settings-loader.cjs +12 -5
  160. package/src/lib/skill-loader.js +62 -43
  161. package/src/lib/slash-commands.js +18 -2
  162. package/src/repl/agent-repl.js +228 -20
  163. package/src/repl/chat-repl.js +4 -2
  164. package/src/repl/permission-tier.js +60 -0
  165. package/src/repl/stream-decision.js +16 -0
  166. package/src/repl/think-command.js +36 -0
  167. package/src/runtime/agent-core.js +67 -10
  168. package/src/runtime/file-ref-expander.js +209 -18
  169. package/src/runtime/headless-runner.js +3 -3
  170. package/src/runtime/headless-stream.js +16 -3
  171. package/src/runtime/mcp-config.js +78 -1
  172. package/src/assets/web-panel/assets/Tasks-BhnGtqaZ.js +0 -1
  173. package/src/assets/web-panel/assets/Terminal-BfgM0oyN.js +0 -3
  174. package/src/assets/web-panel/assets/devWarning-gNvbyy4j.js +0 -1
  175. package/src/assets/web-panel/assets/index-BNXpMnIY.js +0 -1
  176. package/src/assets/web-panel/assets/index-gfHxqT1Q.js +0 -1
@@ -38,11 +38,51 @@ function looksPathLike(raw) {
38
38
  return /[\\/]/.test(raw) || /\.[A-Za-z0-9]+$/.test(raw);
39
39
  }
40
40
 
41
+ /** Whether a resolved path is a PDF (text extraction is async, opt-in). */
42
+ function isPdf(p) {
43
+ return /\.pdf$/i.test(String(p || ""));
44
+ }
45
+
41
46
  /** Strip trailing sentence punctuation that is unlikely to be part of a path. */
42
47
  function trimTrailingPunct(raw) {
43
48
  return raw.replace(/[),;:!?'".]+$/g, "");
44
49
  }
45
50
 
51
+ /**
52
+ * Split a token into its path and an optional trailing line range — Claude-Code
53
+ * `@file#L5-10` parity. Accepts `#L5-10`, `#5-10`, `#L5`, `#5` (1-based,
54
+ * inclusive). Returns `{ path, start, end }`, or null when there is no valid
55
+ * range suffix (so plain `@path` falls through to whole-file expansion).
56
+ */
57
+ export function parseLineRange(raw) {
58
+ const m = /^(.+?)#[Ll]?(\d+)(?:-(\d+))?$/.exec(String(raw || ""));
59
+ if (!m) return null;
60
+ const start = parseInt(m[2], 10);
61
+ if (!Number.isFinite(start) || start < 1) return null;
62
+ let end = m[3] != null ? parseInt(m[3], 10) : start;
63
+ if (!Number.isFinite(end) || end < start) end = start;
64
+ return { path: m[1], start, end };
65
+ }
66
+
67
+ /**
68
+ * Take lines [start, end] (1-based, inclusive) from `content`, clamped to the
69
+ * file, then cap the slice at `maxBytes`. Returns the text plus the actual
70
+ * (clamped) line bounds and whether the byte cap truncated it.
71
+ */
72
+ function sliceLines(content, start, end, maxBytes) {
73
+ const lines = content.split("\n");
74
+ const total = lines.length;
75
+ const s = Math.max(1, Math.min(start, total));
76
+ const e = Math.min(Math.max(end, s), total);
77
+ let text = lines.slice(s - 1, e).join("\n");
78
+ let truncated = false;
79
+ if (Buffer.byteLength(text, "utf-8") > maxBytes) {
80
+ text = text.slice(0, maxBytes);
81
+ truncated = true;
82
+ }
83
+ return { text, start: s, end: e, truncated };
84
+ }
85
+
46
86
  /**
47
87
  * Find unique `@path` candidates in the text, in first-seen order.
48
88
  * @returns {Array<{raw:string}>}
@@ -81,7 +121,10 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
81
121
  if (trimmed && trimmed !== raw) candidates.push(trimmed);
82
122
 
83
123
  for (const cand of candidates) {
84
- const abs = path.resolve(cwd, cand);
124
+ // `@path#L5-10` resolve the bare path, slice the lines below.
125
+ const range = parseLineRange(cand);
126
+ const fsPath = range ? range.path : cand;
127
+ const abs = path.resolve(cwd, fsPath);
85
128
  let stat;
86
129
  try {
87
130
  stat = fs.statSync(abs);
@@ -89,6 +132,7 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
89
132
  continue; // not this candidate
90
133
  }
91
134
  if (stat.isDirectory()) {
135
+ // A line range on a directory is meaningless — ignore it and list the dir.
92
136
  let entries;
93
137
  try {
94
138
  entries = fs.readdirSync(abs, { withFileTypes: true });
@@ -96,7 +140,7 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
96
140
  return {
97
141
  kind: "error",
98
142
  raw: cand,
99
- rel: cand,
143
+ rel: fsPath,
100
144
  message: `cannot read directory: ${err.message}`,
101
145
  };
102
146
  }
@@ -108,7 +152,7 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
108
152
  return {
109
153
  kind: "dir",
110
154
  raw: cand,
111
- rel: cand,
155
+ rel: fsPath,
112
156
  entries: names,
113
157
  total: entries.length,
114
158
  truncated,
@@ -122,18 +166,46 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
122
166
  return {
123
167
  kind: "error",
124
168
  raw: cand,
125
- rel: cand,
169
+ rel: fsPath,
126
170
  message: `cannot read file: ${err.message}`,
127
171
  };
128
172
  }
173
+ if (isPdf(fsPath)) {
174
+ // PDF text extraction is async (pdf-parse). Return a deferred marker
175
+ // carrying the bytes + requested page range; expandFileRefsAsync fills
176
+ // in `content`. The sync path renders it as a note (no extraction).
177
+ return {
178
+ kind: "pdf",
179
+ raw: cand,
180
+ rel: fsPath,
181
+ buf,
182
+ bytes: stat.size,
183
+ pageStart: range ? range.start : null,
184
+ pageEnd: range ? range.end : null,
185
+ };
186
+ }
129
187
  if (looksBinary(buf)) {
130
188
  return {
131
189
  kind: "binary",
132
190
  raw: cand,
133
- rel: cand,
191
+ rel: fsPath,
134
192
  bytes: stat.size,
135
193
  };
136
194
  }
195
+ if (range) {
196
+ // Slice the requested lines (clamped to the file), then byte-cap them.
197
+ const sl = sliceLines(buf.toString("utf-8"), range.start, range.end, maxBytes);
198
+ return {
199
+ kind: "file",
200
+ raw: cand,
201
+ rel: fsPath,
202
+ bytes: stat.size,
203
+ content: sl.text,
204
+ truncated: sl.truncated,
205
+ lineStart: sl.start,
206
+ lineEnd: sl.end,
207
+ };
208
+ }
137
209
  const truncated = buf.length > maxBytes;
138
210
  const content = (truncated ? buf.slice(0, maxBytes) : buf).toString(
139
211
  "utf-8",
@@ -141,7 +213,7 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
141
213
  return {
142
214
  kind: "file",
143
215
  raw: cand,
144
- rel: cand,
216
+ rel: fsPath,
145
217
  bytes: stat.size,
146
218
  content,
147
219
  truncated,
@@ -164,15 +236,23 @@ function renderBlock(refs) {
164
236
  ];
165
237
  for (const ref of refs) {
166
238
  if (ref.kind === "file") {
239
+ const lineAttr = ref.lineStart
240
+ ? ` lines="${ref.lineStart}-${ref.lineEnd}"`
241
+ : "";
167
242
  const attrs =
168
243
  `path="${escapeAttr(ref.rel)}" bytes="${ref.bytes}"` +
244
+ lineAttr +
169
245
  (ref.truncated
170
246
  ? ` truncated="true" shown-bytes="${DEFAULT_MAX_BYTES}"`
171
247
  : "");
172
248
  parts.push(`<file ${attrs}>`);
173
249
  parts.push(ref.content);
174
250
  if (ref.truncated) {
175
- parts.push(`\n… [truncated — file is ${ref.bytes} bytes]`);
251
+ parts.push(
252
+ ref.lineStart
253
+ ? `\n… [truncated — line range exceeds ${DEFAULT_MAX_BYTES} bytes]`
254
+ : `\n… [truncated — file is ${ref.bytes} bytes]`,
255
+ );
176
256
  }
177
257
  parts.push("</file>");
178
258
  } else if (ref.kind === "dir") {
@@ -185,6 +265,30 @@ function renderBlock(refs) {
185
265
  parts.push(`… [truncated — ${ref.total} entries total]`);
186
266
  }
187
267
  parts.push("</dir>");
268
+ } else if (ref.kind === "pdf") {
269
+ if (typeof ref.content === "string") {
270
+ const pageAttr =
271
+ ref.pageStart != null ? ` pages="${ref.pageStart}-${ref.pageEnd}"` : "";
272
+ const attrs =
273
+ `path="${escapeAttr(ref.rel)}" bytes="${ref.bytes}" type="pdf"` +
274
+ pageAttr +
275
+ (ref.truncated
276
+ ? ` truncated="true" shown-bytes="${DEFAULT_MAX_BYTES}"`
277
+ : "");
278
+ parts.push(`<file ${attrs}>`);
279
+ parts.push(ref.content);
280
+ if (ref.truncated) {
281
+ parts.push(`\n… [truncated — PDF text exceeds ${DEFAULT_MAX_BYTES} bytes]`);
282
+ }
283
+ parts.push("</file>");
284
+ } else {
285
+ // Sync context (or extraction failed): no page text inlined.
286
+ const note =
287
+ ref.pdfNote || "PDF — page text not extracted in this context";
288
+ parts.push(
289
+ `<file path="${escapeAttr(ref.rel)}" bytes="${ref.bytes}" type="pdf" note="${escapeAttr(note)}" />`,
290
+ );
291
+ }
188
292
  } else if (ref.kind === "binary") {
189
293
  parts.push(
190
294
  `<file path="${escapeAttr(ref.rel)}" bytes="${ref.bytes}" binary="true" note="binary file — contents omitted" />`,
@@ -208,11 +312,8 @@ function renderBlock(refs) {
208
312
  * `prompt` is unchanged when nothing resolved; otherwise it is the
209
313
  * original text + a trailing `<referenced-files>` block.
210
314
  */
211
- export function expandFileRefs(prompt, opts = {}) {
212
- const text = typeof prompt === "string" ? prompt : "";
213
- if (!text || !text.includes("@")) {
214
- return { prompt: text, refs: [], warnings: [] };
215
- }
315
+ /** Resolve every @token to a ref (no rendering). Shared by sync + async. */
316
+ function _resolveAllRefs(text, opts) {
216
317
  const fs = opts.deps?.fs || fsDefault;
217
318
  const path = opts.deps?.path || pathDefault;
218
319
  const cwd = opts.cwd || process.cwd();
@@ -242,17 +343,107 @@ export function expandFileRefs(prompt, opts = {}) {
242
343
  }
243
344
  refs.push(ref);
244
345
  }
346
+ return { refs, warnings, maxBytes };
347
+ }
348
+
349
+ export function expandFileRefs(prompt, opts = {}) {
350
+ const text = typeof prompt === "string" ? prompt : "";
351
+ if (!text || !text.includes("@")) {
352
+ return { prompt: text, refs: [], warnings: [] };
353
+ }
354
+ const { refs, warnings } = _resolveAllRefs(text, opts);
355
+ if (refs.length === 0) {
356
+ return { prompt: text, refs: [], warnings };
357
+ }
358
+ return { prompt: `${text}\n\n${renderBlock(refs)}`, refs, warnings };
359
+ }
360
+
361
+ /**
362
+ * Async superset of {@link expandFileRefs} that ALSO extracts text from
363
+ * `@file.pdf` (optionally a page range, e.g. `@doc.pdf#1-3`). Needs the optional
364
+ * `pdf-parse` dependency; when it's absent each PDF ref degrades to a note and a
365
+ * warning (never throws). Used by the agent / REPL paths; the sync expandFileRefs
366
+ * leaves PDFs un-extracted.
367
+ */
368
+ export async function expandFileRefsAsync(prompt, opts = {}) {
369
+ const text = typeof prompt === "string" ? prompt : "";
370
+ if (!text || !text.includes("@")) {
371
+ return { prompt: text, refs: [], warnings: [] };
372
+ }
373
+ const { refs, warnings, maxBytes } = _resolveAllRefs(text, opts);
374
+ const extractPdf = opts.deps?.extractPdfPages || _extractPdfPages;
375
+
376
+ for (const ref of refs) {
377
+ if (ref.kind !== "pdf" || !ref.buf) continue;
378
+ try {
379
+ const out = await extractPdf(ref.buf, {
380
+ firstPage: ref.pageStart,
381
+ lastPage: ref.pageEnd,
382
+ maxBytes,
383
+ });
384
+ ref.content = String(out?.text || "");
385
+ ref.truncated = !!out?.truncated;
386
+ } catch (err) {
387
+ if (err && err.code === "PDF_LIB_MISSING") {
388
+ ref.pdfNote =
389
+ "PDF — install the optional `pdf-parse` dependency to extract page text";
390
+ warnings.push(
391
+ `@${ref.raw} — PDF extraction needs the optional \`pdf-parse\` dep (left as a reference)`,
392
+ );
393
+ } else {
394
+ ref.pdfNote = `PDF — could not extract text (${err?.message || "error"})`;
395
+ warnings.push(
396
+ `@${ref.raw} — PDF extraction failed: ${err?.message || "error"} (left as a reference)`,
397
+ );
398
+ }
399
+ }
400
+ delete ref.buf; // don't keep the raw bytes around once consumed
401
+ }
245
402
 
246
403
  if (refs.length === 0) {
247
404
  return { prompt: text, refs: [], warnings };
248
405
  }
406
+ return { prompt: `${text}\n\n${renderBlock(refs)}`, refs, warnings };
407
+ }
249
408
 
250
- const block = renderBlock(refs);
251
- return {
252
- prompt: `${text}\n\n${block}`,
253
- refs,
254
- warnings,
255
- };
409
+ /**
410
+ * Default PDF text extractor (optional `pdf-parse`). Returns
411
+ * `{ text, numpages, truncated }` for pages [firstPage, lastPage] (all pages
412
+ * when those are null), byte-capped at maxBytes. Throws code `PDF_LIB_MISSING`
413
+ * when the optional dependency is not installed.
414
+ */
415
+ async function _extractPdfPages(buffer, { firstPage, lastPage, maxBytes } = {}) {
416
+ let pdfParse;
417
+ try {
418
+ // pdf-parse's index.js runs debug code under ESM (no module.parent), so
419
+ // import the lib entry directly to avoid it.
420
+ const mod = await import("pdf-parse/lib/pdf-parse.js");
421
+ pdfParse = mod.default || mod;
422
+ } catch {
423
+ const e = new Error("pdf-parse not installed");
424
+ e.code = "PDF_LIB_MISSING";
425
+ throw e;
426
+ }
427
+ const data = await pdfParse(buffer, {
428
+ pagerender: (pageData) => {
429
+ const n = pageData && pageData.pageNumber;
430
+ if (typeof n === "number") {
431
+ if (firstPage && n < firstPage) return "";
432
+ if (lastPage && n > lastPage) return "";
433
+ }
434
+ return pageData.getTextContent().then((tc) =>
435
+ (tc.items || []).map((it) => it.str).join(" "),
436
+ );
437
+ },
438
+ });
439
+ let out = String(data?.text || "").trim();
440
+ let truncated = false;
441
+ const cap = Number.isFinite(maxBytes) ? maxBytes : DEFAULT_MAX_BYTES;
442
+ if (Buffer.byteLength(out, "utf-8") > cap) {
443
+ out = out.slice(0, cap);
444
+ truncated = true;
445
+ }
446
+ return { text: out, numpages: data?.numpages || 0, truncated };
256
447
  }
257
448
 
258
449
  export const _deps = { fs: fsDefault, path: pathDefault };
@@ -43,7 +43,7 @@ import {
43
43
  sessionExists as jsonlSessionExists,
44
44
  getLastSessionId as jsonlGetLastSessionId,
45
45
  } from "../harness/jsonl-session-store.js";
46
- import { expandFileRefs } from "./file-ref-expander.js";
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
49
  import { withQuietStdout } from "./quiet-stdout.js";
@@ -330,8 +330,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
330
330
  // cat-pipe. Opt out with `--no-file-refs` (options.expandFileRefs === false).
331
331
  let userContent = prompt;
332
332
  if (options.expandFileRefs !== false) {
333
- const doExpand = deps.expandFileRefs || expandFileRefs;
334
- const expanded = doExpand(prompt, { cwd });
333
+ const doExpand = deps.expandFileRefs || expandFileRefsAsync;
334
+ const expanded = await doExpand(prompt, { cwd });
335
335
  userContent = expanded.prompt;
336
336
  // Warnings (typo'd paths, unreadable files) go to stderr in every output
337
337
  // format so stdout stays a clean machine payload.
@@ -19,7 +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 { expandFileRefs } from "./file-ref-expander.js";
22
+ import { expandFileRefsAsync } from "./file-ref-expander.js";
23
23
  import {
24
24
  resolveAgentMcp,
25
25
  resolvePermissionPromptTool,
@@ -260,7 +260,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
260
260
  const input = deps.input || process.stdin;
261
261
  const runLoop = deps.agentLoop || coreAgentLoop;
262
262
  const doBootstrap = deps.bootstrap || bootstrap;
263
- const doExpand = deps.expandFileRefs || expandFileRefs;
263
+ const doExpand = deps.expandFileRefs || expandFileRefsAsync;
264
264
  const writeOut = deps.writeOut || ((s) => process.stdout.write(s));
265
265
  const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
266
266
  const emit = (obj) => writeOut(JSON.stringify(obj) + "\n");
@@ -578,6 +578,19 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
578
578
  },
579
579
  })
580
580
  : undefined,
581
+ // Extended-thinking reasoning deltas (Anthropic; only when thinking is on).
582
+ // Surfaced as a thinking_delta so consumers can render a dimmed/collapsed
583
+ // reasoning block — the visible half of the /think toggle.
584
+ onThinking: options.includePartialMessages
585
+ ? (thinking) =>
586
+ emit({
587
+ type: "stream_event",
588
+ event: {
589
+ type: "content_block_delta",
590
+ delta: { type: "thinking_delta", thinking },
591
+ },
592
+ })
593
+ : undefined,
581
594
  };
582
595
 
583
596
  // --max-budget-usd: a SESSION-WIDE USD spend cap across all turns. Folded
@@ -745,7 +758,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
745
758
  // @file expansion per user event (parity with single-turn headless).
746
759
  let userContent = parsed.text;
747
760
  if (options.expandFileRefs !== false) {
748
- const expanded = doExpand(parsed.text, { cwd });
761
+ const expanded = await doExpand(parsed.text, { cwd });
749
762
  userContent = expanded.prompt;
750
763
  for (const w of expanded.warnings) writeErr(` @ref: ${w}\n`);
751
764
  }
@@ -15,7 +15,9 @@
15
15
  */
16
16
 
17
17
  import fs from "fs";
18
+ import path from "path";
18
19
  import { MCPClient } from "../harness/mcp-client.js";
20
+ import { projectRootBase } from "../lib/project-root.cjs";
19
21
  import {
20
22
  discoverIdeServer,
21
23
  ideServerToMcpConfig,
@@ -375,10 +377,73 @@ export async function loadIdeMcp(opts = {}, deps = {}) {
375
377
  return out;
376
378
  }
377
379
 
380
+ /**
381
+ * Discover + connect a project-scoped `.mcp.json` (Claude-Code parity). Reads a
382
+ * `.mcp.json` from the git project root (walked up from cwd, same as the
383
+ * `.claude` config layers) and from cwd itself, merging their `mcpServers`
384
+ * (cwd wins on a name clash — closest wins). Best-effort: a missing / empty /
385
+ * malformed file contributes nothing and never throws.
386
+ *
387
+ * SECURITY: a checked-in `.mcp.json` can spawn arbitrary commands, so this layer
388
+ * is OPT-IN (default-off) — it only runs when explicitly enabled with
389
+ * `--project-mcp` / `CC_PROJECT_MCP=1` (truthy). When enabled, the servers it
390
+ * loads are announced via writeErr. Connected into `deps.into`, so an explicit
391
+ * `--mcp-config` server or a registered (`cc mcp add`) server WINS on a name
392
+ * clash (the first batch wins in setupMcpFromConfig).
393
+ *
394
+ * @param {object} opts { cwd?, env? }
395
+ * @param {object} [deps] { writeErr, into, readFile, fileExists, createClient }
396
+ */
397
+ export async function loadProjectMcp(opts = {}, deps = {}) {
398
+ const env = opts.env || process.env;
399
+ // Opt-in gate (default-off): only load a project `.mcp.json` when explicitly
400
+ // enabled — a checked-in file spawning commands in any cloned repo is a
401
+ // supply-chain risk, so the user must turn it on per run / per shell.
402
+ const flag = String(env.CC_PROJECT_MCP || "").toLowerCase();
403
+ if (flag !== "1" && flag !== "true") return deps.into || null;
404
+ const cwd = opts.cwd || process.cwd();
405
+ const readFile = deps.readFile || ((p) => fs.readFileSync(p, "utf-8"));
406
+ const fileExists = deps.fileExists || ((p) => fs.existsSync(p));
407
+ const writeErr = deps.writeErr || (() => {});
408
+
409
+ // Project-root `.mcp.json` (below cwd's), then cwd's own — so a cwd-local file
410
+ // overrides the root on a name clash. projectRootBase() is null when cwd IS
411
+ // the root (its own file already covers it) or there is no git project.
412
+ const files = [];
413
+ const root = projectRootBase(cwd, { fs, path });
414
+ if (root) files.push(path.join(root, ".mcp.json"));
415
+ files.push(path.join(cwd, ".mcp.json"));
416
+
417
+ const servers = {};
418
+ const seenFiles = [];
419
+ for (const file of files) {
420
+ if (!fileExists(file)) continue;
421
+ let raw;
422
+ try {
423
+ raw = JSON.parse(readFile(file));
424
+ } catch (err) {
425
+ writeErr(` mcp: ignoring malformed ${file} (${err.message})\n`);
426
+ continue;
427
+ }
428
+ const parsed = parseMcpServers(raw);
429
+ if (Object.keys(parsed).length > 0) {
430
+ Object.assign(servers, parsed); // later file (cwd) overrides earlier (root)
431
+ seenFiles.push(file);
432
+ }
433
+ }
434
+ if (Object.keys(servers).length === 0) return deps.into || null;
435
+ writeErr(
436
+ ` mcp: ${Object.keys(servers).length} server(s) from project .mcp.json ` +
437
+ `(${seenFiles.join(", ")}) — loaded via --project-mcp\n`,
438
+ );
439
+ return setupMcpFromConfig(servers, deps);
440
+ }
441
+
378
442
  /**
379
443
  * Resolve the full MCP tool surface for one agent run: the ad-hoc
380
444
  * `--mcp-config` file (if any) PLUS registered auto-connect servers (unless
381
- * disabled) PLUS an auto-discovered IDE bridge, connected into a single client.
445
+ * disabled) PLUS a project-scoped `.mcp.json` (opt-in, `--project-mcp`) PLUS an
446
+ * auto-discovered IDE bridge, connected into a single client.
382
447
  * Returns the combined `{mcpClient, extraToolDefinitions, ...}` or null when
383
448
  * there's nothing. Throws only on a bad `--mcp-config` file (explicit request).
384
449
  *
@@ -391,6 +456,7 @@ export async function loadIdeMcp(opts = {}, deps = {}) {
391
456
  export async function resolveAgentMcp(args = {}, deps = {}) {
392
457
  const doFile = deps.loadMcpConfig || loadMcpConfig;
393
458
  const doReg = deps.loadRegisteredMcp || loadRegisteredMcp;
459
+ const doProject = deps.loadProjectMcp || loadProjectMcp;
394
460
  const doIde = deps.loadIdeMcp || loadIdeMcp;
395
461
  // Thread the agent session id down to setupMcpFromConfig so spawned stdio MCP
396
462
  // servers get CC_SESSION_ID / CLAUDE_CODE_SESSION_ID (Claude-Code parity).
@@ -413,6 +479,17 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
413
479
  into: result || undefined,
414
480
  });
415
481
  }
482
+ // Project-scoped `.mcp.json` (Claude-Code parity). After --mcp-config +
483
+ // registered (those win on a name clash), before IDE auto-discovery. Skipped
484
+ // under --strict-mcp-config (returned above). OPT-IN: loadProjectMcp is a
485
+ // no-op unless --project-mcp / CC_PROJECT_MCP=1 is set (default-off — a
486
+ // checked-in .mcp.json can spawn commands). `projectMcp:false` hard-skips it.
487
+ if (args.projectMcp !== false) {
488
+ result = await doProject(
489
+ { cwd: args.cwd, env: args.env || process.env },
490
+ { ...fwd, into: result || undefined },
491
+ );
492
+ }
416
493
  if (args.ide !== false) {
417
494
  const env = args.env || process.env;
418
495
  const inIde = (deps.isInIdeTerminal || isInIdeTerminal)(env);
@@ -1 +0,0 @@
1
- import{E as B,b as D,r as z,I as p,J as c,U as _,c as n,K as a,S,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-CSnTUPQx.js";import{R as E}from"./icons-DP3uiYxy.js";const V=B("tasks",()=>{const k=z([]),l=z(!1);let u=null,e=null;const x=D(()=>k.value.filter(t=>t.status==="running")),b=D(()=>k.value.filter(t=>t.status==="pending")),y=D(()=>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=z(null);function m(t=5e3){v(),f(),u=setInterval(f,t),T()}function v(){u&&(clearInterval(u),u=null),e&&(e(),e=null)}function T(){const t=R();if(e)return;const s=C=>{C.type==="task:notification"&&C.payload?.task&&(d.value=C.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"},Q={key:0,class:"error-text"},j={key:1},G={class:"task-header"},J={class:"task-desc"},K={class:"task-id"},M={class:"task-meta"},W=["title"],Z={key:0,class:"error-text"},q={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"),T=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(),S(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",Q,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(T,{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(),S(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",G,[n(N,{color:e.store.getStatusColor(t.status)},{default:a(()=>[g(r(t.status.toUpperCase()),1)]),_:2},1032,["color"]),_("span",J,r(t.description),1),_("span",K,r(t.id.slice(0,16)),1)]),_("div",M,[_("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(),S(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,W)):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",Z,r(e.truncate(s.error,60)),1)):s.result?(i(),c("span",q,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(),S(y,{key:0,size:"small",danger:"",onClick:C=>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-wQGCAD/repo/packages/web-panel/src/views/Tasks.vue"]]);export{et as default};
@@ -1,3 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./xterm-BZcWGsqw.js","./markdown-CsiA8-E5.js","./markdown-Dfs9RUU9.css","./addon-fit-CK6X9sAG.js","./xterm-DFuMZ0ql.css"])))=>i.map(i=>d[i]);
2
- import{u as fe,_ as me,d as V,e as U}from"./index-CSnTUPQx.js";import{I as z,J as x,U as _,Q as P,S as J,K as T,V as R,c as A,F as K,Z as Y,R as E,o as Z,f as H,w as $,n as q,b as ee,r as S,P as y,_ as ve,a2 as we,a3 as he,a4 as _e}from"./vendor-BvqAck49.js";import{R as ye,b as pe,as as ge}from"./icons-DP3uiYxy.js";const k=new Map,C=new Map,N=new Set,F=new Set;let te=!1;function xe(c){te||(te=!0,c.onMessage(o=>{if(!(!o||typeof o.type!="string")){if(o.type==="terminal.stdout"){const{sessionId:s,data:e,seq:i}=o.payload||{};if(!s)return;let w;try{const d=atob(e||""),f=new Uint8Array(d.length);for(let n=0;n<d.length;n++)f[n]=d.charCodeAt(n);w=new TextDecoder("utf-8").decode(f)}catch{w=""}const u={sessionId:s,data:w,seq:i};k.get(s)?.forEach(d=>d(u)),N.forEach(d=>d(u))}else if(o.type==="terminal.exit"){const{sessionId:s,exitCode:e,signal:i}=o.payload||{};if(!s)return;const w={sessionId:s,exitCode:e,signal:i};C.get(s)?.forEach(u=>u(w)),F.forEach(u=>u(w))}}}))}function ne(c){const o=new TextEncoder().encode(c);let s="";for(let e=0;e<o.length;e++)s+=String.fromCharCode(o[e]);return btoa(s)}function ae(c){const o=atob(c||""),s=new Uint8Array(o.length);for(let e=0;e<o.length;e++)s[e]=o.charCodeAt(e);return new TextDecoder("utf-8").decode(s)}function oe(){const c=fe();xe(c);async function o(n={}){const a=await c.sendRaw({type:"terminal.create",payload:{shell:n.shell,cwd:n.cwd,env:n.env,cols:n.cols,rows:n.rows}});if(a.ok===!1)throw new Error(a.error||"terminal_create_failed");return a.result??a}async function s(){const n=await c.sendRaw({type:"terminal.list",payload:{}});if(n.ok===!1)throw new Error(n.error||"terminal_list_failed");const a=n.result??n;return Array.isArray(a.sessions)?a.sessions:[]}async function e(n,a){const r=await c.sendRaw({type:"terminal.stdin",payload:{sessionId:n,data:ne(String(a))}});if(r.ok===!1)throw new Error(r.error||"terminal_stdin_failed");return r.result??r}async function i(n,a,r){const h=await c.sendRaw({type:"terminal.resize",payload:{sessionId:n,cols:a,rows:r}});if(h.ok===!1)throw new Error(h.error||"terminal_resize_failed");return h.result??h}async function w(n){const a=await c.sendRaw({type:"terminal.close",payload:{sessionId:n}});if(a.ok===!1)throw new Error(a.error||"terminal_close_failed");return a.result??a}async function u(n,a=0){const r=await c.sendRaw({type:"terminal.history",payload:{sessionId:n,fromSeq:a}});if(r.ok===!1)throw new Error(r.error||"terminal_history_failed");const h=r.result??r;return{truncated:!!h.truncated,chunks:(h.chunks||[]).map(D=>({seq:D.seq,data:ae(D.data)}))}}function d(n,a){return n?(k.has(n)||k.set(n,new Set),k.get(n).add(a),()=>{k.get(n)?.delete(a),k.get(n)?.size===0&&k.delete(n)}):(N.add(a),()=>N.delete(a))}function f(n,a){return n?(C.has(n)||C.set(n,new Set),C.get(n).add(a),()=>{C.get(n)?.delete(a),C.get(n)?.size===0&&C.delete(n)}):(F.add(a),()=>F.delete(a))}return{create:o,list:s,stdin:e,resize:i,close:w,history:u,onStdout:d,onExit:f,_internal:{stdoutSubs:k,exitSubs:C,toBase64Utf8:ne,fromBase64Utf8:ae}}}const Se={__name:"Terminal",setup(c,{expose:o}){o();const s=oe(),e=S([]),i=S(null),w=S("pwsh"),u=S(!1),d=S(!1),f=S(""),n=S(""),a=S([]),r=[{value:"pwsh",label:"PowerShell"},{value:"cmd",label:"CMD"},{value:"bash",label:"Bash"},{value:"wsl",label:"WSL"}],h=ee(()=>e.value.find(t=>t.id===i.value));function D(t){return t?t.slice(0,8):""}let O=null,M=null;async function I(){if(O)return{xtermMod:O,fitAddonMod:M};try{O=await U(()=>import("./xterm-BZcWGsqw.js").then(t=>t.x),__vite__mapDeps([0,1,2]),import.meta.url),M=await U(()=>import("./addon-fit-CK6X9sAG.js").then(t=>t.a),__vite__mapDeps([3,1,2]),import.meta.url),await U(()=>Promise.resolve({}),__vite__mapDeps([4]),import.meta.url)}catch(t){throw n.value="xterm 资源加载失败:"+(t?.message||"未知错误"),t}return{xtermMod:O,fitAddonMod:M}}async function B(t){await q();const{xtermMod:l,fitAddonMod:p}=await I(),b=a.value.find(v=>v?.dataset?.sessionId===t.id);if(!b)return;const m=new l.Terminal({cursorBlink:!0,fontFamily:'Consolas, "Courier New", monospace',fontSize:13,theme:{background:"#1e1e1e",foreground:"#d4d4d4"},convertEol:!1}),L=new p.FitAddon;m.loadAddon(L),m.open(b);try{L.fit()}catch{}t.xterm=m,t.fitAddon=L;const ie=m.onData(v=>{s.stdin(t.id,v).catch(g=>{String(g?.message||"").includes("dangerous_keyword_blocked")?V.warning("该命令被桌面端拦截(高危关键字)"):V.error("stdin 失败: "+(g?.message||g))})}),ce=s.onStdout(t.id,({data:v,seq:g})=>{t.lastSeq=g,m.write(v)}),de=s.onExit(t.id,({exitCode:v,signal:g})=>{t.alive=!1,t.exitCode=v,t.signal=g,m.writeln(`\r
3
- \x1B[33m[session exited, code=${v}, signal=${g??"-"}]\x1B[0m`)});t.offs=()=>{try{ie.dispose?.()}catch{}ce(),de()};try{const{chunks:v,truncated:g}=await s.history(t.id,0);g&&m.writeln("\x1B[2m[history truncated — earlier output was evicted]\x1B[0m");for(const G of v)m.write(G.data),t.lastSeq=G.seq}catch(v){m.writeln(`\x1B[31m[history fetch failed: ${v?.message||v}]\x1B[0m`)}const j=new ResizeObserver(()=>{try{L.fit(),s.resize(t.id,m.cols,m.rows).catch(()=>{})}catch{}});j.observe(b);const ue=t.offs;t.offs=()=>{try{j.disconnect()}catch{}ue()}}async function re(){u.value=!0,f.value="";try{const t=await s.create({shell:w.value,cols:80,rows:24}),l={id:t.sessionId,shell:t.shell,cwd:"",alive:!0,lastSeq:0,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(l),i.value=l.id,await B(l)}catch(t){f.value=t?.message||String(t)}finally{u.value=!1}}async function se(t){try{await s.close(t)}catch(l){f.value=l?.message||String(l)}setTimeout(()=>W(t),500)}function W(t){const l=e.value.findIndex(b=>b.id===t);if(l===-1)return;const p=e.value[l];try{p.offs?.()}catch{}try{p.xterm?.dispose?.()}catch{}e.value.splice(l,1),i.value===t&&(i.value=e.value[0]?.id||null)}function le(t){i.value=t,q(()=>{const l=e.value.find(p=>p.id===t);try{l?.fitAddon?.fit()}catch{}})}async function Q(){d.value=!0,f.value="";try{const t=await s.list();for(const l of t){const p=e.value.find(m=>m.id===l.id);if(p){p.alive=l.alive,p.lastSeq=l.lastSeq;continue}const b={id:l.id,shell:l.shell,cwd:l.cwd,alive:l.alive,lastSeq:l.lastSeq,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(b),await B(b)}!i.value&&e.value.length>0&&(i.value=e.value[0].id)}catch(t){f.value=t?.message||String(t)}finally{d.value=!1}}Z(async()=>{await Q()}),H(()=>{for(const t of e.value){try{t.offs?.()}catch{}try{t.xterm?.dispose?.()}catch{}}}),$(i,()=>{q(()=>{const t=h.value;try{t?.fitAddon?.fit()}catch{}})});const X={term:s,sessions:e,activeId:i,newShell:w,creating:u,loadingList:d,error:f,warning:n,xtermContainers:a,shellOptions:r,active:h,shortId:D,get xtermMod(){return O},set xtermMod(t){O=t},get fitAddonMod(){return M},set fitAddonMod(t){M=t},loadXterm:I,mountXterm:B,onCreate:re,onClose:se,removeSession:W,activate:le,refreshList:Q,ref:S,computed:ee,onMounted:Z,onBeforeUnmount:H,nextTick:q,watch:$,get message(){return V},get PlusOutlined(){return ge},get CloseOutlined(){return pe},get ReloadOutlined(){return ye},get useTerminal(){return oe}};return Object.defineProperty(X,"__isScriptSetup",{enumerable:!1,value:!0}),X}},be={class:"terminal-page"},ke={class:"terminal-header"},Ce={class:"page-sub"},Ae={class:"terminal-body"},Ee={class:"session-tabs"},Oe=["onClick"],Te={class:"session-shell"},Re={class:"session-id"},Me={key:0,class:"session-empty"},ze={class:"xterm-host"},De=["data-session-id"],Le={key:0,class:"xterm-placeholder"},Pe={key:1,class:"terminal-footer"},qe={key:0,class:"footer-exit"};function Be(c,o,s,e,i,w){const u=z("a-tag"),d=z("a-select"),f=z("a-button"),n=z("a-space"),a=z("a-alert");return y(),x("div",be,[_("div",ke,[_("div",null,[o[3]||(o[3]=_("h2",{class:"page-title"},"远程终端",-1)),_("p",Ce,[o[2]||(o[2]=P(" 桌面端托管的 PTY 会话;Android 端可远程操控同一通道 ",-1)),e.warning?(y(),J(u,{key:0,color:"orange",style:{"margin-left":"8px"}},{default:T(()=>[P(E(e.warning),1)]),_:1})):R("v-if",!0)])]),A(n,null,{default:T(()=>[A(d,{value:e.newShell,"onUpdate:value":o[0]||(o[0]=r=>e.newShell=r),style:{width:"130px"},size:"small",options:e.shellOptions},null,8,["value"]),A(f,{type:"primary",size:"small",loading:e.creating,onClick:e.onCreate},{icon:T(()=>[A(e.PlusOutlined)]),default:T(()=>[o[4]||(o[4]=P(" 新会话 ",-1))]),_:1},8,["loading"]),A(f,{size:"small",loading:e.loadingList,onClick:e.refreshList},{icon:T(()=>[A(e.ReloadOutlined)]),default:T(()=>[o[5]||(o[5]=P(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.error?(y(),J(a,{key:0,message:e.error,type:"error","show-icon":"",closable:"",style:{"margin-bottom":"12px"},onClose:o[1]||(o[1]=r=>e.error="")},null,8,["message"])):R("v-if",!0),_("div",Ae,[_("div",Ee,[(y(!0),x(K,null,Y(e.sessions,r=>(y(),x("div",{key:r.id,class:ve(["session-tab",{active:r.id===e.activeId,dead:!r.alive}]),onClick:h=>e.activate(r.id)},[_("span",Te,E(r.shell),1),_("span",Re,E(e.shortId(r.id)),1),A(e.CloseOutlined,{class:"session-close",onClick:we(h=>e.onClose(r.id),["stop"])},null,8,["onClick"])],10,Oe))),128)),e.sessions.length===0?(y(),x("div",Me,' 点击 "新会话" 创建第一个终端 ')):R("v-if",!0)]),_("div",ze,[(y(!0),x(K,null,Y(e.sessions,r=>he((y(),x("div",{key:r.id,ref_for:!0,ref:"xtermContainers","data-session-id":r.id,class:"xterm-container"},null,8,De)),[[_e,r.id===e.activeId]])),128)),e.sessions.length===0?(y(),x("div",Le,[...o[6]||(o[6]=[_("span",null,"无活跃会话",-1)])])):R("v-if",!0)])]),e.active?(y(),x("div",Pe,[_("span",null,E(e.active.shell)+" · "+E(e.active.cwd||"(默认 cwd)")+" · seq "+E(e.active.lastSeq),1),e.active.alive?R("v-if",!0):(y(),x("span",qe,"已退出 (code="+E(e.active.exitCode??"-")+")",1))])):R("v-if",!0)])}const Fe=me(Se,[["render",Be],["__scopeId","data-v-65366a29"],["__file","/tmp/cc-web-panel-wQGCAD/repo/packages/web-panel/src/views/Terminal.vue"]]);export{Fe as default};
@@ -1 +0,0 @@
1
- import{O as r}from"./index-CSnTUPQx.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-B6KdyRTE.js";import{U as t}from"./index-CSnTUPQx.js";import"./vendor-BvqAck49.js";import"./index-C2CN7coN.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-6p4DKFSi.js";import{U as t}from"./index-CSnTUPQx.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-BQG9LlBs.js";import"./useFlexGapSupport-D_iwA3vx.js";import"./styleChecker-BZ-nMyDB.js";import"./index-C2CN7coN.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};