chainlesschain 0.162.94 → 0.162.96

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 (224) hide show
  1. package/README.md +1 -1
  2. package/bin/chainlesschain.js +8 -18
  3. package/package.json +1 -1
  4. package/src/assets/web-panel/.build-hash +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-CiEoV_Hg.js → AIOps-Bo9Ux24z.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DrrjQMuK.js → ActionButton-CExgXSQT.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-ChlhPe9a.js → Analytics-BNnZhRTZ.js} +2 -2
  8. package/src/assets/web-panel/assets/{AppLayout-CIkI7d5o.js → AppLayout-D9xfqFCT.js} +4 -4
  9. package/src/assets/web-panel/assets/{Audit-_sY9bNSN.js → Audit-Cpgu8uCw.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DvzaThN8.js → Backup-CHdEJnNE.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DDZW_DU8.js → BaseInput-Cbw-PxBq.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-DqErkog2.js → Chat-ChHTZK_6.js} +5 -5
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BcnNHS-r.js → ChatBubbleRenderer-Dl6z6ZH7.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-NWDuyRK6.js → Checkbox-Cj8d9bru.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-B_jnSC8a.js → Codegen-C2YobW4j.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-B-uyUy0z.js → Col-CxfV5FGT.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-Dmf1MpG7.js → Community-CiwOASMj.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-fGI68M5y.js → Compact-CTg_2iKW.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-PV9qT-iV.js → Compliance-HMbsTmtw.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-BM6BvCgv.js → Cowork-DyNDqGR2.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-BsSWwFFo.js → Cron-9-x5M7qy.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DUdPVYvS.js → Crosschain-4msgDaYJ.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-PPLLhrJs.js → DID--2Beb5Po.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-Cn_Xjj80.js → Dashboard-T6nq0Lzs.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DkTXjy5D.js → Dropdown-D_Q6T10v.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BnA27cjB.js → EmailListRenderer-TnN21bJx.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-jqrv5VCp.js → FamilyGuardDashboard-kky_uIij.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-DESwXwtR.js → Federation-C1GkNY4B.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-C9gbyY1r.js → FormItemContext-5-_Fc5YV.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-CkZB9crH.js → GenericCardRenderer-CmHiB7sr.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-B6niu0W9.js → Git-Cuci_BPI.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BrF28dEi.js → Governance-BU0cO2LD.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CZDnV8SN.js → Inference-BDFNgEcx.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-eqZ0hP0l.js → KnowledgeGraph-DITXUzHz.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-BlHS7DoS.js → Logs-Ea-07CRd.js} +2 -2
  36. package/src/assets/web-panel/assets/{Marketplace-NOp9G83e.js → Marketplace-D6OBbRVG.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-B6wMx173.js → McpTools-eiKpIJMi.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-BKVeTAeT.js → Memory-M-X-T8UF.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-Da2y6iYW.js → MobileBridge-xcZb9Ekv.js} +2 -2
  40. package/src/assets/web-panel/assets/MobileProjects-DCfoTPRC.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-B7Hy5rAT.js → Mtc-BWfGDzD8.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-BgBoX0XI.js → MtcAudit-imBuld-U.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-Db7bwi5J.js → Multisig-C2kcsq7I.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-f9ca2vst.js → NLProgramming-DObvXSXP.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-meVqoOMz.js → Notes-C-6OGJMe.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BfEhBXNo.js → NotificationSettings-ub7Ozxci.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-e25Q6ALJ.js → OrderTableRenderer-CR2W89Vk.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-BpgOG9lj.js → Organization-DNA_Wty7.js} +2 -2
  49. package/src/assets/web-panel/assets/{Overflow-fI3L05Rq.js → Overflow-rT4Wb4rQ.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-wD0wpJJY.js → P2P-CK-hARKv.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-BWV9J4VZ.js → PdhVaultBrowser-C2pbtNbT.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-BJH7W2iv.js → Permissions-B8EIEqGJ.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CqQ3XpMz.js → PersonalDataHub-BxNVNU3s.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-CHyXCU1i.js → Pipeline-CT9pbkyY.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-CJtfNlc7.js → Privacy-DhCNd2CS.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-CKOaHFGR.js → ProjectInit-Qngnx-vQ.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-QD8wp_EM.js → ProjectSettings-Dfn-nQc1.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-BKdiSaPR.js +1 -0
  59. package/src/assets/web-panel/assets/{Providers-BPESqCEg.js → Providers-4o9B_n-X.js} +1 -1
  60. package/src/assets/web-panel/assets/{QuickAsk-C5AzvvRo.js → QuickAsk-bs1qvF30.js} +1 -1
  61. package/src/assets/web-panel/assets/{Recommend-cGpF3tsA.js → Recommend-CuEnKA2K.js} +1 -1
  62. package/src/assets/web-panel/assets/{Reputation-Duaxvbt9.js → Reputation-DbfvmRb2.js} +1 -1
  63. package/src/assets/web-panel/assets/{Row-xsUwB5Ay.js → Row-DvMJGAI3.js} +1 -1
  64. package/src/assets/web-panel/assets/{RssFeed-DmUUsqaF.js → RssFeed-oJ0BZvmA.js} +3 -3
  65. package/src/assets/web-panel/assets/{Search-Do9YuDbX.js → Search-DnIVrY9O.js} +1 -1
  66. package/src/assets/web-panel/assets/{Security-06BgEn-d.js → Security-CIWhI_Tc.js} +3 -3
  67. package/src/assets/web-panel/assets/{Services-DyaCes7r.js → Services-DLrnpjwm.js} +2 -2
  68. package/src/assets/web-panel/assets/{Skeleton-Cj_VbkFG.js → Skeleton-CYmqgtVb.js} +1 -1
  69. package/src/assets/web-panel/assets/{Skills-DCOWMJOR.js → Skills-BUzCkoeu.js} +1 -1
  70. package/src/assets/web-panel/assets/{Sla-C44_86bu.js → Sla-DYRE4bnS.js} +1 -1
  71. package/src/assets/web-panel/assets/{SpeechSettings-BXhBJSMB.js → SpeechSettings-_6MurdOg.js} +1 -1
  72. package/src/assets/web-panel/assets/{SyncSettings-BpHsaNWg.js → SyncSettings-UIdnF5Li.js} +2 -2
  73. package/src/assets/web-panel/assets/Tasks-COx2CjT8.js +1 -0
  74. package/src/assets/web-panel/assets/{Templates-aEWbCOdo.js → Templates-BcHAmkZo.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tenant-DkOLw1Yz.js → Tenant-CjYQS8yZ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Terminal-5Z4paIoh.js → Terminal-BmfOPcWt.js} +2 -2
  77. package/src/assets/web-panel/assets/{TimelineRenderer-CYhublOm.js → TimelineRenderer-D5HuarNQ.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tokens-h57dBT4T.js → Tokens-C_fbProA.js} +1 -1
  79. package/src/assets/web-panel/assets/{Trigger-abE21FpD.js → Trigger-JPulpRx8.js} +1 -1
  80. package/src/assets/web-panel/assets/{Trust-urB3VZip.js → Trust-CnO-062O.js} +1 -1
  81. package/src/assets/web-panel/assets/{UkeySign-D6uXV9pp.js → UkeySign-HpNovvau.js} +1 -1
  82. package/src/assets/web-panel/assets/{VideoEditing-C9MxXAzw.js → VideoEditing-yMncxH7y.js} +1 -1
  83. package/src/assets/web-panel/assets/{Wallet-DTn5rW4u.js → Wallet-Cug-t7Np.js} +3 -3
  84. package/src/assets/web-panel/assets/{WebAuthn-BNYEqeqr.js → WebAuthn--U1-NR-3.js} +2 -2
  85. package/src/assets/web-panel/assets/{WorkflowEditor-CsRoOJPT.js → WorkflowEditor-R-XvSJ3S.js} +1 -1
  86. package/src/assets/web-panel/assets/{chat-B5GoUHDS.js → chat-CCI1i6Rp.js} +1 -1
  87. package/src/assets/web-panel/assets/{colors-BF_Rqaab.js → colors-C-mqoaLt.js} +1 -1
  88. package/src/assets/web-panel/assets/{compact-item-BNPfqT4P.js → compact-item-De_N2iRR.js} +1 -1
  89. package/src/assets/web-panel/assets/{createContext-C3qLKXX-.js → createContext-DbTM6sjZ.js} +1 -1
  90. package/src/assets/web-panel/assets/devWarning-OcLPHSl5.js +1 -0
  91. package/src/assets/web-panel/assets/{hasIn-BLpAeFXB.js → hasIn-D0Adylyc.js} +1 -1
  92. package/src/assets/web-panel/assets/index-7E_mHkDU.js +1 -0
  93. package/src/assets/web-panel/assets/{index-BOoTjHGU.js → index-AY937BxS.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-Cv1WRH-j.js → index-B6hgy5VC.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-C2wJowV1.js → index-B7XnpLHk.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Dj6rUk3f.js → index-B7gw-tDm.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-Dz7o1Zt6.js → index-BBgDgkwW.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CMRdeB2r.js → index-BMmeiw88.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-2-7AD4Fq.js → index-BU6XtnSx.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-7Tt41tHa.js → index-Bi7VUG0R.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CaROOJ5Z.js → index-BtE3cw9m.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DmrPbYXh.js → index-C9ej-MF0.js} +3 -3
  103. package/src/assets/web-panel/assets/{index-CgIrRLBP.js → index-CIEiQl1j.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DudglWTC.js → index-CKgaW9E5.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C8B3rHnr.js → index-CY0KKR5f.js} +1 -1
  106. package/src/assets/web-panel/assets/index-CbV3-WlB.js +1 -0
  107. package/src/assets/web-panel/assets/{index-ixN0R0We.js → index-Co1UkcFX.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Cqb8TXEp.js → index-CzP5d5LW.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DH95hKUN.js → index-D0NJ5lRi.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-C6yRwT6e.js → index-D0gBsqTX.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-o1doEeT3.js → index-D5F6shtn.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BxWEK9FS.js → index-DVtamtlm.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Cxd2RsZR.js → index-DWT18hDG.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-vXHPZOmO.js → index-DaXb4B9P.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BJsVUj80.js → index-DjQA0Vez.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CIjPwa7h.js → index-Ds8NJVEL.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DMKiwMJa.js → index-DuP-8HWu.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BIpGZeh2.js → index-DwLTiJ31.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Dn95Blhx.js → index-T3VhH8cO.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BqjU6Jp9.js → index-TDY1o0w3.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CBFekqcY.js → index-TRy2Gc3V.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-D-PNuV4r.js → index-W1OMxCmI.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BlEDjdTc.js → index-ftFRZbuc.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DMKbLaTg.js → index-iGPGaORA.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DYWExa2Z.js → index-jhy5KQvg.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BryugSCS.js → index-qUSZJcgw.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-81hgV6U6.js → index-w3f6lqkD.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CmBMP52w.js → index-xdMc71Kh.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-KUdyAwqr.js → index-xhX5eg2Z.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DGVf-eOG.js → index-zkTiW6d6.js} +1 -1
  131. package/src/assets/web-panel/assets/{initDefaultProps-Dhfx-jOJ.js → initDefaultProps-CIHqouWk.js} +1 -1
  132. package/src/assets/web-panel/assets/{motion-DzZPc4Mq.js → motion-D1iUKftk.js} +1 -1
  133. package/src/assets/web-panel/assets/{move-D6R8EIjz.js → move-YOpWjmjL.js} +1 -1
  134. package/src/assets/web-panel/assets/{omit-CPniUUR1.js → omit-C_1357UY.js} +1 -1
  135. package/src/assets/web-panel/assets/{pickAttrs-DbzxHNNa.js → pickAttrs-CDb4dq6o.js} +1 -1
  136. package/src/assets/web-panel/assets/{placementArrow-B_MxmwXz.js → placementArrow-D-OGYyhd.js} +1 -1
  137. package/src/assets/web-panel/assets/{responsiveObserve-Em-jKJ7U.js → responsiveObserve-hS-j69A0.js} +1 -1
  138. package/src/assets/web-panel/assets/{slide-B2RV1mQl.js → slide-tnjuvphU.js} +1 -1
  139. package/src/assets/web-panel/assets/{statusUtils-C9Ps6HQe.js → statusUtils-BERfMMcU.js} +1 -1
  140. package/src/assets/web-panel/assets/{styleChecker-DCoehh1S.js → styleChecker-DKpl2K9E.js} +1 -1
  141. package/src/assets/web-panel/assets/{useFlexGapSupport-DZOaLVto.js → useFlexGapSupport-C_sX4D3N.js} +1 -1
  142. package/src/assets/web-panel/assets/{useFs-Dk_JA91R.js → useFs-DBcxC1vK.js} +1 -1
  143. package/src/assets/web-panel/assets/{usePersonalDataHub-CJR6Dqtz.js → usePersonalDataHub-CeoDf2XI.js} +1 -1
  144. package/src/assets/web-panel/assets/{vnode-BaFNaDQL.js → vnode-DC9Pmj_u.js} +1 -1
  145. package/src/assets/web-panel/assets/{zoom-CxA9IYpM.js → zoom-CZA58J7M.js} +1 -1
  146. package/src/assets/web-panel/index.html +1 -1
  147. package/src/commands/activitypub.js +19 -3
  148. package/src/commands/agent.js +25 -0
  149. package/src/commands/ask.js +13 -0
  150. package/src/commands/config.js +17 -1
  151. package/src/commands/cost.js +6 -1
  152. package/src/commands/dao.js +16 -3
  153. package/src/commands/dlp.js +7 -1
  154. package/src/commands/hub.js +13 -0
  155. package/src/commands/mtc.js +37 -1
  156. package/src/commands/pdh.js +162 -0
  157. package/src/gateways/discord/discord-formatter.js +18 -1
  158. package/src/gateways/telegram/telegram-formatter.js +6 -3
  159. package/src/gateways/ws/ws-server.js +19 -1
  160. package/src/harness/mcp-client.js +19 -2
  161. package/src/harness/plugin-manager.js +20 -0
  162. package/src/harness/worktree-isolator.js +17 -1
  163. package/src/index.js +2 -0
  164. package/src/lib/__tests__/model-deprecation.test.js +194 -0
  165. package/src/lib/a2a-protocol.js +23 -9
  166. package/src/lib/agent-core.js +2 -5
  167. package/src/lib/audit-mtc.js +40 -2
  168. package/src/lib/chat-core.js +141 -18
  169. package/src/lib/claude-code-bridge.js +14 -2
  170. package/src/lib/cli-anything-bridge.js +5 -0
  171. package/src/lib/cli-numeric.js +38 -0
  172. package/src/lib/config-manager.js +37 -6
  173. package/src/lib/cowork/ab-comparator-cli.js +6 -2
  174. package/src/lib/cowork-cron.js +45 -34
  175. package/src/lib/cowork-learning.js +31 -1
  176. package/src/lib/cowork-share.js +39 -3
  177. package/src/lib/cowork-template-marketplace.js +54 -2
  178. package/src/lib/cowork-workflow.js +33 -6
  179. package/src/lib/cross-chain-mtc.js +41 -12
  180. package/src/lib/crypto-manager.js +12 -2
  181. package/src/lib/dbevo.js +19 -8
  182. package/src/lib/downloader.js +24 -9
  183. package/src/lib/evomap-governance.js +4 -4
  184. package/src/lib/evomap-manager.js +54 -7
  185. package/src/lib/fatal-handler.js +48 -0
  186. package/src/lib/file-checkpoint.js +56 -4
  187. package/src/lib/git-integration.js +28 -0
  188. package/src/lib/goal-store.js +36 -10
  189. package/src/lib/hierarchical-memory.js +6 -0
  190. package/src/lib/llm-pricing.js +52 -2
  191. package/src/lib/mcp-oauth.js +37 -7
  192. package/src/lib/memory-manager.js +23 -2
  193. package/src/lib/model-deprecation.js +249 -0
  194. package/src/lib/pdh-feedback-ledger.js +131 -0
  195. package/src/lib/permanent-memory.js +30 -2
  196. package/src/lib/permission-rules.cjs +11 -3
  197. package/src/lib/personal-data-hub-aichat-wizard.js +33 -3
  198. package/src/lib/personal-data-hub-wiring.js +36 -13
  199. package/src/lib/project-instructions.js +10 -4
  200. package/src/lib/runnable-provider.js +62 -31
  201. package/src/lib/session-tail.js +6 -1
  202. package/src/lib/session-usage.js +34 -1
  203. package/src/lib/skill-loader.js +4 -1
  204. package/src/lib/skill-packs/generator.js +25 -2
  205. package/src/lib/stream-retry.js +56 -0
  206. package/src/lib/sync-credentials.js +53 -17
  207. package/src/lib/token-tracker.js +12 -2
  208. package/src/lib/with-file-lock.js +87 -0
  209. package/src/repl/agent-repl.js +52 -13
  210. package/src/repl/chat-repl.js +10 -0
  211. package/src/repl/session-cost.js +31 -3
  212. package/src/runtime/agent-core.js +474 -53
  213. package/src/runtime/coding-agent-contract-shared.cjs +58 -1
  214. package/src/runtime/coding-agent-policy.cjs +10 -0
  215. package/src/runtime/file-ref-expander.js +29 -1
  216. package/src/runtime/headless-runner.js +51 -6
  217. package/src/runtime/headless-stream.js +219 -2
  218. package/src/skills/video-editing/tools/commit.js +15 -1
  219. package/src/assets/web-panel/assets/MobileProjects-CTFPhn4A.js +0 -1
  220. package/src/assets/web-panel/assets/Projects-Dj33CO-H.js +0 -1
  221. package/src/assets/web-panel/assets/Tasks-C83eyBn8.js +0 -1
  222. package/src/assets/web-panel/assets/devWarning-D5Rwbl_Y.js +0 -1
  223. package/src/assets/web-panel/assets/index-7ls1Z3dH.js +0 -1
  224. package/src/assets/web-panel/assets/index-DoldiBPq.js +0 -1
@@ -27,11 +27,22 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
27
27
  title: "Read File",
28
28
  kind: "filesystem",
29
29
  tier: "mvp",
30
- description: "Read a file's content",
30
+ description:
31
+ "Read a file's content. Jupyter notebooks (.ipynb) are rendered as a compact cell listing (index/id/type/source, outputs hidden) for use with notebook_edit — pass raw:true for the underlying JSON.",
31
32
  inputSchema: {
32
33
  type: "object",
33
34
  properties: {
34
35
  path: { type: "string", description: "File path to read" },
36
+ hashed: {
37
+ type: "boolean",
38
+ description:
39
+ "Prefix each line with a 6-char content hash for edit_file_hashed anchoring",
40
+ },
41
+ raw: {
42
+ type: "boolean",
43
+ description:
44
+ "For .ipynb: return the raw notebook JSON instead of the rendered cell listing",
45
+ },
35
46
  },
36
47
  required: ["path"],
37
48
  },
@@ -69,6 +80,52 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
69
80
  tags: ["tool:write_file", "contract:coding-agent", "tier:mvp"],
70
81
  },
