chainlesschain 0.162.86 → 0.162.88

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 (154) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BsWi0a9a.js → AIOps-C7p710um.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-CgU09_bk.js → ActionButton-BPkTxPrS.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-EAT1K7a2.js → Analytics-ZVxKJQmI.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-scmKwxG-.js → AppLayout-BnAycTFm.js} +3 -3
  6. package/src/assets/web-panel/assets/{Audit-BjUhZorx.js → Audit-B7ndNORB.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-UZynrFEB.js → Backup-DsghhiwY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-Dw7VRL38.js → BaseInput-QpM6Sqnh.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-jFpknfRR.js → Chat-BATie-Ql.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-V8GFgU1l.js → ChatBubbleRenderer-3ihYfTKb.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-A6QNjulp.js → Checkbox-CD7zltrP.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-plIAoFPy.js → Codegen-Cjcpbqy9.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-p8jds0fN.js → Col-CNaC37C3.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-CjdSyAYH.js → Community-CoYZ9qY1.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-D_pwxcOz.js → Compact-CPwcX_f4.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-lKVtLubh.js → Compliance-DwpNy1Vy.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-C1N1klDH.js → Cowork-CHf8f-Dj.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-De82luS5.js → Cron-DfNvIJWO.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-Ye0orjca.js → Crosschain-BLMwA95k.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-Ci2zdZFM.js → DID-DPjQKDJA.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-8ttZ4QQ9.js → Dashboard-UkuRfhAR.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-BON5tdO8.js → Dropdown-CnXX69X4.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-iPlELXWj.js → EmailListRenderer-CmyZ4JIO.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BNBYL3FW.js → FamilyGuardDashboard-D9pJ7lhj.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-Bur4PRzE.js → Federation-BTae63Nm.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-BlOvhD7K.js → FormItemContext-XQRGWRGN.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-BoVvb2xa.js → GenericCardRenderer-Da27wB3g.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-B__nMbw1.js → Git-CqkMNIfH.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-DK0Zgh2N.js → Governance-CD3kOLh8.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-BddQ7oih.js → Inference-B7lFbXHh.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-CvFX71Ed.js → KnowledgeGraph-BQy_DfuV.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-L2sBQLYZ.js → Logs-Dm7o5SAZ.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-BCWe7HDC.js → Marketplace-BH5XF-eR.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-DqKH9JPl.js → McpTools-CpoDVi4m.js} +5 -5
  35. package/src/assets/web-panel/assets/{Memory-DWWABKsb.js → Memory-CSuFkL3l.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-B2eLD-PB.js → MobileBridge-DWlG1Q_d.js} +2 -2
  37. package/src/assets/web-panel/assets/MobileProjects-BzYrwU_s.js +1 -0
  38. package/src/assets/web-panel/assets/{Mtc-Y-5_ueBj.js → Mtc-BtWk1cJe.js} +5 -5
  39. package/src/assets/web-panel/assets/{MtcAudit-D00-m4zy.js → MtcAudit-CGpZVUOE.js} +6 -6
  40. package/src/assets/web-panel/assets/{Multisig-2YOBtc_K.js → Multisig-BcUnSjCA.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-kRWZBnaz.js → NLProgramming-DUmrvSP0.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-DPRHkyl5.js → Notes-D9FXvxYu.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-vJOg9C4W.js → NotificationSettings-BrmdFdj6.js} +1 -1
  44. package/src/assets/web-panel/assets/OrderTableRenderer-CdtRzrha.js +1 -0
  45. package/src/assets/web-panel/assets/{Organization-BuISwIXd.js → Organization-DOvfmN8O.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-BNGHwMDw.js → Overflow-CWG2ShdF.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-DHBBs29l.js → P2P-DaWTeBSk.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-D9zGzba7.js → PdhVaultBrowser-DZqxKcZI.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-QLkdu-G_.js → Permissions-DR0b2vOB.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-BuQlObqk.js → PersonalDataHub-DCWQVfqV.js} +4 -4
  51. package/src/assets/web-panel/assets/{Pipeline-D_ycs0g9.js → Pipeline-BWxeVK9I.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-oN6XDVGm.js → Privacy-DvyfEXua.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-BGThFxbb.js → ProjectInit-BkKJTJYI.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-BxWieeHC.js → ProjectSettings-Dj-CSqKJ.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-DOd58I-_.js → Projects-DxWA-GFn.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-kREzYT7U.js → Providers-DygrHqSN.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-Cw11_JEa.js → QuickAsk-CoRPq_xD.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-CDWYEzDP.js → Recommend-DdOIHxul.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-BuDEzBoL.js → Reputation-BunheyMP.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-Bxxu4Xtz.js → Row-DQJPE1Hl.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-BpEsZmwI.js → RssFeed-Dv5NljB2.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-BKDmySFl.js → Search-DETFhGY8.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-gJvuDQw2.js → Security-3kETo1JV.js} +3 -3
  64. package/src/assets/web-panel/assets/{Services-XmNshc8J.js → Services-nci51WA4.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-sGp0pOss.js → Skeleton-CN_zj5Oz.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-O-23QIht.js → Skills-BJW2xEDm.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-DVxzPFWL.js → Sla-DWbkkwaH.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-CdZV4JqV.js → SpeechSettings-Dw0Eobl1.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-CzKwdZHi.js → SyncSettings-D2xzsxVY.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-CXj_bksx.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-dKai3F-y.js → Templates-CyNa5Phu.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-DGtGH0wG.js → Tenant-BlmHvT2V.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-B4S1SFTD.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-Dq4yqkky.js → TimelineRenderer-CsVx24uf.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-C2qbIdlP.js → Tokens-C8i9sMwm.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-Cqee0r__.js → Trigger-BW0Wr8zU.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-D2qJ8aQY.js → Trust-yeY49AiB.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-DVvv_9zC.js → UkeySign-CeX-u78O.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-B-34cGbd.js → VideoEditing-DMz6N92G.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-ChvGDsZH.js → Wallet-OzYHmmSs.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-h7kqS8ou.js → WebAuthn-rmzLUB7g.js} +4 -4
  82. package/src/assets/web-panel/assets/{WorkflowEditor-AUqprf8Y.js → WorkflowEditor-Dvjfyhrq.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-i7hUCh_C.js → chat-B6FXhFv9.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-DjtDsEu7.js → colors-Bn9vUneb.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-CyoTiRay.js → compact-item-DtwuNWsP.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-byecyZks.js → createContext-DAJtVtdd.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-CUtg0_6Z.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-CJVaIlUw.js → hasIn-D5c5gdV9.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-CDf8t-mU.js → index-5UHFrmZR.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-1SXdlEmZ.js → index-5bFK91OU.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-DLIQMCBQ.js → index-5d-14CRb.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-EZd5K5UE.js → index-Al0VKpbw.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-kOZvf-u5.js → index-BLwrvr7X.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-K1wX1vnH.js → index-BPkg_k6k.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Cr42QNqy.js → index-BcVW04-2.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Cme6n3eY.js → index-Bex3miQ0.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DznVBVpM.js → index-BfRKcYyV.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BRWjzWaM.js → index-BfwJ25Ar.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-XGSqce94.js → index-Bh7i75eT.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BscEBCR0.js → index-Bi714djd.js} +1 -1
  101. package/src/assets/web-panel/assets/index-Buu4km5l.js +1 -0
  102. package/src/assets/web-panel/assets/{index-CnjxYq-t.js → index-BwzmekUj.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-B4gYSyri.js → index-BxvE4tvX.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Dc8QTolS.js → index-Byucj_-b.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DXgZwbRe.js → index-C1rXkPLH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-a6qb2NLc.js → index-C5Ke20j6.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DwV8P00A.js → index-CLLjQyNA.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CtdcStbl.js → index-CVAU-rz-.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-C3mMDCOE.js → index-CfssgRTF.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BxkXcXNs.js → index-Ch9xyBwj.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DwI-ZhZq.js → index-CizZpWXl.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-gWPWksKr.js → index-Ck-Y-zMe.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-COs_6PQ5.js → index-Ckk1aCu6.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-RYkcxXFq.js → index-CwaiSvQu.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C8beUhKO.js → index-D2pqmzya.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-sUJ2fbT9.js → index-D5jVrErG.js} +1 -1
  117. package/src/assets/web-panel/assets/index-DJQBDN4o.js +1 -0
  118. package/src/assets/web-panel/assets/{index-D3JKjMEY.js → index-DOYO7e-g.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-KIqcaJ6Q.js → index-DXIYYWVV.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DKeNd7yb.js → index-DdW7vya3.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DH7suqAN.js → index-DueHm10i.js} +3 -3
  122. package/src/assets/web-panel/assets/{index-jAdTCN4U.js → index-JMQznEKT.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Qesr-8RD.js → index-Ra_2K2v3.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C2I6a-RA.js → index-bqodI7zJ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BLaQNt_7.js → index-dpy2EOcg.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DoAiXnUJ.js → index-hTd8zvNU.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BD3pqRA9.js → index-rvuBNAZ0.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-C9XZl-TO.js → initDefaultProps-7A7oMj0Q.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-DTSNqE6t.js → motion-DW8osXmN.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-DTmo8xnK.js → move-fFBKeX-1.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-Dd9VzuaV.js → omit-BftvxKV7.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-CRTbePD_.js → pickAttrs-Bo1b8Ust.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-cPPZNiDG.js → placementArrow-DEz5HJX5.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-CWSLBUlY.js → responsiveObserve-Do0AXkGf.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Bu6wM4Vm.js → slide-BJx6VmlY.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-BQSVPEW6.js → statusUtils-B3H6UxEU.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-CIH0NQmx.js → styleChecker-CQ6edivv.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-Cw2z1E4v.js → useFlexGapSupport-1L2Xx-45.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-CEf8lFD8.js → useFs-COy3Bo5w.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-C-xuLSv-.js → usePersonalDataHub-D2Hg1YtD.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-D6QpJFSY.js → vnode-BFJqKuGN.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-DccRPdcN.js → zoom-Na3JHINV.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/repl/agent-repl.js +4 -1
  145. package/src/repl/config-summary.js +48 -0
  146. package/src/runtime/coding-agent-shell-policy.cjs +90 -18
  147. package/src/runtime/headless-stream.js +26 -10
  148. package/src/assets/web-panel/assets/MobileProjects-cieCNE_S.js +0 -1
  149. package/src/assets/web-panel/assets/OrderTableRenderer-B0Y6J6Nc.js +0 -1
  150. package/src/assets/web-panel/assets/Tasks-2QWjs9uX.js +0 -1
  151. package/src/assets/web-panel/assets/Terminal-DK2OhsAg.js +0 -3
  152. package/src/assets/web-panel/assets/devWarning-D3_gOwpU.js +0 -1
  153. package/src/assets/web-panel/assets/index-C4MOtXdA.js +0 -1
  154. package/src/assets/web-panel/assets/index-nH2eOdD9.js +0 -1
@@ -46,6 +46,11 @@ export function parseConfigCommand(argStr) {
46
46
  const s = (argStr || "").trim();
47
47
  if (s === "") return { action: "show" };
48
48
 
49
+ // `/config --help` | `-h` | `help` | `?` (Claude-Code 2.1.183 parity) — list
50
+ // the common config keys. Checked before `=` / `key value` so `help` isn't
51
+ // mistaken for a key read.
52
+ if (/^(--help|-h|help|\?)$/i.test(s)) return { action: "help" };
53
+
49
54
  const eq = s.indexOf("=");
50
55
  if (eq !== -1) {
51
56
  const key = s.slice(0, eq).trim();
@@ -62,6 +67,49 @@ export function parseConfigCommand(argStr) {
62
67
  return { action: "get", key: s };
63
68
  }
64
69
 
70
+ /**
71
+ * The common config keys, surfaced by `/config --help`. cc's `/config` accepts
72
+ * any dotted key (free-form), so this is a curated quick-reference of the keys
73
+ * the CLI actually reads — not an exhaustive schema.
74
+ */
75
+ export const COMMON_CONFIG_KEYS = Object.freeze([
76
+ [
77
+ "llm.provider",
78
+ "LLM provider (ollama | volcengine | anthropic | openai | …)",
79
+ ],
80
+ ["llm.model", "default text model id"],
81
+ ["llm.visionModel", "model used for image turns (falls back to a default)"],
82
+ ["llm.baseUrl", "provider API base URL"],
83
+ ["llm.apiKey", "provider API key (stored masked; env *_API_KEY overrides)"],
84
+ [
85
+ "webSearch.provider",
86
+ "web_search backend (auto | tavily | brave | duckduckgo | …)",
87
+ ],
88
+ ["webSearch.apiKey", "web-search API key"],
89
+ ["cli.theme", "REPL color theme (auto | dark | light | mono)"],
90
+ ]);
91
+
92
+ /** Render `/config --help`: usage + the common config keys. */
93
+ export function renderConfigHelp() {
94
+ const lines = [
95
+ "/config — show or edit configuration:",
96
+ " /config show effective config (secret-safe)",
97
+ " /config <key> read a value (e.g. /config llm.model)",
98
+ " /config <key>=<value> set a value (e.g. /config llm.model=opus)",
99
+ " /config <key> <value> set a value (space form)",
100
+ " /config --help this list",
101
+ "",
102
+ "Common keys:",
103
+ ];
104
+ const width = Math.max(...COMMON_CONFIG_KEYS.map(([k]) => k.length));
105
+ for (const [key, desc] of COMMON_CONFIG_KEYS) {
106
+ lines.push(` ${key.padEnd(width)} ${desc}`);
107
+ }
108
+ lines.push("");
109
+ lines.push(" (any dotted key is accepted; keys are stored in config.json)");
110
+ return lines.join("\n");
111
+ }
112
+
65
113
  /** Render a single config value for `/config <key>`, masking secrets. */
66
114
  export function renderConfigGet(key, value) {
67
115
  if (value === undefined) return `${key} = (unset)`;
@@ -114,6 +114,52 @@ function splitFirstCommandSegment(command) {
114
114
  .trim();
115
115
  }
116
116
 
117
+ /**
118
+ * Strip the parts of a command segment that hide the real executable from
119
+ * first-token classification: a leading subshell `(`/`{`, and leading env-var
120
+ * assignments (`FOO=bar BAZ=qux cmd …` → `cmd …`). Without this, `x=1 rm -rf …`
121
+ * would be classified by firstToken `x=1` (unclassified → WARN) instead of `rm`.
122
+ */
123
+ function stripSegmentPrefix(segment) {
124
+ let t = String(segment || "").trim();
125
+ t = t.replace(/^[({]\s*/, ""); // leading subshell / group
126
+ // leading VAR=value assignments (quoted or bare), one or more
127
+ t = t.replace(/^(?:[A-Za-z_]\w*=(?:"[^"]*"|'[^']*'|\S*)\s+)+/, "");
128
+ return t.trim();
129
+ }
130
+
131
+ /**
132
+ * Split a (possibly compound) command into the individual command segments the
133
+ * policy must EACH inspect — not just the first — so a destructive command
134
+ * (`rm -rf …`, `git reset --hard`) cannot be smuggled past a benign or
135
+ * allowlisted leading segment.
136
+ *
137
+ * Covers every way a second command can ride along: the shell separators
138
+ * `&& || | ; &` AND newlines, plus commands hidden inside command-substitution
139
+ * `$(…)` / backticks (extracted as their own segments). Leading subshell parens
140
+ * and env-var assignment prefixes are stripped per segment so the real
141
+ * executable is what gets classified.
142
+ */
143
+ function splitCommandSegments(command) {
144
+ let s = String(command || "");
145
+ const extracted = [];
146
+ // Pull out command-substitution / backtick bodies as additional segments
147
+ // (single level — nested substitutions are an accepted edge case).
148
+ s = s.replace(/\$\(([^()]*)\)/g, (_m, inner) => {
149
+ extracted.push(inner);
150
+ return " ";
151
+ });
152
+ s = s.replace(/`([^`]*)`/g, (_m, inner) => {
153
+ extracted.push(inner);
154
+ return " ";
155
+ });
156
+ // Separators: && || | ; & and any newline.
157
+ const parts = s.split(/(?:\|\||&&|[|;&]|[\r\n]+)/).concat(extracted);
158
+ return parts
159
+ .map((segment) => stripSegmentPrefix(segment))
160
+ .filter(Boolean);
161
+ }
162
+
117
163
  function tokenizeShellCommand(command) {
118
164
  const tokens = [];
119
165
  let current = "";
@@ -165,34 +211,28 @@ function normalizeShellCommand(command) {
165
211
  return splitFirstCommandSegment(command).replace(/\s+/g, " ").trim();
166
212
  }
167
213
 
168
- function evaluateShellCommandPolicy(command, options = {}) {
169
- const normalized = normalizeShellCommand(command);
214
+ // Severity ordering so the most restrictive segment of a compound command wins.
215
+ const DECISION_SEVERITY = Object.freeze({
216
+ [SHELL_POLICY_DECISIONS.DENY]: 3,
217
+ [SHELL_POLICY_DECISIONS.REROUTE]: 2,
218
+ [SHELL_POLICY_DECISIONS.WARN]: 1,
219
+ [SHELL_POLICY_DECISIONS.ALLOW]: 0,
220
+ });
221
+
222
+ /** Classify ONE command segment (no separators). */
223
+ function evaluateSegmentPolicy(segment, overrideRuleIds) {
224
+ const normalized = normalizeShellCommand(segment);
170
225
  const tokens = tokenizeShellCommand(normalized);
171
226
  const firstToken = (tokens[0] || "").toLowerCase();
172
227
  const secondToken = (tokens[1] || "").toLowerCase();
173
228
  const context = {
174
- command: String(command || ""),
229
+ command: String(segment || ""),
175
230
  normalized,
176
231
  tokens,
177
232
  firstToken,
178
233
  secondToken,
179
234
  };
180
235
 
181
- // Rule IDs that should be downgraded from DENY to WARN (e.g. cowork web-research)
182
- const overrideRuleIds = Array.isArray(options.overrideRuleIds)
183
- ? new Set(options.overrideRuleIds)
184
- : new Set();
185
-
186
- if (!normalized) {
187
- return {
188
- allowed: false,
189
- decision: SHELL_POLICY_DECISIONS.DENY,
190
- reason: "Shell command is required.",
191
- ruleId: "empty-command",
192
- normalizedCommand: normalized,
193
- };
194
- }
195
-
196
236
  const blockedRule = BLOCKED_SHELL_RULES.find((rule) => rule.test(context));
197
237
  if (blockedRule) {
198
238
  // If the rule is overridden, downgrade from DENY to WARN (allowed)
@@ -237,6 +277,37 @@ function evaluateShellCommandPolicy(command, options = {}) {
237
277
  };
238
278
  }
239
279
 
280
+ function evaluateShellCommandPolicy(command, options = {}) {
281
+ // Rule IDs that should be downgraded from DENY to WARN (e.g. cowork web-research)
282
+ const overrideRuleIds = Array.isArray(options.overrideRuleIds)
283
+ ? new Set(options.overrideRuleIds)
284
+ : new Set();
285
+
286
+ // Inspect EVERY segment of a compound command, not just the first — a
287
+ // dangerous segment after `&&` / `;` / `|` must still be caught. The most
288
+ // restrictive segment decides the whole command (a compound is only ALLOW
289
+ // when every segment is independently allowlisted).
290
+ const segments = splitCommandSegments(command);
291
+ if (!segments.length) {
292
+ return {
293
+ allowed: false,
294
+ decision: SHELL_POLICY_DECISIONS.DENY,
295
+ reason: "Shell command is required.",
296
+ ruleId: "empty-command",
297
+ normalizedCommand: "",
298
+ };
299
+ }
300
+
301
+ let worst = null;
302
+ for (const segment of segments) {
303
+ const result = evaluateSegmentPolicy(segment, overrideRuleIds);
304
+ const sev = DECISION_SEVERITY[result.decision] ?? 1;
305
+ const worstSev = worst ? (DECISION_SEVERITY[worst.decision] ?? 1) : -1;
306
+ if (sev > worstSev) worst = result;
307
+ }
308
+ return worst;
309
+ }
310
+
240
311
  module.exports = {
241
312
  ALLOWLISTED_SHELL_RULES,
242
313
  BLOCKED_SHELL_RULES,
@@ -244,5 +315,6 @@ module.exports = {
244
315
  evaluateShellCommandPolicy,
245
316
  normalizeShellCommand,
246
317
  splitFirstCommandSegment,
318
+ splitCommandSegments,
247
319
  tokenizeShellCommand,
248
320
  };
@@ -649,6 +649,12 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
649
649
 
650
650
  let turns = 0;
651
651
  let sawError = false;
652
+ // Once any turn attaches an image, the image stays in the conversation
653
+ // history — so every later turn (even a text-only follow-up like "what colour
654
+ // is it?") must keep using the vision LLM, otherwise a text-only default model
655
+ // is handed image content it can't read. Claude Code never hits this (one
656
+ // multimodal model); cc splits text/vision models, so we sticky the routing.
657
+ let conversationHasImages = false;
652
658
 
653
659
  // ── Concurrent stdin pump (turn-interrupt support) ────────────────────────
654
660
  // Input is consumed AS IT ARRIVES — not between turns — so an
@@ -879,23 +885,15 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
879
885
  // On an image turn, also switch THIS turn to the vision LLM (model only —
880
886
  // same account/key) so it's read by a vision-capable model.
881
887
  let turnContent = userContent;
882
- let turnVisionLlm = null;
883
888
  if (parsed.images && parsed.images.length) {
884
889
  try {
885
- const { resolveImages, buildUserContent, resolveVisionLlm } =
890
+ const { resolveImages, buildUserContent } =
886
891
  await import("../lib/image-input.js");
887
892
  turnContent = buildUserContent(
888
893
  userContent,
889
894
  resolveImages(parsed.images),
890
895
  );
891
- turnVisionLlm = resolveVisionLlm({
892
- hasImage: true,
893
- flags: {},
894
- llm: { provider, baseUrl, apiKey, visionModel },
895
- });
896
- writeErr(
897
- ` [image] ${parsed.images.length} attached → vision model ${turnVisionLlm.model}\n`,
898
- );
896
+ conversationHasImages = true;
899
897
  } catch (err) {
900
898
  emit({
901
899
  type: "result",
@@ -907,6 +905,24 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
907
905
  continue; // bad attachment kills the turn, not the session
908
906
  }
909
907
  }
908
+ // Route to the vision LLM (model only — same provider/account/key/baseUrl)
909
+ // on any turn that carries an image AND on every later turn once the
910
+ // conversation holds an image, so a text-only follow-up about the image
911
+ // isn't sent to a text-only default model that can't read the history.
912
+ let turnVisionLlm = null;
913
+ if (conversationHasImages) {
914
+ const { resolveVisionLlm } = await import("../lib/image-input.js");
915
+ turnVisionLlm = resolveVisionLlm({
916
+ hasImage: true,
917
+ flags: {},
918
+ llm: { provider, baseUrl, apiKey, visionModel },
919
+ });
920
+ if (parsed.images && parsed.images.length) {
921
+ writeErr(
922
+ ` [image] ${parsed.images.length} attached → vision model ${turnVisionLlm.model}\n`,
923
+ );
924
+ }
925
+ }
910
926
 
911
927
  messages.push({ role: "user", content: turnContent });
912
928
  if (persist) {
@@ -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-DH7suqAN.js";import{a7 as y,M}from"./icons-DP3uiYxy.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return M},get FolderOutlined(){return y}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),j=n("a-empty"),P=n("a-card");return h(),g("div",x,[l(P,null,{default:r(()=>[l(j,{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-GijCQY/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};
@@ -1 +0,0 @@
1
- import{I as w,P as l,J as u,U as s,R as n,c as i,K as v,Q as _,V as g,b as a}from"./vendor-BvqAck49.js";import{_ as S}from"./index-DH7suqAN.js";import"./icons-DP3uiYxy.js";const k={__name:"OrderTableRenderer",props:{event:{type:Object,required:!0}},setup(p,{expose:r}){r();const o=p,e=a(()=>o.event.content||{}),d=a(()=>o.event.extra||{}),m=a(()=>d.value.merchant||e.value.merchant||e.value.counterparty||"—"),c=a(()=>e.value.title||e.value.name||e.value.itemName||e.value.text||"—"),y=a(()=>{const t=e.value.amount??e.value.price??e.value.total;return t==null?"—":`${e.value.currency||"¥"} ${typeof t=="number"?t.toFixed(2):t}`}),T=a(()=>d.value.orderNo||e.value.orderNo||e.value.orderId),f=a(()=>e.value.status||e.value.state),b=a(()=>{const t=(f.value||"").toLowerCase();return t.includes("成功")||t.includes("succe")||t.includes("paid")?"green":t.includes("退")||t.includes("refund")?"orange":t.includes("失败")||t.includes("fail")?"red":"default"}),h=a(()=>{if(!o.event.occurredAt)return"";const t=new Date(o.event.occurredAt);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}),x={props:o,c:e,e:d,merchantText:m,itemText:c,amountText:y,orderNo:T,statusText:f,statusColor:b,formattedTime:h,computed:a};return Object.defineProperty(x,"__isScriptSetup",{enumerable:!1,value:!0}),x}},N={class:"order-card"},C={class:"head"},O={class:"time"},V={class:"row"},R={class:"val"},j={class:"row"},B={class:"val"},D={class:"row amount-row"},I={class:"val amount"},A={key:0,class:"row"},F={class:"val mono"},M={key:1,class:"row"};function P(p,r,o,e,d,m){const c=w("a-tag");return l(),u("div",N,[s("div",C,[s("span",O,n(e.formattedTime),1),i(c,{color:"gold"},{default:v(()=>[_(n(o.event.source.adapter),1)]),_:1}),i(c,null,{default:v(()=>[_(n(o.event.subtype),1)]),_:1})]),s("div",V,[r[0]||(r[0]=s("span",{class:"key"},"商户",-1)),s("span",R,n(e.merchantText),1)]),s("div",j,[r[1]||(r[1]=s("span",{class:"key"},"商品/项目",-1)),s("span",B,n(e.itemText),1)]),s("div",D,[r[2]||(r[2]=s("span",{class:"key"},"金额",-1)),s("span",I,n(e.amountText),1)]),e.orderNo?(l(),u("div",A,[r[3]||(r[3]=s("span",{class:"key"},"单号",-1)),s("span",F,n(e.orderNo),1)])):g("v-if",!0),e.statusText?(l(),u("div",M,[r[4]||(r[4]=s("span",{class:"key"},"状态",-1)),i(c,{color:e.statusColor},{default:v(()=>[_(n(e.statusText),1)]),_:1},8,["color"])])):g("v-if",!0)])}const G=S(k,[["render",P],["__scopeId","data-v-5ed5524d"],["__file","/tmp/cc-web-panel-GijCQY/repo/packages/web-panel/src/components/pdh/renderers/OrderTableRenderer.vue"]]);export{G 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,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-DH7suqAN.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),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}},j={class:"page-header"},L={key:0,class:"error-text"},Q={key:1},G={class:"task-header"},J={class:"task-desc"},K={class:"task-id"},M={class:"task-meta"},W=["title"],Y={key:0,class:"error-text"},Z={key:1,class:"success-text"},q={key:2,class:"muted-text"};function H(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",j,[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",L,r(e.store.lastNotification.error),1)):e.store.lastNotification.result?(i(),c("span",Q,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",Y,r(e.truncate(s.error,60)),1)):s.result?(i(),c("span",Z,r(e.truncate(String(s.result),60)),1)):(i(),c("span",q,"-"))],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",H],["__scopeId","data-v-da5ff6a2"],["__file","/tmp/cc-web-panel-GijCQY/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-DH7suqAN.js";import{I as z,J as x,U as _,Q as D,S as G,K as T,V as R,c as A,F as J,Z as K,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(L=>({seq:L.seq,data:ae(L.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 L(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}),P=new p.FitAddon;m.loadAddon(P),m.open(b);try{P.fit()}catch{}t.xterm=m,t.fitAddon=P;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 Y of v)m.write(Y.data),t.lastSeq=Y.seq}catch(v){m.writeln(`\x1B[31m[history fetch failed: ${v?.message||v}]\x1B[0m`)}const X=new ResizeObserver(()=>{try{P.fit(),s.resize(t.id,m.cols,m.rows).catch(()=>{})}catch{}});X.observe(b);const ue=t.offs;t.offs=()=>{try{X.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 j(){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 j()}),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 Q={term:s,sessions:e,activeId:i,newShell:w,creating:u,loadingList:d,error:f,warning:n,xtermContainers:a,shellOptions:r,active:h,shortId:L,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:j,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(Q,"__isScriptSetup",{enumerable:!1,value:!0}),Q}},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"},Le=["data-session-id"],Pe={key:0,class:"xterm-placeholder"},De={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]=D(" 桌面端托管的 PTY 会话;Android 端可远程操控同一通道 ",-1)),e.warning?(y(),G(u,{key:0,color:"orange",style:{"margin-left":"8px"}},{default:T(()=>[D(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]=D(" 新会话 ",-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]=D(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.error?(y(),G(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(J,null,K(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(J,null,K(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,Le)),[[_e,r.id===e.activeId]])),128)),e.sessions.length===0?(y(),x("div",Pe,[...o[6]||(o[6]=[_("span",null,"无活跃会话",-1)])])):R("v-if",!0)])]),e.active?(y(),x("div",De,[_("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-GijCQY/repo/packages/web-panel/src/views/Terminal.vue"]]);export{Fe as default};
@@ -1 +0,0 @@
1
- import{O as r}from"./index-DH7suqAN.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-p8jds0fN.js";import{U as t}from"./index-DH7suqAN.js";import"./vendor-BvqAck49.js";import"./index-BLaQNt_7.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-Bxxu4Xtz.js";import{U as t}from"./index-DH7suqAN.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-CWSLBUlY.js";import"./useFlexGapSupport-Cw2z1E4v.js";import"./styleChecker-CIH0NQmx.js";import"./index-BLaQNt_7.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};