chainlesschain 0.162.45 → 0.162.47

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 (160) hide show
  1. package/package.json +2 -2
  2. package/src/assets/web-panel/assets/{AIOps-D-W6s4eA.js → AIOps-BBjFOl4N.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-nPOyfwP_.js → ActionButton-B7A6lHz3.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DoX0H6wa.js → Analytics-DZgNxdvw.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BYNnmmUE.js → AppLayout-CFbPWVnh.js} +3 -3
  6. package/src/assets/web-panel/assets/{Audit-AjglOteL.js → Audit-Ao9RxevG.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-DT38xAKk.js → Backup-B1AGqahI.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-DT1pD4sT.js → BaseInput-M01bA2JM.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-Z77BT13i.js → Chat-CC0Gmd9k.js} +6 -6
  10. package/src/assets/web-panel/assets/ChatBubbleRenderer-DKe4yjqq.js +1 -0
  11. package/src/assets/web-panel/assets/{Checkbox-CVOMmTDm.js → Checkbox-CpEqAg5P.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-Bqy11vCf.js → Codegen-9c1H2P_L.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-C3A1d5Wt.js → Col-sH2Obo8q.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-D2q6UNaX.js → Community-DyzjH37r.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-C2701nAm.js → Compact-DsNatLOG.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-SJnaA5oN.js → Compliance-B3ws7qwL.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-BvTYuhJy.js → Cowork-odGfUMsv.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-sJ-9lLUV.js → Cron-bxO6NLDR.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-CStGE_K9.js → Crosschain-xHCPQpE9.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-JY0Kx-7a.js → DID-3l7HvzNC.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-BiZEZPRN.js → Dashboard-BNzT5YBj.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-DK2BszlZ.js → Dropdown-DZynMYpG.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-DtjOYS0Q.js → EmailListRenderer-6HZ2XA9g.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D2EI2B5E.js → FamilyGuardDashboard-DqzqNzRP.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-CebAtHrY.js → Federation-CI7lf1MF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-Bd8WNQLm.js → FormItemContext-D2m3YZ-k.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-tH3zcpN9.js → GenericCardRenderer-Bwcc-9EB.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-DARoXdm7.js → Git-C7qN3bA1.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-gcKIyn7g.js → Governance-JfuugS1c.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-Rh4pllPC.js → Inference-BNsHm2IH.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-Cvh73WwA.js → KnowledgeGraph-CTH_FiL1.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-BBZSagwy.js → Logs-CxcfBcmS.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-e5C7xHES.js → Marketplace-B9PU3qlx.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-BzfXvajQ.js → McpTools-BlvQpnvj.js} +5 -5
  35. package/src/assets/web-panel/assets/{Memory-C3ZgSBrL.js → Memory-Diiig9gp.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-BYVobYJJ.js → MobileBridge-CGfUn4xi.js} +2 -2
  37. package/src/assets/web-panel/assets/{MobileProjects-Bl8xCXs4.js → MobileProjects-CFvH6A9E.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-BxNytLEb.js → Mtc-CT_1x1Gr.js} +4 -4
  39. package/src/assets/web-panel/assets/{MtcAudit-BUadScwJ.js → MtcAudit-DPAjU1Qn.js} +4 -4
  40. package/src/assets/web-panel/assets/{Multisig-BWZmAn6M.js → Multisig-nks2HW0C.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-B4eau0Yo.js → NLProgramming-BWd74a91.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-eHe1Jd1n.js → Notes-B342yG3u.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-DFMSI_xu.js → NotificationSettings-C9kjn20B.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-Ctejeurt.js → OrderTableRenderer-DKQ3FPUN.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-M_NYVPks.js → Organization-Ch-qkiyP.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-Bi-TzxkX.js → Overflow-DeV865TY.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-vtorIyuM.js → P2P-9pzyAAE1.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-D9I3WUUZ.js → PdhVaultBrowser-oGgQiWpR.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-YFbIKLZw.js → Permissions-MPDfvUva.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-JM8yN0w0.js → PersonalDataHub-Es8GFY4_.js} +3 -3
  51. package/src/assets/web-panel/assets/{Pipeline-Cyvwlqpr.js → Pipeline-R10lJHtN.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-CIKHwg7m.js → Privacy-8YMg8xrV.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-Bj6-CmbC.js → ProjectInit-B-L3DMBv.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-CBnTXhIt.js → ProjectSettings-pR4l7GCe.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-B3CwPTNd.js → Projects-5vaXw-7d.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-dtUZaXuY.js → Providers-C_E-G6Bh.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-BWzt81Dm.js → QuickAsk-CM-FSYbK.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-CToDb_n9.js → Recommend-DcwFptAP.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-B6MCFsXH.js → Reputation-DJKj97w-.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-CipchQUs.js → Row-BfI2mGUm.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-CR3mpmuE.js → RssFeed-D6tzthT0.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-DRvRD7_k.js → Search-CkxIxA5y.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-Bv1bEvfO.js → Security-BeTfFgoX.js} +3 -3
  64. package/src/assets/web-panel/assets/{Services-BLAljjtu.js → Services-BahX89X1.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-BRFNIS9s.js → Skeleton-55na3k97.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-B6dEwkkO.js → Skills-DZ-dxsiR.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-A97O6hQJ.js → Sla-BUTClrI0.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-DNBeqO5l.js → SpeechSettings-C0c2AmSU.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-C61PTeaN.js → SyncSettings-Vr5zzdPz.js} +2 -2
  70. package/src/assets/web-panel/assets/{Tasks-C8q-8JXF.js → Tasks-BrouZA03.js} +1 -1
  71. package/src/assets/web-panel/assets/{Templates-R-4ZBAPY.js → Templates-DnaU_7nb.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-dRpKvdmN.js → Tenant-1dw4SFBA.js} +1 -1
  73. package/src/assets/web-panel/assets/{Terminal-egMhD-wn.js → Terminal-Pe1vBvOm.js} +2 -2
  74. package/src/assets/web-panel/assets/{TimelineRenderer-BbXUD3AZ.js → TimelineRenderer-dDxMvAvM.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-CuYIAO1f.js → Tokens-CPJMLjkE.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-bt_5ffBh.js → Trigger-B1IWp6HK.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-rk4LCtlg.js → Trust-iswzFvfA.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-Bgf8zhuS.js → UkeySign-CuMmDUvU.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-B_D_kcq5.js → VideoEditing-BguHSBQ5.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-BuhroOcU.js → Wallet-CW4PFXSw.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-DNVp_EWD.js → WebAuthn-YOO0lqjJ.js} +4 -4
  82. package/src/assets/web-panel/assets/{WorkflowEditor-C94Nr2Yq.js → WorkflowEditor-A_z3yLuG.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-CqvcO82L.js → chat-BSHj9uiJ.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-CiHv7zLX.js → colors-D7gA-kvN.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BbL_7DRy.js → compact-item-ChDt0wUv.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-BcnUkPGe.js → createContext-5UAhDsNU.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-NW6VMT5L.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-bKZM79uJ.js → hasIn-7ysmGHSf.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-C0Dew6UJ.js → index--UCy6rsJ.js} +1 -1
  90. package/src/assets/web-panel/assets/index-A6oY6RQQ.js +1 -0
  91. package/src/assets/web-panel/assets/{index-sdSZZzwh.js → index-B6OX-6N1.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-UrCGcZXp.js → index-BGlolJwU.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-kHUuRAFp.js → index-BLoQ2FkI.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-D5X8cqw-.js → index-BTzZlYgQ.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Zxnsweba.js → index-B_xBUmAE.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Dpb_Zh3w.js → index-BcPEgfGF.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-ABAWaz7Y.js → index-BhsGGFa4.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Drdlb5iB.js → index-BoCy4bxa.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CWPLkrPr.js → index-BzPxVTI2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C1b8TGYq.js → index-C4nXq9eB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Bfcq_Svy.js → index-C62SpQws.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Bh9TSxy7.js → index-C93TfkpQ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DAayTu3W.js → index-CGVsJplV.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-ByEejvcB.js → index-CHdEHlNY.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CPJ4NWCv.js → index-COwKdUAS.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-2nrwvHPn.js → index-Cl10KB1R.js} +1 -1
  107. package/src/assets/web-panel/assets/index-Cn2g4vqt.js +1 -0
  108. package/src/assets/web-panel/assets/{index-vzVBm4mg.js → index-CylU_ot3.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DNBdA_cQ.js → index-D-pJNNc5.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DYH3St42.js → index-D9R6sJiP.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-B76qMGe0.js → index-DSRnnGez.js} +3 -3
  112. package/src/assets/web-panel/assets/{index-Bd0u4iTg.js → index-Db4hf2WV.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DPHskdVZ.js → index-DcKVERvm.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BlIYy94Y.js → index-DfjMbFZA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-J8Xba8Zt.js → index-Dj3IHF24.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B1StZUmz.js → index-Dq4fd0cB.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Cc48TfA8.js → index-DslmMjVo.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Kl_dtIkL.js → index-DttrXREN.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-D-jqR16_.js → index-HUiKkQOf.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BySbK7vA.js → index-NtFFgW-x.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-JteeOvFE.js → index-QPBJl4wk.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-AJLQ9KfF.js → index-WM_jYoK8.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Csgtimo8.js → index-ZOmjAajS.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CQonLmOf.js → index-_8xZf-zU.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Kt6y6Hh5.js → index-pk9WOpeN.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-SeP48n4C.js → index-s_MPIulF.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BSzQlPjx.js → index-trVj-RG1.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-Cg2ZQCW2.js → initDefaultProps-BcWdcWH2.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-CVup4XZf.js → motion-D-GC86LC.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-0we4XeEJ.js → move-7N01T4vz.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-DNvkWjsk.js → omit-B8_G8lAi.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-DNGWkffo.js → pickAttrs-BeEwgLq8.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-DdMP7Lk2.js → placementArrow-CiQwkkN_.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-CgCiGZ6t.js → responsiveObserve-CtfIP2YM.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-CQxOWXtr.js → slide-DnA-Z3fK.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-BVYop9K6.js → statusUtils-Ckaf7hg9.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-BTkUPq_y.js → styleChecker-CE7d6-LQ.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-CKncli3p.js → useFlexGapSupport-BBC2EqTi.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-B7k6cPxd.js → useFs-BWncdesy.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-CiVRczRO.js → usePersonalDataHub-BVJgKdiT.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-CPueAEhr.js → vnode-CdZoGwk8.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-BhzuJF_P.js → zoom-8BsyiHWV.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +44 -30
  145. package/src/commands/hub.js +87 -0
  146. package/src/harness/mcp-client.js +86 -1
  147. package/src/lib/auto-checkpoint-default.js +49 -0
  148. package/src/lib/personal-data-hub-wiring.js +44 -2
  149. package/src/lib/repl-completer.js +6 -3
  150. package/src/lib/sensitive-file-guard.js +58 -0
  151. package/src/lib/skill-loader.js +43 -7
  152. package/src/lib/sub-agent-context.js +3 -0
  153. package/src/repl/agent-repl.js +27 -1
  154. package/src/runtime/agent-core.js +55 -0
  155. package/src/runtime/headless-stream.js +36 -4
  156. package/src/runtime/mcp-config.js +19 -1
  157. package/src/assets/web-panel/assets/ChatBubbleRenderer-C1MKMzjB.js +0 -1
  158. package/src/assets/web-panel/assets/devWarning-BSbU0obw.js +0 -1
  159. package/src/assets/web-panel/assets/index-DHgbmZ-Y.js +0 -1
  160. package/src/assets/web-panel/assets/index-pr3q7Jlo.js +0 -1
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Sensitive-file write guard — Claude-Code 2.1.160 parity ("prompts before
3
+ * writing to shell startup files").
4
+ *
5
+ * Writing a shell startup file, PowerShell profile, or git hook plants code
6
+ * that EXECUTES on the user's next shell/commit — a step up from a normal
7
+ * edit, so even pre-authorized edit flows must confirm first. The check is
8
+ * name-based (basename / well-known relative fragments), deliberately
9
+ * conservative: build configs like Makefile/package.json are everyday edits
10
+ * and are NOT flagged (false-positive fatigue would teach users to blind-OK).
11
+ */
12
+
13
+ const SHELL_STARTUP_NAMES = new Set([
14
+ ".bashrc",
15
+ ".bash_profile",
16
+ ".bash_login",
17
+ ".bash_logout",
18
+ ".profile",
19
+ ".zshrc",
20
+ ".zshenv",
21
+ ".zprofile",
22
+ ".zlogin",
23
+ ".zlogout",
24
+ ".cshrc",
25
+ ".tcshrc",
26
+ ".kshrc",
27
+ ]);
28
+
29
+ const POWERSHELL_PROFILE_RE = /(^|[\\/])(microsoft\.powershell_profile\.ps1|profile\.ps1)$/i;
30
+ const FISH_CONFIG_RE = /[\\/]fish[\\/]config\.fish$/i;
31
+ const GIT_HOOK_RE = /[\\/]\.git[\\/]hooks[\\/][^\\/]+$/i;
32
+ const HUSKY_HOOK_RE = /[\\/]\.husky[\\/](?!_)[^\\/]+$/i;
33
+
34
+ /**
35
+ * @param {string} targetPath path as the tool received it (rel or abs)
36
+ * @returns {string|null} human reason when sensitive, null otherwise
37
+ */
38
+ export function sensitiveFileReason(targetPath) {
39
+ const p = String(targetPath || "");
40
+ if (!p) return null;
41
+ const base = p.replace(/\\/g, "/").split("/").pop() || "";
42
+ if (SHELL_STARTUP_NAMES.has(base)) {
43
+ return `shell startup file (${base}) — runs on the user's next shell`;
44
+ }
45
+ if (POWERSHELL_PROFILE_RE.test(p)) {
46
+ return "PowerShell profile — runs on the user's next PowerShell session";
47
+ }
48
+ if (FISH_CONFIG_RE.test(p)) {
49
+ return "fish shell config — runs on the user's next shell";
50
+ }
51
+ if (GIT_HOOK_RE.test(p)) {
52
+ return "git hook — executes on the user's next git operation";
53
+ }
54
+ if (HUSKY_HOOK_RE.test(p)) {
55
+ return "husky hook — executes on the user's next git operation";
56
+ }
57
+ return null;
58
+ }
@@ -1,24 +1,40 @@
1
1
  /**
2
2
  * Multi-layer skill loader for CLI
3
3
  *
4
- * 4-layer priority system (highest wins on name collision):
5
- * 0 (lowest) bundled — desktop-app-vue/.../skills/builtin/
6
- * 1 marketplace — <userData>/marketplace/skills/
7
- * 2 managed — <userData>/skills/
8
- * 3 (highest) workspace <projectRoot>/.chainlesschain/skills/
4
+ * 6-layer priority system (highest wins on name collision):
5
+ * 0 (lowest) bundled — desktop-app-vue/.../skills/builtin/
6
+ * 1 marketplace — <userData>/marketplace/skills/
7
+ * 2 managed — <userData>/skills/
8
+ * 3 claude-user ~/.claude/skills/ (Claude-Code 可移植)
9
+ * 4 claude-project — <projectRoot>/.claude/skills/ (Claude-Code 可移植)
10
+ * 5 (highest) workspace — <projectRoot>/.chainlesschain/skills/
11
+ *
12
+ * The two `claude-*` layers are Claude-Code portability (its 2.1.157
13
+ * ".claude/skills auto-load" behavior): a repo carrying Claude-Code skills
14
+ * works in cc unchanged — same SKILL.md format — while native
15
+ * `.chainlesschain/skills` still wins on name collisions.
9
16
  */
10
17
 
11
18
  import fs from "fs";
19
+ import os from "os";
12
20
  import path from "path";
13
21
  import { fileURLToPath } from "url";
14
22
  import { getElectronUserDataDir } from "./paths.js";
15
23
  import { findProjectRoot } from "./project-detector.js";
24
+ import { findProjectRoot as findGitRoot } from "./project-instructions.js";
16
25
  import { parseSkillMcpServers } from "./skill-mcp.js";
17
26
 
18
27
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
28
 
20
29
  /** Layer names in priority order (lowest → highest) */
21
- export const LAYER_NAMES = ["bundled", "marketplace", "managed", "workspace"];
30
+ export const LAYER_NAMES = [
31
+ "bundled",
32
+ "marketplace",
33
+ "managed",
34
+ "claude-user",
35
+ "claude-project",
36
+ "workspace",
37
+ ];
22
38
 
23
39
  /**
24
40
  * Simple YAML frontmatter parser (no dependencies)
@@ -230,7 +246,27 @@ export class CLISkillLoader {
230
246
  exists: fs.existsSync(managedPath),
231
247
  });
232
248
 
233
- // Layer 3: workspace — <projectRoot>/.chainlesschain/skills/
249
+ // Layers 3+4: Claude-Code portability ~/.claude/skills + <root>/.claude/skills
250
+ const home = os.homedir() || "";
251
+ const claudeUserPath = home ? path.join(home, ".claude", "skills") : null;
252
+ layers.push({
253
+ layer: "claude-user",
254
+ path: claudeUserPath,
255
+ exists: Boolean(claudeUserPath && fs.existsSync(claudeUserPath)),
256
+ });
257
+ // Project base: .chainlesschain marker first, git root as fallback so a
258
+ // pure Claude-Code repo (no .chainlesschain/) still gets its skills.
259
+ const claudeBase = findProjectRoot() || findGitRoot(process.cwd());
260
+ const claudeProjectPath = claudeBase
261
+ ? path.join(claudeBase, ".claude", "skills")
262
+ : null;
263
+ layers.push({
264
+ layer: "claude-project",
265
+ path: claudeProjectPath,
266
+ exists: Boolean(claudeProjectPath && fs.existsSync(claudeProjectPath)),
267
+ });
268
+
269
+ // Layer 5 (highest): workspace — <projectRoot>/.chainlesschain/skills/
234
270
  const projectRoot = findProjectRoot();
235
271
  if (projectRoot) {
236
272
  const workspacePath = path.join(projectRoot, ".chainlesschain", "skills");
@@ -73,6 +73,7 @@ export class SubAgentContext {
73
73
  this.tokenBudget = options.tokenBudget || null;
74
74
  this.inheritedContext = options.inheritedContext || null;
75
75
  this.allowedTools = options.allowedTools || null; // null = all
76
+ this.depth = options.depth || 1; // nesting level (parent main loop = 0)
76
77
  this.cwd = options.cwd || process.cwd();
77
78
  this.status = "active";
78
79
  this.result = null;
@@ -249,6 +250,8 @@ export class SubAgentContext {
249
250
  ...this._llmOptions,
250
251
  contextEngine: this.contextEngine,
251
252
  cwd: this.cwd,
253
+ // Nesting level: lets a nested spawn_sub_agent see — and cap — its depth.
254
+ subAgentDepth: this.depth,
252
255
  ...loopOptions,
253
256
  };
254
257
  if (this.iterationBudget) {
@@ -20,6 +20,7 @@
20
20
  import readline from "readline";
21
21
  import chalk from "chalk";
22
22
  import fs from "fs";
23
+ import os from "os";
23
24
  import path from "path";
24
25
  import { logger } from "../lib/logger.js";
25
26
  import { getPlanModeManager, PlanState } from "../lib/plan-mode.js";
@@ -748,10 +749,12 @@ export async function startAgentRepl(options = {}) {
748
749
  // (when the IDE bridge is connected) the editor's open tabs ranked first.
749
750
  const { makeAtCompleter } = await import("../lib/repl-completer.js");
750
751
  const atCompleter = makeAtCompleter({
751
- cwd: process.cwd(),
752
+ // cwd left unset on purpose: the completer resolves process.cwd() lazily
753
+ // so it follows `/cd` mid-session.
752
754
  // Keep in sync with the rl.on("line") handlers + /help below.
753
755
  slashCommands: [
754
756
  "/auto",
757
+ "/cd",
755
758
  "/clear",
756
759
  "/compact",
757
760
  "/context",
@@ -1012,6 +1015,9 @@ export async function startAgentRepl(options = {}) {
1012
1015
  logger.log(
1013
1016
  ` ${chalk.cyan("/rewind")} Rewind conversation to an earlier turn (double-Esc lists)`,
1014
1017
  );
1018
+ logger.log(
1019
+ ` ${chalk.cyan("/cd <dir>")} Change working directory mid-session (completion/memory follow)`,
1020
+ );
1015
1021
  logger.log(
1016
1022
  ` ${chalk.cyan("/compact")} Smart compact (importance-based)`,
1017
1023
  );
@@ -1250,6 +1256,26 @@ export async function startAgentRepl(options = {}) {
1250
1256
  return;
1251
1257
  }
1252
1258
 
1259
+ // `/cd` (Claude-Code 2.1.163 parity): relocate the session's working
1260
+ // directory mid-conversation. Everything that reads process.cwd() per
1261
+ // call follows automatically (agent cwd, @-completion, project memory).
1262
+ if (trimmed === "/cd" || trimmed.startsWith("/cd ")) {
1263
+ const target = trimmed.slice(3).trim();
1264
+ if (!target) {
1265
+ logger.info(`cwd: ${process.cwd()}`);
1266
+ } else {
1267
+ try {
1268
+ const expanded = target.replace(/^~(?=$|[\\/])/, os.homedir());
1269
+ process.chdir(path.resolve(process.cwd(), expanded));
1270
+ logger.log(chalk.green(`cwd → ${process.cwd()}`));
1271
+ } catch (err) {
1272
+ logger.error(`/cd failed: ${err.message}`);
1273
+ }
1274
+ }
1275
+ prompt();
1276
+ return;
1277
+ }
1278
+
1253
1279
  if (trimmed === "/rewind" || trimmed.startsWith("/rewind ")) {
1254
1280
  try {
1255
1281
  const { listUserTurns, rewindToTurn, renderTurnList } = await import(
@@ -901,6 +901,40 @@ export async function executeTool(name, args, context = {}) {
901
901
  ruleAllowed = true;
902
902
  }
903
903
 
904
+ // Sensitive-file write guard (Claude-Code 2.1.160 parity): shell startup
905
+ // files / PowerShell profiles / git+husky hooks execute code on the user's
906
+ // next shell or commit — even otherwise-permitted edit flows confirm first.
907
+ // An explicit settings `allow` rule is the only bypass (exact user
908
+ // pre-authorization); headless without a confirmer fails closed.
909
+ if (
910
+ (name === "write_file" || name === "edit_file") &&
911
+ settingsVerdict.decision !== "allow" &&
912
+ args?.path
913
+ ) {
914
+ const { sensitiveFileReason } = await import(
915
+ "../lib/sensitive-file-guard.js"
916
+ );
917
+ const sensReason = sensitiveFileReason(args.path);
918
+ if (sensReason) {
919
+ const confirm = context.permissionConfirm || context.shellConfirm || null;
920
+ const ok =
921
+ typeof confirm === "function"
922
+ ? await confirm({
923
+ tool: name,
924
+ args,
925
+ rule: null,
926
+ reason: `sensitive file: ${sensReason}`,
927
+ })
928
+ : false;
929
+ if (!ok) {
930
+ return {
931
+ error: `[Sensitive File] Writing "${args.path}" requires confirmation (${sensReason}) — denied. Add a settings allow rule to pre-authorize.`,
932
+ policy: { decision: "ask", via: "sensitive-file" },
933
+ };
934
+ }
935
+ }
936
+ }
937
+
904
938
  // Plan mode: check if tool is allowed (a settings `allow` rule pre-authorizes)
905
939
  if (
906
940
  planManager.isActive() &&
@@ -980,6 +1014,7 @@ export async function executeTool(name, args, context = {}) {
980
1014
  shellConfirm: context.shellConfirm || null,
981
1015
  additionalDirectories: context.additionalDirectories || null,
982
1016
  ruleAllowed,
1017
+ subAgentDepth: context.subAgentDepth || 0,
983
1018
  });
984
1019
  } catch (err) {
985
1020
  if (hookDb) {
@@ -1150,6 +1185,7 @@ async function executeToolInner(
1150
1185
  shellConfirm,
1151
1186
  additionalDirectories,
1152
1187
  ruleAllowed = false,
1188
+ subAgentDepth = 0,
1153
1189
  },
1154
1190
  ) {
1155
1191
  const localToolDescriptor =
@@ -1528,6 +1564,7 @@ async function executeToolInner(
1528
1564
  interaction,
1529
1565
  sessionId,
1530
1566
  llmOptions,
1567
+ subAgentDepth,
1531
1568
  }),
1532
1569
  );
1533
1570
  }
@@ -2186,6 +2223,13 @@ async function _executeRunCode(args, cwd) {
2186
2223
 
2187
2224
  // ─── spawn_sub_agent implementation ──────────────────────────────────────
2188
2225
 
2226
+ /**
2227
+ * Max sub-agent nesting depth (Claude-Code 2.1.172 parity: sub-agents may
2228
+ * spawn their own sub-agents, capped at 5 levels so a runaway model cannot
2229
+ * recurse forever). Main loop = depth 0, its children = 1, …
2230
+ */
2231
+ export const MAX_SUB_AGENT_DEPTH = 5;
2232
+
2189
2233
  /**
2190
2234
  * Execute a spawn_sub_agent tool call.
2191
2235
  * Creates an isolated SubAgentContext, runs it, and returns only the summary.
@@ -2195,6 +2239,13 @@ async function _executeRunCode(args, cwd) {
2195
2239
  * @returns {Promise<object>}
2196
2240
  */
2197
2241
  async function _executeSpawnSubAgent(args, ctx) {
2242
+ // Nesting cap: refuse before any context/registry work.
2243
+ const currentDepth = ctx.subAgentDepth || 0;
2244
+ if (currentDepth >= MAX_SUB_AGENT_DEPTH) {
2245
+ return {
2246
+ error: `spawn_sub_agent: max nesting depth (${MAX_SUB_AGENT_DEPTH}) reached — complete the task directly instead of delegating further.`,
2247
+ };
2248
+ }
2198
2249
  let {
2199
2250
  role,
2200
2251
  task,
@@ -2296,6 +2347,7 @@ async function _executeSpawnSubAgent(args, ctx) {
2296
2347
  cwd: ctx.cwd,
2297
2348
  profile: profile || null,
2298
2349
  llmOptions: subLlmOptions,
2350
+ depth: currentDepth + 1, // nested spawns see their own level
2299
2351
  });
2300
2352
 
2301
2353
  const emit = (type, payload) => {
@@ -3332,6 +3384,9 @@ export async function* agentLoop(messages, options) {
3332
3384
  autoCheckpoint: options.autoCheckpoint || false,
3333
3385
  checkpointSession:
3334
3386
  options.checkpointSession || options.sessionId || "agent",
3387
+ // Sub-agent nesting level (0 = main loop); spawn_sub_agent caps at
3388
+ // MAX_SUB_AGENT_DEPTH using this.
3389
+ subAgentDepth: options.subAgentDepth || 0,
3335
3390
  };
3336
3391
 
3337
3392
  throwIfAborted(signal);
@@ -102,8 +102,19 @@ export function parseInputEvent(line) {
102
102
  .map((b) => (typeof b === "string" ? b : b?.text || ""))
103
103
  .join("");
104
104
  }
105
- if (typeof content !== "string" || !content.trim()) return null;
106
- return { text: content };
105
+ // Vision input (chat-panel image paste): {"type":"user","text":…,
106
+ // "images":["/abs/file.png", …]} — file paths, resolved at turn build via
107
+ // the same image-input pipeline as `cc agent --image`.
108
+ const rawImages = obj && typeof obj === "object" ? obj.images || msg.images : null;
109
+ const images = Array.isArray(rawImages)
110
+ ? rawImages.filter((p) => typeof p === "string" && p.trim()).slice(0, 8)
111
+ : [];
112
+ if (typeof content !== "string" || !content.trim()) {
113
+ // An image-only turn is valid — give the model something to act on.
114
+ if (images.length) return { text: "Please look at the attached image(s).", images };
115
+ return null;
116
+ }
117
+ return images.length ? { text: content, images } : { text: content };
107
118
  }
108
119
 
109
120
  /**
@@ -727,10 +738,31 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
727
738
  // optional polish — never fail the turn over it
728
739
  }
729
740
 
730
- messages.push({ role: "user", content: userContent });
741
+ // Attach pasted/added images (panel parity with `--image`): file paths →
742
+ // data URLs → OpenAI-style multimodal content. buildUserContent returns
743
+ // the plain string when there are no images, so text turns are unchanged.
744
+ let turnContent = userContent;
745
+ if (parsed.images && parsed.images.length) {
746
+ try {
747
+ const { resolveImages, buildUserContent } =
748
+ await import("../lib/image-input.js");
749
+ turnContent = buildUserContent(userContent, resolveImages(parsed.images));
750
+ } catch (err) {
751
+ emit({
752
+ type: "result",
753
+ subtype: "error",
754
+ is_error: true,
755
+ result: `image attach failed: ${err.message}`,
756
+ session_id: sessionId,
757
+ });
758
+ continue; // bad attachment kills the turn, not the session
759
+ }
760
+ }
761
+
762
+ messages.push({ role: "user", content: turnContent });
731
763
  if (persist) {
732
764
  try {
733
- store.appendUserMessage(sessionId, userContent);
765
+ store.appendUserMessage(sessionId, turnContent);
734
766
  } catch {
735
767
  /* best-effort */
736
768
  }
@@ -347,7 +347,25 @@ export async function loadIdeMcp(opts = {}, deps = {}) {
347
347
  }
348
348
  const cfg = toCfg(lock);
349
349
  if (!cfg) return deps.into || null;
350
- return setupMcpFromConfig({ ide: cfg }, deps);
350
+ const out = await setupMcpFromConfig({ ide: cfg }, deps);
351
+ // Hot reconnect: a window reload / extension update restarts the editor's
352
+ // MCP server on a NEW port with a NEW token. Register a reconnector so a
353
+ // failed mcp__ide__* call re-scans the lockfiles mid-session and retries,
354
+ // instead of the IDE tools (and selection/diagnostics injection) silently
355
+ // dying for the rest of the run. Note the stale CHAINLESSCHAIN_IDE_PORT in
356
+ // our env no longer matches any live lock, so discovery falls through to
357
+ // the workspace scan — exactly the path that finds the restarted instance.
358
+ if (out?.mcpClient?.setReconnector) {
359
+ out.mcpClient.setReconnector("ide", () => {
360
+ const fresh = discover({
361
+ cwd: opts.cwd,
362
+ env: opts.env,
363
+ force: opts.force === true,
364
+ });
365
+ return fresh ? toCfg(fresh) : null;
366
+ });
367
+ }
368
+ return out;
351
369
  }
352
370
 
353
371
  /**
@@ -1 +0,0 @@
1
- import{I as v,P as u,J as S,U as n,R as a,S as y,K as C,Q as x,V as w,_ as B,b as s}from"./vendor-BvqAck49.js";import{_ as k}from"./index-B76qMGe0.js";import"./icons-DP3uiYxy.js";const M={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=s(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=s(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=s(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=s(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=s(()=>{if(!t.event.occurredAt)return"";try{const e=new Date(t.event.occurredAt),p=e.getFullYear(),f=String(e.getMonth()+1).padStart(2,"0"),b=String(e.getDate()).padStart(2,"0"),g=String(e.getHours()).padStart(2,"0"),h=String(e.getMinutes()).padStart(2,"0");return`${p}-${f}-${b} ${g}:${h}`}catch{return""}}),_={props:t,messageText:r,actorLabel:i,isMine:l,adapterColor:o,formattedTime:m,computed:s};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},N={class:"bubble"},T={class:"meta"},R={class:"actor"},V={class:"time"},j={class:"body"};function q(c,d,t,r,i,l){const o=v("a-tag");return u(),S("div",{class:B(["chat-row",{mine:r.isMine}])},[n("div",N,[n("div",T,[n("span",R,a(r.actorLabel),1),n("span",V,a(r.formattedTime),1)]),n("div",j,a(r.messageText),1),t.event.source.adapter?(u(),y(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(a(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const A=k(M,[["render",q],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-MQBjbf/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{A as default};
@@ -1 +0,0 @@
1
- import{O as r}from"./index-B76qMGe0.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-CipchQUs.js";import{U as t}from"./index-B76qMGe0.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-CgCiGZ6t.js";import"./useFlexGapSupport-CKncli3p.js";import"./styleChecker-BTkUPq_y.js";import"./index-C1b8TGYq.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-C3A1d5Wt.js";import{U as t}from"./index-B76qMGe0.js";import"./vendor-BvqAck49.js";import"./index-C1b8TGYq.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};