71
82
  },
83
+ {
84
+ name: "notebook_edit",
85
+ title: "Edit Notebook",
86
+ kind: "filesystem",
87
+ tier: "mvp",
88
+ description:
89
+ "Edit a Jupyter notebook (.ipynb) cell. edit_mode 'replace' (default) overwrites a cell's source; 'insert' adds a new cell (after the target cell, or at the top when no target given); 'delete' removes a cell. Identify the target with cell_id (preferred) or 0-based cell_index. cell_type ('code'|'markdown') is required for 'insert'. Source is plain text with newlines preserved; replacing a code cell clears its previous outputs + execution_count.",
90
+ inputSchema: {
91
+ type: "object",
92
+ properties: {
93
+ path: { type: "string", description: "Path to the .ipynb notebook" },
94
+ new_source: {
95
+ type: "string",
96
+ description: "New cell source text (required for replace/insert)",
97
+ },
98
+ cell_id: {
99
+ type: "string",
100
+ description: "Target cell id (preferred over cell_index)",
101
+ },
102
+ cell_index: {
103
+ type: "number",
104
+ description: "0-based cell index (when cell_id is unknown)",
105
+ },
106
+ cell_type: {
107
+ type: "string",
108
+ enum: ["code", "markdown"],
109
+ description: "Cell type — required for edit_mode 'insert'",
110
+ },
111
+ edit_mode: {
112
+ type: "string",
113
+ enum: ["replace", "insert", "delete"],
114
+ description: "replace (default) | insert | delete",
115
+ },
116
+ },
117
+ required: ["path"],
118
+ },
119
+ ...TOOL_POLICY_METADATA.notebook_edit,
120
+ permissions: {
121
+ level: "elevated",
122
+ scopes: ["filesystem:write"],
123
+ },
124
+ telemetry: {
125
+ category: "filesystem",
126
+ tags: ["tool:notebook_edit", "contract:coding-agent", "tier:mvp"],
127
+ },
128
+ },
72
129
  {
73
130
  name: "edit_file",
74
131
  title: "Edit File",
@@ -94,6 +94,16 @@ const TOOL_POLICY_METADATA = Object.freeze({
94
94
  approvalFlow: "plan",
95
95
  isReadOnly: false,
96
96
  },
97
+ notebook_edit: {
98
+ riskLevel: RISK_LEVELS.MEDIUM,
99
+ category: TOOL_CATEGORIES.WRITE,
100
+ availableInPlanMode: false,
101
+ planModeBehavior: "blocked",
102
+ requiresPlanApproval: true,
103
+ requiresConfirmation: false,
104
+ approvalFlow: "plan",
105
+ isReadOnly: false,
106
+ },
97
107
  run_shell: {
98
108
  riskLevel: RISK_LEVELS.HIGH,
99
109
  category: TOOL_CATEGORIES.EXECUTE,
@@ -110,6 +110,28 @@ function looksBinary(buf) {
110
110
  return false;
111
111
  }
112
112
 
113
+ /**
114
+ * Read at most `limit` bytes from the start of a file. A plain `@file` only
115
+ * ever shows the first `maxBytes`, so reading the whole thing into memory first
116
+ * (readFileSync) would allocate the entire file — pointless for a 300 MB log and
117
+ * a hard failure for files > 2 GB. We read `limit` bytes so truncation can still
118
+ * be detected (caller passes maxBytes + 1). Falls back to readFileSync if the
119
+ * injected fs lacks the lower-level calls.
120
+ */
121
+ function readBoundedFile(fs, abs, limit) {
122
+ if (typeof fs.openSync !== "function" || typeof fs.readSync !== "function") {
123
+ return fs.readFileSync(abs);
124
+ }
125
+ const fd = fs.openSync(abs, "r");
126
+ try {
127
+ const buf = Buffer.alloc(limit);
128
+ const n = fs.readSync(fd, buf, 0, limit, 0);
129
+ return buf.subarray(0, n);
130
+ } finally {
131
+ fs.closeSync(fd);
132
+ }
133
+ }
134
+
113
135
  /**
114
136
  * Resolve a single raw token to an injectable ref descriptor, or null when it
115
137
  * does not resolve to an existing path. Tries the literal path first, then a
@@ -159,9 +181,15 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
159
181
  };
160
182
  }
161
183
  if (stat.isFile()) {
184
+ // PDFs (pdf-parse needs the bytes) and line ranges (must reach the end
185
+ // line) need the whole file; a plain inline only ever shows the first
186
+ // maxBytes, so cap the read there instead of slurping the entire file.
187
+ const needsWholeFile = isPdf(fsPath) || range != null;
162
188
  let buf;
163
189
  try {
164
- buf = fs.readFileSync(abs);
190
+ buf = needsWholeFile
191
+ ? fs.readFileSync(abs)
192
+ : readBoundedFile(fs, abs, maxBytes + 1);
165
193
  } catch (err) {
166
194
  return {
167
195
  kind: "error",
@@ -414,6 +414,40 @@ export async function runAgentHeadless(options = {}, deps = {}) {
414
414
  writeErr("No previous session to continue; starting a new one.\n");
415
415
  }
416
416
 
417
+ // Machine-readable modes (`--output-format json` / `stream-json`) must ALWAYS
418
+ // end with a terminal result envelope — a consumer parsing stdout otherwise
419
+ // gets nothing and can't tell success from failure. Several setup-phase error
420
+ // paths below early-return BEFORE the main loop's try/catch envelope (and
421
+ // before `system/init`), so route them through this so stdout is never empty.
422
+ // No-op in text mode (those paths already writeErr a human message).
423
+ const emitHeadlessError = (resultMsg) => {
424
+ if (isStream) {
425
+ writeOut(
426
+ JSON.stringify({
427
+ type: "result",
428
+ subtype: "error",
429
+ is_error: true,
430
+ error: resultMsg,
431
+ }) + "\n",
432
+ );
433
+ } else if (isJson) {
434
+ writeOut(
435
+ JSON.stringify(
436
+ buildResultEnvelope({
437
+ subtype: "error",
438
+ isError: true,
439
+ result: resultMsg,
440
+ sessionId,
441
+ toolCalls: [],
442
+ usage: {},
443
+ numTurns: 0,
444
+ durationMs: 0,
445
+ }),
446
+ ) + "\n",
447
+ );
448
+ }
449
+ };
450
+
417
451
  // Load prior conversation when resuming an existing session. The fresh
418
452
  // system prompt always leads; we drop any persisted system turns so it is
419
453
  // never duplicated.
@@ -489,11 +523,9 @@ export async function runAgentHeadless(options = {}, deps = {}) {
489
523
  writeErr(
490
524
  `[hook] prompt blocked${ups.reason ? ": " + ups.reason : ""}\n`,
491
525
  );
492
- return {
493
- exitCode: 2,
494
- result: ups.reason || "blocked by UserPromptSubmit hook",
495
- isError: true,
496
- };
526
+ const reason = ups.reason || "blocked by UserPromptSubmit hook";
527
+ emitHeadlessError(reason);
528
+ return { exitCode: 2, result: reason, isError: true };
497
529
  }
498
530
  if (ups.additionalContext) {
499
531
  userContent += `\n\n[hook context]\n${ups.additionalContext}`;
@@ -575,6 +607,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
575
607
  // registered (cc mcp add) + IDE bridge auto-discovery.
576
608
  strict: options.strictMcpConfig === true,
577
609
  ide: options.ide,
610
+ pdh: options.pdh,
578
611
  cwd: options.cwd || process.cwd(),
579
612
  // advertise the session id to spawned stdio MCP servers
580
613
  sessionId,
@@ -593,6 +626,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
593
626
  }
594
627
  } catch (err) {
595
628
  writeErr(`Error: ${err.message}\n`);
629
+ emitHeadlessError(err.message);
596
630
  return { exitCode: 1, result: err.message, isError: true };
597
631
  }
598
632
  }
@@ -635,6 +669,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
635
669
  } catch (err) {
636
670
  writeErr(`Error: ${err.message}\n`);
637
671
  if (mcp?.mcpClient) await mcp.mcpClient.disconnectAll().catch(() => {});
672
+ emitHeadlessError(err.message);
638
673
  return { exitCode: 1, result: err.message, isError: true };
639
674
  }
640
675
  if (approvalGate && typeof approvalGate.setConfirmer === "function") {
@@ -726,7 +761,12 @@ export async function runAgentHeadless(options = {}, deps = {}) {
726
761
 
727
762
  const startedAt = deps.now ? deps.now() : Date.now();
728
763
  const toolCalls = [];
729
- const usage = { input_tokens: 0, output_tokens: 0 };
764
+ const usage = {
765
+ input_tokens: 0,
766
+ output_tokens: 0,
767
+ cache_read_input_tokens: 0,
768
+ cache_creation_input_tokens: 0,
769
+ };
730
770
  let finalText = "";
731
771
  let endReason = "complete";
732
772
  let stopForCost = false;
@@ -803,6 +843,11 @@ export async function runAgentHeadless(options = {}, deps = {}) {
803
843
  case "token-usage": {
804
844
  usage.input_tokens += event.usage?.input_tokens || 0;
805
845
  usage.output_tokens += event.usage?.output_tokens || 0;
846
+ // Carry prompt-cache tokens into accumulated usage (cost accuracy).
847
+ usage.cache_read_input_tokens +=
848
+ event.usage?.cache_read_input_tokens || 0;
849
+ usage.cache_creation_input_tokens +=
850
+ event.usage?.cache_creation_input_tokens || 0;
806
851
  emitStream({ type: "token_usage", usage: event.usage });
807
852
  if (costBudget) {
808
853
  costBudget.add({
@@ -102,6 +102,46 @@ export function parseInputEvent(line) {
102
102
  if (!obj.id) return null;
103
103
  return { approval: { id: String(obj.id), approve: obj.approve === true } };
104
104
  }
105
+ // Answer to an ask_user_question (panel QuickPick for interactive questions):
106
+ // {"type":"answer","id":"q-1","answer":<string|string[]|null>}
107
+ // A null/absent answer cancels (handler → user_timeout, model proceeds).
108
+ if (obj && typeof obj === "object" && obj.type === "answer") {
109
+ if (!obj.id) return null;
110
+ return {
111
+ answer: {
112
+ id: String(obj.id),
113
+ value: obj.answer === undefined ? null : obj.answer,
114
+ },
115
+ };
116
+ }
117
+ // PDH self-learning feedback (design module 101 §3.5.13). The personal-data
118
+ // chat's 纠正卡 sends {"type":"feedback","turn_id":…,"kind":"positive"|
119
+ // "negative"|"correction","comment":…} after a reply. A missing kind → skip.
120
+ if (obj && typeof obj === "object" && obj.type === "feedback") {
121
+ const kind = String(obj.kind || "").toLowerCase();
122
+ if (!kind) return null;
123
+ return {
124
+ feedback: {
125
+ turnId: obj.turn_id != null ? String(obj.turn_id) : null,
126
+ kind,
127
+ comment: typeof obj.comment === "string" ? obj.comment : null,
128
+ },
129
+ };
130
+ }
131
+ // PDH guided-collection resume (design module 101 §3.5.15). When a PDH tool
132
+ // returns assist_required (e.g. "log into the app first") the chat's 引导卡
133
+ // sends {"type":"resume","token":…,"action":"completed"|"skip"} once the user
134
+ // finishes or skips the in-app step. A missing action → skip.
135
+ if (obj && typeof obj === "object" && obj.type === "resume") {
136
+ const action = String(obj.action || "").toLowerCase();
137
+ if (!action) return null;
138
+ return {
139
+ resume: {
140
+ token: obj.token != null ? String(obj.token) : null,
141
+ action,
142
+ },
143
+ };
144
+ }
105
145
  const msg = obj && typeof obj === "object" ? obj.message || obj : {};
106
146
  let content = msg.content ?? obj.text ?? obj.prompt;
107
147
  if (Array.isArray(content)) {
@@ -147,14 +187,24 @@ export function parseInputEvent(line) {
147
187
  */
148
188
  export async function* readJsonLines(input) {
149
189
  let buf = "";
190
+ // Reuse ONE streaming decoder across chunks so a multi-byte UTF-8 character
191
+ // (e.g. a 3-byte Chinese char) split across two Buffer chunks is reassembled
192
+ // rather than corrupted. process.stdin yields Buffers with no setEncoding, so
193
+ // a per-chunk `chunk.toString("utf-8")` would turn a split character into
194
+ // U+FFFD replacement chars.
195
+ const decoder = new TextDecoder();
150
196
  for await (const chunk of input) {
151
- buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
197
+ buf +=
198
+ typeof chunk === "string"
199
+ ? chunk
200
+ : decoder.decode(chunk, { stream: true });
152
201
  let idx;
153
202
  while ((idx = buf.indexOf("\n")) >= 0) {
154
203
  yield buf.slice(0, idx);
155
204
  buf = buf.slice(idx + 1);
156
205
  }
157
206
  }
207
+ buf += decoder.decode(); // flush any bytes held from a final partial char
158
208
  if (buf.trim()) yield buf;
159
209
  }
160
210
 
@@ -163,7 +213,12 @@ export async function* readJsonLines(input) {
163
213
  * Returns the turn outcome so the caller can grow history + the result line.
164
214
  */
165
215
  async function runTurn(messages, loopOptions, { runLoop, emit, costBudget }) {
166
- const usage = { input_tokens: 0, output_tokens: 0 };
216
+ const usage = {
217
+ input_tokens: 0,
218
+ output_tokens: 0,
219
+ cache_read_input_tokens: 0,
220
+ cache_creation_input_tokens: 0,
221
+ };
167
222
  const toolCalls = [];
168
223
  let finalText = "";
169
224
  let endReason = "complete";
@@ -191,6 +246,12 @@ async function runTurn(messages, loopOptions, { runLoop, emit, costBudget }) {
191
246
  case "token-usage":
192
247
  usage.input_tokens += event.usage?.input_tokens || 0;
193
248
  usage.output_tokens += event.usage?.output_tokens || 0;
249
+ // Carry prompt-cache tokens into the turn's accumulated usage so the
250
+ // final `result` envelope (read by IDE panels) reflects caching too.
251
+ usage.cache_read_input_tokens +=
252
+ event.usage?.cache_read_input_tokens || 0;
253
+ usage.cache_creation_input_tokens +=
254
+ event.usage?.cache_creation_input_tokens || 0;
194
255
  emit({ type: "token_usage", usage: event.usage });
195
256
  if (costBudget) {
196
257
  costBudget.add({
@@ -404,6 +465,65 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
404
465
  approvalGate = null;
405
466
  }
406
467
 
468
+ // ── Interactive questions (ask_user_question round-trip; chat-panel UX) ────
469
+ // Same structured pattern as approvals: when the consumer opts in (the IDE
470
+ // panel sets CC_INTERACTIVE_QUESTIONS=1 in the child env), the model's
471
+ // `ask_user_question` tool emits `question_request`, BLOCKS until a
472
+ // {"type":"answer",id,answer} arrives on stdin, and times out gracefully
473
+ // (CC_QUESTION_TIMEOUT_MS, default 180s) — the handler maps the timeout to
474
+ // user_timeout so the model proceeds, never a hard failure. Off by default
475
+ // (env unset / pipes) → agent-core gets no askUser → user_not_reachable, the
476
+ // existing graceful "proceed autonomously" path. Backward-safe: an env var
477
+ // (not a flag) means an old `cc` simply ignores it.
478
+ const interactiveQuestions =
479
+ options.interactiveQuestions === true ||
480
+ process.env.CC_INTERACTIVE_QUESTIONS === "1";
481
+ const pendingQuestions = new Map();
482
+ let questionSeq = 0;
483
+ const questionTimeoutMs =
484
+ Number(process.env.CC_QUESTION_TIMEOUT_MS) > 0
485
+ ? Number(process.env.CC_QUESTION_TIMEOUT_MS)
486
+ : 180000;
487
+ const settleQuestion = (id, answer, via) => {
488
+ const p = pendingQuestions.get(id);
489
+ if (!p) return;
490
+ pendingQuestions.delete(id);
491
+ clearTimeout(p.timer);
492
+ emit({ type: "question_resolved", id, via, session_id: sessionId });
493
+ p.resolve(answer);
494
+ };
495
+ const failQuestion = (id, via) => {
496
+ const p = pendingQuestions.get(id);
497
+ if (!p) return;
498
+ pendingQuestions.delete(id);
499
+ clearTimeout(p.timer);
500
+ emit({ type: "question_resolved", id, via, session_id: sessionId });
501
+ const e = new Error(`ask_user_question ${via}`);
502
+ e.code = "USER_TIMEOUT"; // handler → user_timeout (model proceeds, not a failure)
503
+ p.reject(e);
504
+ };
505
+ const interactionAskUser = ({
506
+ question,
507
+ options: qOptions,
508
+ multiSelect,
509
+ timeoutMs,
510
+ } = {}) =>
511
+ new Promise((resolve, reject) => {
512
+ const id = `q-${++questionSeq}`;
513
+ const ms = Number(timeoutMs) > 0 ? Number(timeoutMs) : questionTimeoutMs;
514
+ const timer = setTimeout(() => failQuestion(id, "timeout"), ms);
515
+ timer.unref?.();
516
+ pendingQuestions.set(id, { resolve, reject, timer });
517
+ emit({
518
+ type: "question_request",
519
+ id,
520
+ session_id: sessionId,
521
+ question: typeof question === "string" ? question : "",
522
+ options: Array.isArray(qOptions) ? qOptions : null,
523
+ multiSelect: multiSelect === true,
524
+ });
525
+ });
526
+
407
527
  // --output-style (or settings.json `outputStyle`) persona, appended.
408
528
  let outputStyleBody = null;
409
529
  try {
@@ -423,6 +543,27 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
423
543
  );
424
544
  const messages = [{ role: "system", content: systemContent }];
425
545
 
546
+ // §3.5.13 flywheel consumption (design module 101): in a PDH session, lead
547
+ // with the user's standing feedback preferences learned ACROSS sessions
548
+ // (corrections + net sentiment) so the agent honours past corrections from
549
+ // the very first turn — the read side of pdh-feedback-ledger.js. Gated to PDH
550
+ // context (the in-APK chat sets CHAINLESSCHAIN_PDH_PORT; `--pdh` forces,
551
+ // `--no-pdh` opts out) so IDE/coding sessions are never polluted. Best-effort.
552
+ try {
553
+ const { isInPdhTerminal } = await import("../lib/pdh-bridge.js");
554
+ const pdhContext =
555
+ options.pdh === true ||
556
+ (options.pdh !== false && isInPdhTerminal(process.env));
557
+ if (pdhContext) {
558
+ const { readFeedback, summarizeFeedback, feedbackSystemNote } =
559
+ await import("../lib/pdh-feedback-ledger.js");
560
+ const note = feedbackSystemNote(summarizeFeedback(readFeedback()));
561
+ if (note) messages.push({ role: "system", content: note });
562
+ }
563
+ } catch {
564
+ /* learned-preference injection must never break the chat */
565
+ }
566
+
426
567
  // settings.json SessionStart hooks → inject session context once (observe-only).
427
568
  if (settingsHooks) {
428
569
  try {
@@ -512,6 +653,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
512
653
  // registered + IDE bridge) for a reproducible MCP surface.
513
654
  strict: options.strictMcpConfig === true,
514
655
  ide: options.ide,
656
+ pdh: options.pdh,
515
657
  cwd: options.cwd || process.cwd(),
516
658
  // advertise the session id to spawned stdio MCP servers
517
659
  sessionId,
@@ -591,6 +733,12 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
591
733
  // edit reviews via openDiff) route to the structured approval round-trip
592
734
  // instead of failing closed. Absent in CI/pipes → unchanged fail-closed.
593
735
  permissionConfirm: interactive ? interactiveConfirm : undefined,
736
+ // ask_user_question round-trip (opt-in via CC_INTERACTIVE_QUESTIONS): give
737
+ // the tool handler an askUser that emits question_request + blocks on stdin.
738
+ // Absent → agent-core returns user_not_reachable (graceful proceed).
739
+ interaction: interactiveQuestions
740
+ ? { askUser: interactionAskUser }
741
+ : undefined,
594
742
  prepareCall: goalPrepareCallFn,
595
743
  // --mcp-config wiring (tool defs + dispatch map + live client).
596
744
  mcpClient: mcp?.mcpClient || null,
@@ -684,6 +832,19 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
684
832
  );
685
833
  continue;
686
834
  }
835
+ if (parsed.answer) {
836
+ // Answers settle a BLOCKED ask_user_question — never queued. A null
837
+ // value (user cancelled the QuickPick) → user_timeout (model proceeds).
838
+ if (parsed.answer.value == null)
839
+ failQuestion(parsed.answer.id, "cancelled");
840
+ else
841
+ settleQuestion(
842
+ parsed.answer.id,
843
+ parsed.answer.value,
844
+ "user-answer",
845
+ );
846
+ continue;
847
+ }
687
848
  queue.push(parsed);
688
849
  if (wakeQueue) wakeQueue();
689
850
  }
@@ -696,6 +857,10 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
696
857
  for (const id of [...pendingApprovals.keys()]) {
697
858
  settleApproval(id, false, "stdin-closed");
698
859
  }
860
+ // stdin closed while a question was pending → user_timeout (model proceeds).
861
+ for (const id of [...pendingQuestions.keys()]) {
862
+ failQuestion(id, "stdin-closed");
863
+ }
699
864
  if (wakeQueue) wakeQueue();
700
865
  })();
701
866
  const nextEvent = async () => {
@@ -805,6 +970,58 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
805
970
  }
806
971
  }
807
972
 
973
+ // PDH self-learning feedback (design module 101 §3.5.13). Always ack so the
974
+ // chat app can confirm receipt. A `correction` re-drives a turn so the model
975
+ // adapts within the session; `positive`/`negative` are recorded as a
976
+ // lightweight preference note in history without forcing a fresh reply.
977
+ if (parsed.feedback) {
978
+ const { turnId, kind, comment } = parsed.feedback;
979
+ emit({
980
+ type: "feedback_ack",
981
+ turn_id: turnId,
982
+ kind,
983
+ session_id: sessionId,
984
+ });
985
+ // §3.5.13: persist to the cross-session learning ledger so the next
986
+ // session can honour the user's standing preferences ("越用越聪明"
987
+ // flywheel). Best-effort — a learning ledger must never break the chat.
988
+ try {
989
+ const { appendFeedback } =
990
+ await import("../lib/pdh-feedback-ledger.js");
991
+ appendFeedback({ sessionId, turnId, kind, comment });
992
+ } catch {
993
+ /* persistence is best-effort */
994
+ }
995
+ if (kind === "correction") {
996
+ parsed.text = comment
997
+ ? `用户对上一轮回复给出纠正:${comment}\n请据此调整并重新回复。`
998
+ : "用户认为上一轮回复需要纠正,请反思后给出更准确的回复。";
999
+ // fall through into the normal turn machinery with the correction prompt
1000
+ } else {
1001
+ const tag = kind === "positive" ? "认可" : "不满意";
1002
+ messages.push({
1003
+ role: "user",
1004
+ content: `(用户反馈:对上一轮回复表示${tag}。请在后续回复中延续/修正此偏好。)`,
1005
+ });
1006
+ continue;
1007
+ }
1008
+ }
1009
+
1010
+ // PDH guided-collection resume (design module 101 §3.5.15). A PDH tool
1011
+ // returned assist_required (e.g. "log into the app first"); the chat's 引导卡
1012
+ // sends a resume once the user finishes or skips the in-app step. Ack so the
1013
+ // app can dismiss the card, then re-drive the model to retry (completed) or
1014
+ // move on (skip).
1015
+ if (parsed.resume) {
1016
+ const { token, action } = parsed.resume;
1017
+ emit({ type: "resume_ack", token, action, session_id: sessionId });
1018
+ parsed.text =
1019
+ action === "skip"
1020
+ ? "我跳过了刚才需要的引导操作,请不要重试该步骤,继续处理其它事项或做个小结。"
1021
+ : "我已完成刚才需要的引导操作,请重试刚才的采集/操作。";
1022
+ // fall through into the normal turn machinery with the continuation prompt
1023
+ }
1024
+
808
1025
  // --replay-user-messages: echo each accepted user message back on the
809
1026
  // output stream (Claude-Code parity) so a consumer can correlate replies to
810
1027
  // inputs / log the transcript. Echoes the raw user text, before @file or
@@ -96,7 +96,21 @@ export async function execute({ section_idx, shot_idx, clips }, context) {
96
96
  try {
97
97
  const raw = await fs.readFile(context.shotPointPath, "utf-8");
98
98
  existing = JSON.parse(raw);
99
- } catch {}
99
+ if (!Array.isArray(existing)) {
100
+ throw new Error("shot-point log is not a JSON array");
101
+ }
102
+ } catch (err) {
103
+ // A missing file is the normal first-commit case — start fresh. Any other
104
+ // error (parse failure / wrong shape on an existing file, permission)
105
+ // means the log is present but unreadable; appending to a fresh [] would
106
+ // silently discard every previously committed clip, so surface it instead
107
+ // of clobbering.
108
+ if (err.code !== "ENOENT") {
109
+ throw new Error(
110
+ `Refusing to overwrite shot-point log ${context.shotPointPath}: ${err.message}`,
111
+ );
112
+ }
113
+ }
100
114
  existing.push(entry);
101
115
  await fs.writeFile(
102
116
  context.shotPointPath,
@@ -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 m}from"./vendor-BvqAck49.js";import{_ as v,b}from"./index-DmrPbYXh.js";import{a7 as y,M}from"./icons-DP3uiYxy.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=b();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 b},get MobileOutlined(){return M},get FolderOutlined(){return y}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",k,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",w,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),m(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),m(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const I=v(B,[["render",T],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-94r5Fm/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{I as default};
@@ -1 +0,0 @@
1
- import{I as i,J as I,U,R as s,Q as r,c as t,K as a,V as _,S as x,o as oe,b as ee,r as u,P as p,F as ne,a2 as ge}from"./vendor-BvqAck49.js";import{_ as we,b as re,u as ie,d}from"./index-DmrPbYXh.js";import{u as de}from"./useShellMode-CgR0wCYM.js";import{aM as ke,aN as Fe,aO as be,f as je,a4 as Ce,a7 as xe,as as Oe,R as Se}from"./icons-DP3uiYxy.js";const Pe={__name:"Projects",setup(se,{expose:l}){l();const{t:te}=re(),e=ie(),{isEmbedded:W}=de();async function w(o,f,ye,ae=8e3){if(W){const Z=await e.sendRaw({...f,type:o},ae);if(!Z?.ok){const $=Z?.error;throw new Error(typeof $=="string"?$:$?.message||`${o} failed`)}return Z.result}return e.executeJson(ye,ae)}const B=u(!1),y=u([]),O=u(""),S=u(""),P=u(!1),v=u(null),h=u([]),k=u(!1),E=u(!1),L=u(!1),F=u({name:"",description:"",type:"document",rootPath:""}),z=[{title:"ID",key:"id",width:110},{title:"名称",key:"name"},{title:"类型",key:"project_type",width:120},{title:"状态",key:"status",width:100},{title:"同步",key:"sync_status",width:100},{title:"更新",key:"updated_at",width:160},{title:"操作",key:"actions",width:180,fixed:"right"}],M=ee(()=>{const o={active:0,draft:0,completed:0,archived:0};for(const f of y.value)o[f.status]!==void 0&&(o[f.status]+=1);return o}),J=ee(()=>y.value.filter(o=>!(O.value&&o.status!==O.value||S.value&&!o.name.toLowerCase().includes(S.value.toLowerCase()))));function g(o){switch(o){case"active":return"green";case"draft":return"default";case"completed":return"cyan";case"archived":return"gold";default:return"default"}}function K(o){switch(o){case"synced":return"green";case"pending":return"orange";case"conflict":return"red";case"error":return"red";default:return"default"}}function Q(o){return!o&&o!==0?"-":new Date(typeof o=="number"?o:parseInt(o,10)).toLocaleString("zh-CN",{hour12:!1})}async function C(){B.value=!0;try{const o=await w("project.list",{limit:500},"project list --limit 500 --json",1e4);y.value=Array.isArray(o?.projects)?o.projects:Array.isArray(o)?o:[]}catch(o){d.error("加载失败: "+(o.message||o)),y.value=[]}finally{B.value=!1}}function G(o){return{onClick:()=>V(o)}}async function V(o){v.value=o,P.value=!0,k.value=!0,h.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);h.value=Array.isArray(f?.files)?f.files:[]}catch{h.value=[]}finally{k.value=!1}}async function H(o){try{(await w("project.delete",{id:o.id},`project delete ${o.id} --json`,8e3))?.ok?(d.success(`已删除项目 '${o.name}'`),P.value=!1,await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}function X(){F.value={name:"",description:"",type:"document",rootPath:""},E.value=!0}async function T(){if(!F.value.name.trim()){d.warning("请输入项目名称");return}L.value=!0;try{const o=await w("project.init",{name:F.value.name.trim(),description:F.value.description||null,projectType:F.value.type,rootPath:F.value.rootPath||null},`project init "${F.value.name.trim()}" --type ${F.value.type} --json`,8e3);o?.id?(d.success(`已创建项目 '${o.name}'`),E.value=!1,await C()):d.error("创建失败")}catch(o){d.error(o.message||String(o))}finally{L.value=!1}}const b=u(!1),D=u(!1),j=u({path:"",content:""}),A=u(!1),m=u(!1),R=u({path:""}),n=u(!1),c=u(null),q=u(""),Y=u(!1);function ue(){j.value={path:"",content:""},b.value=!0}function ce(){R.value={path:""},A.value=!0}async function N(){if(v.value){k.value=!0;try{const o=await w("project.listFiles",{projectId:v.value.id,limit:200},`project list-files ${v.value.id} --json`,8e3);h.value=Array.isArray(o?.files)?o.files:[]}catch(o){d.error("刷新文件失败: "+(o.message||o))}finally{k.value=!1}}}async function fe(){if(!j.value.path.trim()){d.warning("请输入文件路径");return}if(v.value){D.value=!0;try{const o=await w("project.createFile",{projectId:v.value.id,filePath:j.value.path.trim(),content:j.value.content||""},`project create-file ${v.value.id} "${j.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件 '${o.file_name}'`),b.value=!1,await N(),await C()):d.error("创建文件失败")}catch(o){d.error(o.message||String(o))}finally{D.value=!1}}}async function pe(){if(!R.value.path.trim()){d.warning("请输入文件夹路径");return}if(v.value){m.value=!0;try{const o=await w("project.createFolder",{projectId:v.value.id,folderPath:R.value.path.trim()},`project create-folder ${v.value.id} "${R.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件夹 '${o.file_name}'`),A.value=!1,await N(),await C()):d.error("创建文件夹失败")}catch(o){d.error(o.message||String(o))}finally{m.value=!1}}}async function ve(o){try{(await w("project.deleteFile",{fileId:o.id},`project delete-file ${o.id} --json`,8e3))?.deleted?(d.success(`已删除 '${o.file_name}'`),await N(),await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}async function me(o){if(o.is_folder){d.info("文件夹无内容可编辑");return}try{const f=await w("project.getFile",{fileId:o.id},`project get-file ${o.id} --json`,8e3);c.value=o,q.value=f?.content||"",n.value=!0}catch(f){d.error("读取文件失败: "+(f.message||f))}}async function _e(){if(c.value){Y.value=!0;try{(await w("project.writeFile",{fileId:c.value.id,content:q.value},`project write-file ${c.value.id} --json`,8e3))?.id?(d.success("已保存"),n.value=!1,await N()):d.error("保存失败")}catch(o){d.error(o.message||String(o))}finally{Y.value=!1}}}oe(()=>{C()});const le={t:te,ws:e,isEmbedded:W,callProjectTopic:w,loading:B,projects:y,statusFilter:O,nameFilter:S,detailOpen:P,detail:v,files:h,filesLoading:k,createOpen:E,creating:L,newProject:F,columns:z,countByStatus:M,filteredProjects:J,statusColor:g,syncColor:K,formatTime:Q,loadAll:C,onRowClick:G,openDetail:V,onDelete:H,onShowCreate:X,onCreate:T,createFileOpen:b,creatingFile:D,newFile:j,createFolderOpen:A,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:N,onCreateFile:fe,onCreateFolder:pe,onDeleteFile:ve,openEditFile:me,onSaveFile:_e,ref:u,computed:ee,onMounted:oe,get ReloadOutlined(){return Se},get PlusOutlined(){return Oe},get FolderOutlined(){return xe},get FileTextOutlined(){return Ce},get CheckCircleOutlined(){return je},get CheckSquareOutlined(){return be},get FileAddOutlined(){return Fe},get FolderAddOutlined(){return ke},get message(){return d},get useI18n(){return re},get useWsStore(){return ie},get useShellMode(){return de}};return Object.defineProperty(le,"__isScriptSetup",{enumerable:!1,value:!0}),le}},ze={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},Ae={class:"page-title"},Ie={class:"page-sub"},Ue={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},he={key:0,style:{"font-size":"12px",color:"#888"}},De={key:0,style:{color:"#888","font-size":"12px"}},Re={key:0},Te={key:1,style:{color:"#888"}},Be=["onClick"],Ee={key:0,style:{color:"#888","font-size":"12px"}};function Le(se,l,te,e,W,w){const B=i("router-link"),y=i("a-button"),O=i("a-space"),S=i("a-statistic"),P=i("a-card"),v=i("a-col"),h=i("a-row"),k=i("a-radio-button"),E=i("a-radio-group"),L=i("a-input-search"),F=i("a-alert"),z=i("a-tag"),M=i("a-popconfirm"),J=i("a-table"),g=i("a-descriptions-item"),K=i("a-descriptions"),Q=i("a-divider"),C=i("a-empty"),G=i("a-list-item"),V=i("a-list"),H=i("a-spin"),X=i("a-drawer"),T=i("a-input"),b=i("a-form-item"),D=i("a-textarea"),j=i("a-form"),A=i("a-modal"),m=i("a-select-option"),R=i("a-select");return p(),I("div",null,[U("div",ze,[U("div",null,[U("h2",Ae,s(e.t("projects.title")),1),U("p",Ie,[l[17]||(l[17]=r("桌面 / CLI / 手机 三端共享同一份项目数据,Phase 3d sync 自动同步 (",-1)),t(B,{to:"/project-init"},{default:a(()=>[...l[16]||(l[16]=[r("项目初始化 / 环境设置",-1)])]),_:1}),l[18]||(l[18]=r(")",-1))])]),t(O,null,{default:a(()=>[t(y,{loading:e.loading,onClick:e.loadAll},{icon:a(()=>[t(e.ReloadOutlined)]),default:a(()=>[l[19]||(l[19]=r(" 刷新 ",-1))]),_:1},8,["loading"]),t(y,{type:"primary",onClick:e.onShowCreate},{icon:a(()=>[t(e.PlusOutlined)]),default:a(()=>[l[20]||(l[20]=r(" 新建项目 ",-1))]),_:1})]),_:1})]),_(" Stats "),t(h,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:a(()=>[t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"总项目",value:e.projects.length,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:a(()=>[t(e.FolderOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"活跃",value:e.countByStatus.active,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckCircleOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"草稿",value:e.countByStatus.draft,"value-style":{color:"#8c8c8c",fontSize:"20px"}},{prefix:a(()=>[t(e.FileTextOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"已完成",value:e.countByStatus.completed,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckSquareOutlined)]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),_(" Filter "),U("div",Ue,[t(E,{value:e.statusFilter,"onUpdate:value":l[0]||(l[0]=n=>e.statusFilter=n),size:"small","button-style":"solid"},{default:a(()=>[t(k,{value:""},{default:a(()=>[...l[21]||(l[21]=[r("全部",-1)])]),_:1}),t(k,{value:"active"},{default:a(()=>[...l[22]||(l[22]=[r("活跃",-1)])]),_:1}),t(k,{value:"draft"},{default:a(()=>[...l[23]||(l[23]=[r("草稿",-1)])]),_:1}),t(k,{value:"completed"},{default:a(()=>[...l[24]||(l[24]=[r("已完成",-1)])]),_:1}),t(k,{value:"archived"},{default:a(()=>[...l[25]||(l[25]=[r("已归档",-1)])]),_:1})]),_:1},8,["value"]),t(L,{value:e.nameFilter,"onUpdate:value":l[1]||(l[1]=n=>e.nameFilter=n),placeholder:"按名称过滤",style:{"max-width":"260px"},"allow-clear":""},null,8,["value"])]),!e.projects.length&&!e.loading?(p(),x(F,{key:0,type:"info",message:"还没有项目",description:'运行 `cc project init <name>` 或点击右上角"新建项目"按钮创建。桌面 / CLI / 手机三端共享同一份数据。',"show-icon":"",style:{"margin-bottom":"16px"}})):_("v-if",!0),e.projects.length||e.loading?(p(),x(J,{key:1,columns:e.columns,"data-source":e.filteredProjects,loading:e.loading,pagination:{pageSize:20,showSizeChanger:!0},"row-key":"id","custom-row":e.onRowClick},{bodyCell:a(({column:n,record:c})=>[n.key==="id"?(p(),I("code",he,s(c.id.slice(0,8))+"…",1)):n.key==="name"?(p(),I(ne,{key:1},[U("strong",null,s(c.name),1),c.description?(p(),I("div",De,s(c.description),1)):_("v-if",!0)],64)):n.key==="project_type"?(p(),x(z,{key:2},{default:a(()=>[r(s(c.project_type),1)]),_:2},1024)):n.key==="status"?(p(),x(z,{key:3,color:e.statusColor(c.status)},{default:a(()=>[r(s(c.status),1)]),_:2},1032,["color"])):n.key==="sync_status"?(p(),x(z,{key:4,color:e.syncColor(c.sync_status)},{default:a(()=>[r(s(c.sync_status||"unknown"),1)]),_:2},1032,["color"])):n.key==="updated_at"?(p(),I(ne,{key:5},[r(s(e.formatTime(c.updated_at)),1)],64)):n.key==="actions"?(p(),x(O,{key:6,onClick:l[2]||(l[2]=ge(()=>{},["stop"]))},{default:a(()=>[t(y,{size:"small",onClick:q=>e.openDetail(c)},{default:a(()=>[...l[26]||(l[26]=[r("详情",-1)])]),_:1},8,["onClick"]),t(M,{title:`删除项目 '${c.name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:q=>e.onDelete(c)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[27]||(l[27]=[r("删除",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)):_("v-if",!0)]),_:1},8,["data-source","loading"])):_("v-if",!0),_(" Detail drawer "),t(X,{open:e.detailOpen,"onUpdate:open":l[3]||(l[3]=n=>e.detailOpen=n),title:e.detail?.name||"项目详情",width:"640",placement:"right"},{default:a(()=>[e.detail?(p(),x(K,{key:0,column:1,bordered:"",size:"small"},{default:a(()=>[t(g,{label:"ID"},{default:a(()=>[U("code",null,s(e.detail.id),1)]),_:1}),t(g,{label:"名称"},{default:a(()=>[r(s(e.detail.name),1)]),_:1}),t(g,{label:"描述"},{default:a(()=>[r(s(e.detail.description||"-"),1)]),_:1}),t(g,{label:"类型"},{default:a(()=>[t(z,null,{default:a(()=>[r(s(e.detail.project_type),1)]),_:1})]),_:1}),t(g,{label:"状态"},{default:a(()=>[t(z,{color:e.statusColor(e.detail.status)},{default:a(()=>[r(s(e.detail.status),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"同步状态"},{default:a(()=>[t(z,{color:e.syncColor(e.detail.sync_status)},{default:a(()=>[r(s(e.detail.sync_status||"unknown"),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"用户"},{default:a(()=>[r(s(e.detail.user_id),1)]),_:1}),t(g,{label:"根路径"},{default:a(()=>[e.detail.root_path?(p(),I("code",Re,s(e.detail.root_path),1)):(p(),I("span",Te,"(无)"))]),_:1}),t(g,{label:"文件数"},{default:a(()=>[r(s(e.detail.file_count||0),1)]),_:1}),t(g,{label:"创建"},{default:a(()=>[r(s(e.formatTime(e.detail.created_at)),1)]),_:1}),t(g,{label:"更新"},{default:a(()=>[r(s(e.formatTime(e.detail.updated_at)),1)]),_:1})]),_:1})):_("v-if",!0),t(Q,null,{default:a(()=>[...l[28]||(l[28]=[r("文件",-1)])]),_:1}),_(" Sub-phase 7.3 (2026-05-17): 文件 CRUD toolbar "),t(O,{style:{"margin-bottom":"12px"}},{default:a(()=>[t(y,{size:"small",type:"primary",disabled:!e.detail,onClick:e.openCreateFile},{default:a(()=>[t(e.FileAddOutlined),l[29]||(l[29]=r(" 新建文件 ",-1))]),_:1},8,["disabled"]),t(y,{size:"small",disabled:!e.detail,onClick:e.openCreateFolder},{default:a(()=>[t(e.FolderAddOutlined),l[30]||(l[30]=r(" 新建文件夹 ",-1))]),_:1},8,["disabled"])]),_:1}),t(H,{spinning:e.filesLoading},{default:a(()=>[!e.files.length&&!e.filesLoading?(p(),x(C,{key:0,description:"无文件 (点上方按钮新建)"})):(p(),x(V,{key:1,size:"small","data-source":e.files},{renderItem:a(({item:n})=>[t(G,null,{extra:a(()=>[t(O,null,{default:a(()=>[n.file_size?(p(),I("span",Ee,s(n.file_size)+" B",1)):_("v-if",!0),t(M,{title:`删除 ${n.is_folder?"文件夹":"文件"} '${n.file_name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:c=>e.onDeleteFile(n)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[31]||(l[31]=[r("×",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)]),default:a(()=>[U("span",{style:{cursor:"pointer"},onClick:c=>e.openEditFile(n)},s(n.is_folder?"📁":"📄")+" "+s(n.file_path),9,Be)]),_:2},1024)]),_:1},8,["data-source"]))]),_:1},8,["spinning"])]),_:1},8,["open","title"]),_(" Sub-phase 7.3: Create file modal "),t(A,{open:e.createFileOpen,"onUpdate:open":l[6]||(l[6]=n=>e.createFileOpen=n),title:"新建文件","confirm-loading":e.creatingFile,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFile},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFile.path,"onUpdate:value":l[4]||(l[4]=n=>e.newFile.path=n),placeholder:"例如 README.md 或 src/main.kt"},null,8,["value"])]),_:1}),t(b,{label:"初始内容(可选)"},{default:a(()=>[t(D,{value:e.newFile.content,"onUpdate:value":l[5]||(l[5]=n=>e.newFile.content=n),rows:6,placeholder:"留空创建空文件"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Create folder modal "),t(A,{open:e.createFolderOpen,"onUpdate:open":l[8]||(l[8]=n=>e.createFolderOpen=n),title:"新建文件夹","confirm-loading":e.creatingFolder,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFolder},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件夹路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFolder.path,"onUpdate:value":l[7]||(l[7]=n=>e.newFolder.path=n),placeholder:"例如 src/utils"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Edit file content modal "),t(A,{open:e.editFileOpen,"onUpdate:open":l[10]||(l[10]=n=>e.editFileOpen=n),title:`编辑 ${e.editingFile?.file_name||""}`,"confirm-loading":e.savingFile,"ok-text":"保存","cancel-text":"取消",onOk:e.onSaveFile,width:"720"},{default:a(()=>[t(D,{value:e.editFileContent,"onUpdate:value":l[9]||(l[9]=n=>e.editFileContent=n),rows:18,"auto-size":{minRows:12,maxRows:24},style:{"font-family":"monospace"}},null,8,["value"])]),_:1},8,["open","title","confirm-loading"]),_(" Create modal "),t(A,{open:e.createOpen,"onUpdate:open":l[15]||(l[15]=n=>e.createOpen=n),title:"新建项目","confirm-loading":e.creating,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreate},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"项目名称",required:""},{default:a(()=>[t(T,{value:e.newProject.name,"onUpdate:value":l[11]||(l[11]=n=>e.newProject.name=n),placeholder:"例如:旅行计划-上海"},null,8,["value"])]),_:1}),t(b,{label:"描述"},{default:a(()=>[t(D,{value:e.newProject.description,"onUpdate:value":l[12]||(l[12]=n=>e.newProject.description=n),rows:2},null,8,["value"])]),_:1}),t(b,{label:"类型"},{default:a(()=>[t(R,{value:e.newProject.type,"onUpdate:value":l[13]||(l[13]=n=>e.newProject.type=n)},{default:a(()=>[t(m,{value:"document"},{default:a(()=>[...l[32]||(l[32]=[r("文档 (document)",-1)])]),_:1}),t(m,{value:"data"},{default:a(()=>[...l[33]||(l[33]=[r("数据 (data)",-1)])]),_:1}),t(m,{value:"web"},{default:a(()=>[...l[34]||(l[34]=[r("Web",-1)])]),_:1}),t(m,{value:"app"},{default:a(()=>[...l[35]||(l[35]=[r("应用 (app)",-1)])]),_:1}),t(m,{value:"presentation"},{default:a(()=>[...l[36]||(l[36]=[r("演示文稿",-1)])]),_:1}),t(m,{value:"spreadsheet"},{default:a(()=>[...l[37]||(l[37]=[r("表格",-1)])]),_:1}),t(m,{value:"design"},{default:a(()=>[...l[38]||(l[38]=[r("设计",-1)])]),_:1}),t(m,{value:"code"},{default:a(()=>[...l[39]||(l[39]=[r("代码",-1)])]),_:1}),t(m,{value:"workflow"},{default:a(()=>[...l[40]||(l[40]=[r("工作流",-1)])]),_:1}),t(m,{value:"knowledge"},{default:a(()=>[...l[41]||(l[41]=[r("知识库",-1)])]),_:1})]),_:1},8,["value"])]),_:1}),t(b,{label:"根路径 (可选)"},{default:a(()=>[t(T,{value:e.newProject.rootPath,"onUpdate:value":l[14]||(l[14]=n=>e.newProject.rootPath=n),placeholder:"留空则仅元数据"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"])])}const We=we(Pe,[["render",Le],["__scopeId","data-v-019ac5aa"],["__file","/tmp/cc-web-panel-94r5Fm/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
@@ -1 +0,0 @@
1
- import{E as V,b as z,r as D,I as p,J as c,U as _,c as n,K as a,S as T,V as w,o as P,x as F,P as i,Q as g,R as r,F as h,Z as B}from"./vendor-BvqAck49.js";import{u as R,_ as O}from"./index-DmrPbYXh.js";import{R as E}from"./icons-DP3uiYxy.js";const I=V("tasks",()=>{const k=D([]),l=D(!1);let u=null,e=null;const x=z(()=>k.value.filter(t=>t.status==="running")),b=z(()=>k.value.filter(t=>t.status==="pending")),y=z(()=>k.value.filter(t=>t.status==="completed"||t.status==="failed"||t.status==="timeout"));async function f(){const t=R();l.value=!0;try{const s=await t.sendRaw({type:"tasks-list"});s&&Array.isArray(s.tasks)&&(k.value=s.tasks)}catch{}finally{l.value=!1}}async function o(t){const s=R();try{await s.sendRaw({type:"tasks-stop",taskId:t})}catch{}finally{await f()}}const d=D(null);function m(t=5e3){v(),f(),u=setInterval(f,t),C()}function v(){u&&(clearInterval(u),u=null),e&&(e(),e=null)}function C(){const t=R();if(e)return;const s=S=>{S.type==="task:notification"&&S.payload?.task&&(d.value=S.payload.task,f(),setTimeout(()=>{d.value=null},8e3))};e=t.onRuntimeEvent(s)}function N(t){return!t||t<0?"-":t<1e3?`${t}ms`:t<6e4?`${(t/1e3).toFixed(1)}s`:`${(t/6e4).toFixed(1)}m`}function A(t){switch(t){case"running":return"processing";case"pending":return"default";case"completed":return"success";case"failed":return"error";case"timeout":return"warning";default:return"default"}}return{tasks:k,loading:l,running:x,pending:b,completed:y,lastNotification:d,fetchTasks:f,stopTask:o,startPolling:m,stopPolling:v,formatDuration:N,getStatusColor:A}}),U={__name:"Tasks",setup(k,{expose:l}){l();const u=I(),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)),F(()=>u.stopPolling());const f={store:u,columns:e,getDuration:x,formatTime:b,truncate:y,onMounted:P,onUnmounted:F,get ReloadOutlined(){return E},get useTasksStore(){return I}};return Object.defineProperty(f,"__isScriptSetup",{enumerable:!1,value:!0}),f}},L={class:"page-header"},j={key:0,class:"error-text"},J={key:1},K={class:"task-header"},M={class:"task-desc"},Q={class:"task-id"},W={class:"task-meta"},Z=["title"],q={key:0,class:"error-text"},G={key:1,class:"success-text"},H={key:2,class:"muted-text"};function X(k,l,u,e,x,b){const y=p("a-button"),f=p("a-space"),o=p("a-alert"),d=p("a-statistic"),m=p("a-card"),v=p("a-col"),C=p("a-row"),N=p("a-tag"),A=p("a-table");return i(),c("div",null,[_("div",L,[l[3]||(l[3]=_("div",null,[_("h2",{class:"page-title"},"后台任务"),_("p",{class:"page-sub"},"查看后台任务队列、实时通知和任务执行结果。")],-1)),n(f,null,{default:a(()=>[n(y,{ghost:"",loading:e.store.loading,onClick:l[0]||(l[0]=t=>e.store.fetchTasks())},{icon:a(()=>[n(e.ReloadOutlined)]),default:a(()=>[l[2]||(l[2]=g(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.store.lastNotification?(i(),T(o,{key:0,type:e.store.lastNotification.status==="completed"?"success":"error","show-icon":"",closable:"",class:"banner",onClose:l[1]||(l[1]=t=>e.store.lastNotification=null)},{message:a(()=>[g(" 任务"+r(e.store.lastNotification.status==="completed"?"完成":"结束")+": "+r(e.store.lastNotification.description||e.store.lastNotification.id.slice(0,16)),1)]),description:a(()=>[e.store.lastNotification.error?(i(),c("span",j,r(e.store.lastNotification.error),1)):e.store.lastNotification.result?(i(),c("span",J,r(e.truncate(String(e.store.lastNotification.result),120)),1)):w("v-if",!0)]),_:1},8,["type"])):w("v-if",!0),n(C,{gutter:[16,16],class:"stats-row"},{default:a(()=>[n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"全部任务",value:e.store.tasks.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"运行中",value:e.store.running.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"等待中",value:e.store.pending.length},null,8,["value"])]),_:1})]),_:1}),n(v,{xs:12,sm:6},{default:a(()=>[n(m,{class:"stat-card",size:"small"},{default:a(()=>[n(d,{title:"已完成",value:e.store.completed.length},null,8,["value"])]),_:1})]),_:1})]),_:1}),e.store.running.length>0?(i(),T(m,{key:1,title:"运行中的任务",class:"panel-card",size:"small"},{default:a(()=>[(i(!0),c(h,null,B(e.store.running,t=>(i(),c("div",{key:t.id,class:"task-item running"},[_("div",K,[n(N,{color:e.store.getStatusColor(t.status)},{default:a(()=>[g(r(t.status.toUpperCase()),1)]),_:2},1032,["color"]),_("span",M,r(t.description),1),_("span",Q,r(t.id.slice(0,16)),1)]),_("div",W,[_("span",null,"类型: "+r(t.type||"-"),1),_("span",null,"已运行: "+r(e.store.formatDuration(Date.now()-t.startedAt)),1),n(y,{size:"small",danger:"",onClick:s=>e.store.stopTask(t.id)},{default:a(()=>[...l[4]||(l[4]=[g("停止",-1)])]),_:1},8,["onClick"])])]))),128))]),_:1})):w("v-if",!0),n(m,{class:"panel-card"},{default:a(()=>[n(A,{columns:e.columns,"data-source":e.store.tasks,pagination:{pageSize:15,size:"small"},loading:e.store.loading,"row-key":"id",size:"small"},{bodyCell:a(({column:t,record:s})=>[t.key==="status"?(i(),T(N,{key:0,color:e.store.getStatusColor(s.status)},{default:a(()=>[g(r(s.status),1)]),_:2},1032,["color"])):t.key==="description"?(i(),c("span",{key:1,title:s.command},r(s.description),9,Z)):t.key==="duration"?(i(),c(h,{key:2},[g(r(e.getDuration(s)),1)],64)):t.key==="createdAt"?(i(),c(h,{key:3},[g(r(e.formatTime(s.createdAt)),1)],64)):t.key==="result"?(i(),c(h,{key:4},[s.error?(i(),c("span",q,r(e.truncate(s.error,60)),1)):s.result?(i(),c("span",G,r(e.truncate(String(s.result),60)),1)):(i(),c("span",H,"-"))],64)):t.key==="action"?(i(),c(h,{key:5},[s.status==="running"?(i(),T(y,{key:0,size:"small",danger:"",onClick:S=>e.store.stopTask(s.id)},{default:a(()=>[...l[5]||(l[5]=[g(" 停止 ",-1)])]),_:1},8,["onClick"])):w("v-if",!0)],64)):w("v-if",!0)]),_:1},8,["data-source","loading"])]),_:1})])}const et=O(U,[["render",X],["__scopeId","data-v-da5ff6a2"],["__file","/tmp/cc-web-panel-94r5Fm/repo/packages/web-panel/src/views/Tasks.vue"]]);export{et as default};
@@ -1 +0,0 @@
1
- import{O as r}from"./index-DmrPbYXh.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
@@ -1 +0,0 @@
1
- import{A as o}from"./Row-xsUwB5Ay.js";import{U as t}from"./index-DmrPbYXh.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-Em-jKJ7U.js";import"./useFlexGapSupport-DZOaLVto.js";import"./styleChecker-DCoehh1S.js";import"./index-Dj6rUk3f.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};