chainlesschain 0.162.65 → 0.162.66

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 (158) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-DjJf_QIn.js → AIOps-BeJlvHR1.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BT45g-KL.js → ActionButton-B93fwcal.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-CRaTHble.js → Analytics-B-Lc0FRK.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-72r5TM1u.js → AppLayout-nv2C8TdH.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-BNlvJ3Yc.js → Audit-B4pwb1Oe.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-Kuj0-vBg.js → Backup-B4HFWkJA.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-_pKOPRf4.js → BaseInput-BQk1ONWO.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-CMNhGWK5.js → Chat-B2IobFfI.js} +5 -5
  10. package/src/assets/web-panel/assets/ChatBubbleRenderer-jJL-hGlG.js +1 -0
  11. package/src/assets/web-panel/assets/{Checkbox-B5R2TdAI.js → Checkbox-BHCU5kit.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-69RAQ0Gi.js → Codegen-Bqgq9-0q.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-DlbssQEY.js → Col-BqDf398Z.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-DU3SAZIS.js → Community-Cd58ltip.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-BqdNnAZv.js → Compact-CWa3CY1X.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-D9a9-ihS.js → Compliance-BNJWsGi0.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-DWBtOBbU.js → Cowork-ChOCC2KD.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-ClSuf90k.js → Cron-BpWtgfDE.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-BFjRKvpa.js → Crosschain-Csy7U94a.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-BwBGRlMm.js → DID-CIh7lr9T.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-CHrXGmQ3.js → Dashboard-DYJUc9Jy.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-C24B5sk2.js → Dropdown-GnUptPAU.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-DaXTSK5p.js → EmailListRenderer-sE9mvxjT.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-65d89G5t.js → FamilyGuardDashboard-Dg7-GHSu.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-CkWdqmVs.js → Federation-BiH_O7jy.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-BV4W2nrT.js → FormItemContext-C1AZ_qE-.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-D60KJ0_b.js → GenericCardRenderer-WpsC5meD.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-BIKuoGvW.js → Git-L4XGb5Qj.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-CKnJpq5X.js → Governance-CJ9Gn_A9.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-C7G3YGeg.js → Inference-Dlc9Ey87.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-D7fCUd4B.js → KnowledgeGraph-CfndHiBW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-C0unjcbC.js → Logs-CSOLZERs.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-BzLlnyI8.js → Marketplace-Cjiz9wPY.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-DSKFRB1-.js → McpTools-C8UNhnTj.js} +4 -4
  35. package/src/assets/web-panel/assets/{Memory-C_QrLAnt.js → Memory-BhOoGXRL.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-DBeaFERD.js → MobileBridge-rKKcGEvg.js} +2 -2
  37. package/src/assets/web-panel/assets/{MobileProjects-C2L_RttC.js → MobileProjects-KvGFVl79.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-B3Tdh6-l.js → Mtc-jyA3mXYt.js} +5 -5
  39. package/src/assets/web-panel/assets/{MtcAudit-B3O_EUvt.js → MtcAudit-BYi6sulR.js} +4 -4
  40. package/src/assets/web-panel/assets/{Multisig--60rVmDj.js → Multisig-CWZGD6_3.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-D60vxATf.js → NLProgramming-bOIPDOh5.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-D2gj2uFI.js → Notes-_I6Hs_bJ.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-D0DWHNlF.js → NotificationSettings-Bj9Bcy2A.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-CNi1B7fH.js → OrderTableRenderer-C5zZeOhJ.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-BRcdFgAd.js → Organization-B-SfOynT.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-C3_Oap7v.js → Overflow-CG7JBYts.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-DEbZ93QW.js → P2P-vpebJYvr.js} +2 -2
  48. package/src/assets/web-panel/assets/PdhVaultBrowser-CPeKixo2.js +7 -0
  49. package/src/assets/web-panel/assets/{Permissions-CPj3C9o2.js → Permissions-CpflO2Ac.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-BZGupZzh.js → PersonalDataHub-D6CjgWDH.js} +2 -2
  51. package/src/assets/web-panel/assets/{Pipeline-SMLW1BG7.js → Pipeline-CgC59gHt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-o24SJ2no.js → Privacy-CoZn6LrI.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-DxjAXD8f.js → ProjectInit-BmNYdFPv.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-DipynlqL.js → ProjectSettings-C13HHOUG.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-CZ9egQ8r.js → Projects-BSHYaYKU.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-x3p-wcab.js → Providers-Dh6ys5NR.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-CZ7beKFC.js → QuickAsk-Cljz9ZIS.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-VJCd2i9_.js → Recommend-CEAVAYGZ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-pl12NmBF.js → Reputation-C7AxH6cu.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-NkSeo4Tb.js → Row-D5Jgzbof.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-B17vp67R.js → RssFeed-V6vBnNBE.js} +2 -2
  62. package/src/assets/web-panel/assets/{Search-Dij0_m6W.js → Search-dfDC6aHa.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-n9CSBX-9.js → Security-BOSRXul6.js} +3 -3
  64. package/src/assets/web-panel/assets/{Services-bZOzqHdK.js → Services-dsNT3Tra.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-B23D5vJ-.js → Skeleton-_rXFZqCe.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-IXh-0mk0.js → Skills-WWvbl-N6.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-QEofxmdK.js → Sla-BZT_pwjV.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-u68R59ft.js → SpeechSettings-BSVqkQ0F.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-B3tc986U.js → SyncSettings-TLHuQW_s.js} +2 -2
  70. package/src/assets/web-panel/assets/{Tasks-Cp2QxGrr.js → Tasks-8-jiv3Dt.js} +1 -1
  71. package/src/assets/web-panel/assets/{Templates-CMWiWxiH.js → Templates-D7qs_H3G.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-M8aPJ3C7.js → Tenant-B4hRLxlc.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-lrlEETgH.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-DF6aIS-d.js → TimelineRenderer-Do8UQaNj.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-BcfMMw_e.js → Tokens-wyuwl9gS.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-jIbNmxvm.js → Trigger-Ck4j8Emr.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-ChLil6CZ.js → Trust-Z07lGZvX.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-B1WzYAon.js → UkeySign-5rI48ojV.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-Dwm0LyCc.js → VideoEditing-Dm8PV-Ss.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-DVyxsX-O.js → Wallet-BwWYuV0j.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-WYPNy2Q7.js → WebAuthn-CavU3f2i.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-Br3dCsmv.js → WorkflowEditor-jj1aB37x.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-fAKHY2HK.js → chat-BpRqPqbA.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-BXqS-Bwi.js → colors-BBJU99fO.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BgCQhtW3.js → compact-item-t2Elz5Kg.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-weZBwqHy.js → createContext-B_D6Nida.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-CmJstpP_.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-Dx68UNFL.js → hasIn-D5k1KNpe.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-BjsidvP5.js → index-1lcpLp-e.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-DXuz90bX.js → index-2KvtrQkP.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-Co5cQnlv.js → index-33FQbw3H.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-CfqzwaAV.js → index-3TymUGUQ.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-DNF3aCJF.js → index-6iwQSswx.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-LxcdLeFj.js → index-B2cxsdFe.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B8zNZ_oH.js → index-BCpJT0on.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DgUC575c.js → index-BH_HjIO6.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BqcH_mKR.js → index-BVEb-kUY.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-ohVNy7ua.js → index-BaS1rfcr.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-ChdeuOni.js → index-BfKFGtsC.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BSQEQCft.js → index-Bo72gKe8.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-HIN85jl7.js → index-C-271Q6Z.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-5e-OAZOb.js → index-C3alXfss.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-Bwv_UrNF.js → index-CB1AFQiL.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BawcE_zG.js → index-CHyyhgQ3.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-qUBHSW_3.js → index-CP2Nz1mx.js} +3 -3
  106. package/src/assets/web-panel/assets/{index-Cxsfc5Ou.js → index-CT_-tscA.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-ClfP1Yax.js → index-CWwjhqgi.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DG2KCc8h.js → index-CYdBeNTv.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BC-4la9j.js → index-CgCeon6Z.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CEjLe8FJ.js → index-Ctt8xM0M.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-G_wPnPoA.js → index-CwAKqpJd.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B9NeNwHP.js → index-CwEJnamf.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Dbv5btEU.js → index-D8LnFSKZ.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-loaP_41H.js → index-DGtbeySv.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CJXZDwkf.js → index-DHHTczBZ.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Bo4UTTla.js → index-DIgtJB5J.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CX9cxRnU.js → index-DLfAmDGs.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-B0rgvjX8.js → index-DRh9m8hf.js} +1 -1
  119. package/src/assets/web-panel/assets/index-Dric_1LC.js +1 -0
  120. package/src/assets/web-panel/assets/{index-u2U9t07r.js → index-DzIq7BlR.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B8-2rQdr.js → index-E4x-hzLB.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BehvfmYd.js → index-GSUbdu-w.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Bazltj8w.js → index-GSpv5udU.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CxfVwfub.js → index-NMj4bTp1.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DCYJDUab.js → index-OmJk1MzD.js} +1 -1
  126. package/src/assets/web-panel/assets/index-eFol7ymc.js +1 -0
  127. package/src/assets/web-panel/assets/{index-C0ZjD3Ac.js → index-eVBDpynR.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-M7xH4eUK.js → initDefaultProps-CuryY55W.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-BrJP4mFE.js → motion-IVsWxV-s.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-BufxEuU9.js → move-DNKsQLrH.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-s6dtQtFP.js → omit-gXu4NluL.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-BcYdIZqz.js → pickAttrs-CVb4Ykex.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-Ds-3Hw3n.js → placementArrow-BarpAJK0.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-BRtrRTxl.js → responsiveObserve-eaDhQlY1.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-RJzqMQM4.js → slide-C8oU8Wlo.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-BuBhJXvr.js → statusUtils-DrBdj2xb.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-so8acGHq.js → styleChecker-_Rycq1-Q.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-BpkV467K.js → useFlexGapSupport-BagU5XLY.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-lES1RctZ.js → useFs-DZYMOaAQ.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-DdCNi4bA.js → usePersonalDataHub-CDMZ5QvU.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-nAeEg_3h.js → vnode-Bg7MuEf5.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-BWjRAfRy.js → zoom-oJIwomWy.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/insights.js +137 -0
  145. package/src/commands/review.js +392 -48
  146. package/src/index.js +2 -0
  147. package/src/lib/personal-data-hub-wiring.js +20 -0
  148. package/src/lib/session-insights.js +145 -0
  149. package/src/lib/skill-loader.js +18 -3
  150. package/src/repl/agent-repl.js +1 -3
  151. package/src/skills-bundled/run/SKILL.md +49 -0
  152. package/src/skills-bundled/verify/SKILL.md +49 -0
  153. package/src/assets/web-panel/assets/ChatBubbleRenderer-DxJmwLv8.js +0 -1
  154. package/src/assets/web-panel/assets/PdhVaultBrowser-DN_pmo2N.js +0 -7
  155. package/src/assets/web-panel/assets/Terminal-CK3zKjIE.js +0 -3
  156. package/src/assets/web-panel/assets/devWarning-BpXdFCJ4.js +0 -1
  157. package/src/assets/web-panel/assets/index-BrPKR2RZ.js +0 -1
  158. package/src/assets/web-panel/assets/index-CMEfvACO.js +0 -1
@@ -63,7 +63,9 @@ function gitCli(args, { cwd } = {}) {
63
63
 
64
64
  function isGitRepo(cwd, git = gitCli) {
65
65
  try {
66
- return git(["rev-parse", "--is-inside-work-tree"], { cwd }).trim() === "true";
66
+ return (
67
+ git(["rev-parse", "--is-inside-work-tree"], { cwd }).trim() === "true"
68
+ );
67
69
  } catch {
68
70
  return false;
69
71
  }
@@ -174,26 +176,43 @@ export function buildReviewPrompt(o = {}) {
174
176
  effort = "medium",
175
177
  mode = "default",
176
178
  fix = false,
179
+ comment = false,
177
180
  label = "working tree vs HEAD",
178
181
  untrackedBlocks = "",
179
182
  truncated = false,
180
183
  } = o;
181
184
 
182
- const tail = fix
183
- ? "First identify the issues as above. Then APPLY the fixes directly with " +
184
- "your edit tools make the smallest change that resolves each issue and " +
185
- "match the surrounding code's style. Every file edit is automatically " +
186
- "checkpointed and reversible, so edit confidently. Stay within the " +
187
- "reviewed change and its immediate dependencies do not refactor " +
188
- "unrelated code. Do NOT run destructive shell commands. When done, output " +
189
- "a Markdown summary: what you changed (with `path:line`) and any issue you " +
190
- "deliberately did NOT fix, each with a one-line reason."
191
- : "Output a Markdown report. For each finding give: a severity " +
192
- "(Critical / High / Medium / Low), the `path:line`, a one-line title, " +
193
- "why it matters, and a concrete suggested fix (a short code snippet when " +
194
- "it helps). Group findings by severity, most severe first. If nothing is " +
195
- "worth raising, say so plainly. Do NOT modify any files — this is a " +
196
- "review only.";
185
+ // comment mode → machine-readable findings so each maps to a PR inline comment.
186
+ const commentTail =
187
+ "Output ONLY a JSON array of findings and nothing else no prose, no " +
188
+ "markdown fence. Each element: " +
189
+ '{"path": "<repo-relative file path exactly as in the diff>", ' +
190
+ '"line": <integer line number in the NEW version of the file, which MUST ' +
191
+ "appear in the diff>, " +
192
+ '"severity": "Critical"|"High"|"Medium"|"Low", ' +
193
+ '"title": "<one-line summary>", ' +
194
+ '"body": "<why it matters + a concrete suggested fix>"}. ' +
195
+ "Only report lines that are present in the diff (added/context lines on the " +
196
+ "new side). Do NOT modify any files. If there is nothing worth raising, " +
197
+ "output exactly [].";
198
+
199
+ const tail = comment
200
+ ? commentTail
201
+ : fix
202
+ ? "First identify the issues as above. Then APPLY the fixes directly with " +
203
+ "your edit tools — make the smallest change that resolves each issue and " +
204
+ "match the surrounding code's style. Every file edit is automatically " +
205
+ "checkpointed and reversible, so edit confidently. Stay within the " +
206
+ "reviewed change and its immediate dependencies — do not refactor " +
207
+ "unrelated code. Do NOT run destructive shell commands. When done, output " +
208
+ "a Markdown summary: what you changed (with `path:line`) and any issue you " +
209
+ "deliberately did NOT fix, each with a one-line reason."
210
+ : "Output a Markdown report. For each finding give: a severity " +
211
+ "(Critical / High / Medium / Low), the `path:line`, a one-line title, " +
212
+ "why it matters, and a concrete suggested fix (a short code snippet when " +
213
+ "it helps). Group findings by severity, most severe first. If nothing is " +
214
+ "worth raising, say so plainly. Do NOT modify any files — this is a " +
215
+ "review only.";
197
216
 
198
217
  return [
199
218
  `You are an expert code reviewer. ${LENS[mode]}`,
@@ -208,7 +227,8 @@ export function buildReviewPrompt(o = {}) {
208
227
  "Unified diff:",
209
228
  "```diff",
210
229
  truncated
211
- ? diff + "\n\n[... diff truncated — review what is shown; note the cutoff]"
230
+ ? diff +
231
+ "\n\n[... diff truncated — review what is shown; note the cutoff]"
212
232
  : diff,
213
233
  "```",
214
234
  untrackedBlocks ? "\n" + untrackedBlocks : "",
@@ -271,6 +291,273 @@ function collectUntracked(cwd, git) {
271
291
  };
272
292
  }
273
293
 
294
+ /**
295
+ * Collect the diff (+ untracked new files) for a review scope. Shared by
296
+ * runReview and runReviewComment. Returns the (possibly truncated) diff.
297
+ */
298
+ function collectReviewDiff(scopeOpts, { cwd, git, includeUntracked }) {
299
+ const { args: diffArgs, scope, label } = resolveDiffArgs(scopeOpts, false);
300
+ const { args: statArgs } = resolveDiffArgs(scopeOpts, true);
301
+ let diff = "";
302
+ let summary = "";
303
+ try {
304
+ diff = git(diffArgs, { cwd });
305
+ summary = git(statArgs, { cwd });
306
+ } catch (err) {
307
+ throw new Error(`git diff failed: ${err.message}`);
308
+ }
309
+ // Untracked new files only matter for the default working scope; staged /
310
+ // base / range are already fully described by git.
311
+ let untracked = { blocks: "", files: [], skipped: [] };
312
+ if (scope === "working" && includeUntracked) {
313
+ untracked = collectUntracked(cwd, git);
314
+ }
315
+ const hasDiff = Boolean(diff.trim());
316
+ const hasUntracked = Boolean(untracked.blocks);
317
+ const truncated = diff.length > MAX_DIFF_CHARS;
318
+ if (truncated) diff = diff.slice(0, MAX_DIFF_CHARS);
319
+ return {
320
+ diff,
321
+ summary,
322
+ scope,
323
+ label,
324
+ untracked,
325
+ hasDiff,
326
+ hasUntracked,
327
+ truncated,
328
+ };
329
+ }
330
+
331
+ /** Run `gh` with an argv array (no shell). UTF-8 in/out; throws on failure. */
332
+ function ghCli(args, { cwd, input } = {}) {
333
+ const res = spawnSync("gh", args, {
334
+ cwd,
335
+ input,
336
+ encoding: "utf-8",
337
+ windowsHide: true,
338
+ maxBuffer: 64 * 1024 * 1024,
339
+ });
340
+ if (res.error) throw res.error;
341
+ if (res.status !== 0) {
342
+ const msg = (res.stderr || res.stdout || "").toString().trim();
343
+ throw new Error(msg || `gh ${args.join(" ")} failed (exit ${res.status})`);
344
+ }
345
+ return (res.stdout || "").toString();
346
+ }
347
+
348
+ /** Resolve the PR for the current branch via gh (read-only). Throws if none. */
349
+ function resolvePr(cwd, gh) {
350
+ let out;
351
+ try {
352
+ out = gh(
353
+ ["pr", "view", "--json", "number,baseRefName,headRefName,headRefOid,url"],
354
+ { cwd },
355
+ );
356
+ } catch (err) {
357
+ throw new Error(
358
+ `no open PR for the current branch (gh: ${err.message}). ` +
359
+ "Push the branch and open a PR first, or use `cc review` without --comment.",
360
+ );
361
+ }
362
+ let pr;
363
+ try {
364
+ pr = JSON.parse(out);
365
+ } catch {
366
+ throw new Error("could not parse `gh pr view` output.");
367
+ }
368
+ let repo = null;
369
+ try {
370
+ repo = JSON.parse(gh(["repo", "view", "--json", "nameWithOwner"], { cwd }))
371
+ .nameWithOwner;
372
+ } catch {
373
+ repo = null;
374
+ }
375
+ return { ...pr, repo };
376
+ }
377
+
378
+ /**
379
+ * Parse the agent's findings JSON (lenient). Strips a code fence, extracts the
380
+ * first JSON array, and keeps only well-formed findings. Pure.
381
+ *
382
+ * @returns {{path:string,line:number,severity:string,title:string,body:string}[]}
383
+ */
384
+ export function parseFindings(text) {
385
+ if (!text) return [];
386
+ let s = String(text).trim();
387
+ const fence = s.match(/```(?:json)?\s*([\s\S]*?)```/i);
388
+ if (fence) s = fence[1].trim();
389
+ const start = s.indexOf("[");
390
+ const end = s.lastIndexOf("]");
391
+ if (start === -1 || end === -1 || end < start) return [];
392
+ let arr;
393
+ try {
394
+ arr = JSON.parse(s.slice(start, end + 1));
395
+ } catch {
396
+ return [];
397
+ }
398
+ if (!Array.isArray(arr)) return [];
399
+ return arr
400
+ .filter(
401
+ (f) =>
402
+ f &&
403
+ typeof f === "object" &&
404
+ f.path &&
405
+ Number.isFinite(Number(f.line)) &&
406
+ Number(f.line) > 0,
407
+ )
408
+ .map((f) => ({
409
+ path: String(f.path),
410
+ line: Math.floor(Number(f.line)),
411
+ severity: f.severity ? String(f.severity) : "Note",
412
+ title: f.title ? String(f.title) : "",
413
+ body: f.body ? String(f.body) : f.title ? String(f.title) : "finding",
414
+ }));
415
+ }
416
+
417
+ /** Format one finding into a PR comment body. Pure. */
418
+ export function buildCommentBody(f) {
419
+ const sev = f.severity ? `**[${f.severity}]** ` : "";
420
+ const title = f.title ? `${f.title}\n\n` : "";
421
+ return `${sev}${title}${f.body}`.trim();
422
+ }
423
+
424
+ /** Build the GitHub "create review" API payload from findings. Pure. */
425
+ export function buildReviewPayload(findings, { commitId } = {}) {
426
+ const comments = (findings || []).map((f) => ({
427
+ path: f.path,
428
+ line: f.line,
429
+ side: "RIGHT",
430
+ body: buildCommentBody(f),
431
+ }));
432
+ const payload = {
433
+ event: "COMMENT",
434
+ body: `cc review — ${comments.length} finding(s).`,
435
+ comments,
436
+ };
437
+ if (commitId) payload.commit_id = commitId;
438
+ return payload;
439
+ }
440
+
441
+ /**
442
+ * Post the findings to the PR as a single review with inline comments
443
+ * (outward-facing — callers gate this behind --dry-run / confirmation).
444
+ */
445
+ export function postReviewComments(pr, findings, { gh = ghCli, cwd, commitId } = {}) {
446
+ if (!pr || !pr.repo || !pr.number) {
447
+ throw new Error("cannot post: PR repo/number not resolved.");
448
+ }
449
+ const payload = buildReviewPayload(findings, { commitId });
450
+ const out = gh(
451
+ [
452
+ "api",
453
+ "--method",
454
+ "POST",
455
+ `repos/${pr.repo}/pulls/${pr.number}/reviews`,
456
+ "--input",
457
+ "-",
458
+ ],
459
+ { cwd, input: JSON.stringify(payload) },
460
+ );
461
+ try {
462
+ return JSON.parse(out);
463
+ } catch {
464
+ return { raw: out };
465
+ }
466
+ }
467
+
468
+ /**
469
+ * Comment-mode review: resolve the PR, collect its diff, get machine-readable
470
+ * findings from one read-only agent turn. Side-effect-free (PR resolution is a
471
+ * read); the caller posts after confirmation. Deps injected for tests.
472
+ *
473
+ * @returns {Promise<{empty:boolean, pr:object, findings:object[], scope?:string,
474
+ * label?:string, isError?:boolean}>}
475
+ */
476
+ export async function runReviewComment(options = {}, deps = {}) {
477
+ const cwd = options.cwd || process.cwd();
478
+ const git = deps.git || gitCli;
479
+ const gh = deps.gh || ghCli;
480
+ const repoCheck = deps.isGitRepo || isGitRepo;
481
+ if (!repoCheck(cwd, git)) {
482
+ throw new Error("cc review needs a git work tree.");
483
+ }
484
+
485
+ const pr = (deps.resolvePr || resolvePr)(cwd, gh);
486
+
487
+ // Default the scope to the PR's base branch (review the PR's changes) unless
488
+ // the user gave an explicit scope.
489
+ const explicitScope =
490
+ options.staged || options.base || options.range || (options.paths || []).length;
491
+ const scopeOpts = {
492
+ staged: options.staged === true,
493
+ base: options.base || (explicitScope ? null : pr.baseRefName),
494
+ range: options.range || null,
495
+ paths: options.paths || [],
496
+ };
497
+
498
+ const collected = collectReviewDiff(scopeOpts, {
499
+ cwd,
500
+ git,
501
+ includeUntracked: false,
502
+ });
503
+ if (!collected.hasDiff && !collected.hasUntracked) {
504
+ return { empty: true, pr, findings: [] };
505
+ }
506
+
507
+ // LLM config defaults (parity with runReview).
508
+ try {
509
+ const loadConfig =
510
+ deps.loadConfig || (await import("../lib/config-manager.js")).loadConfig;
511
+ const { applyConfigLlmDefaults } = deps.applyConfigLlmDefaults
512
+ ? { applyConfigLlmDefaults: deps.applyConfigLlmDefaults }
513
+ : await import("../lib/llm-config-defaults.js");
514
+ applyConfigLlmDefaults(options, loadConfig().llm || {}, {
515
+ explicitModel: options.model,
516
+ });
517
+ } catch {
518
+ /* fall back to runner defaults */
519
+ }
520
+
521
+ const prompt = buildReviewPrompt({
522
+ diff: collected.hasDiff ? collected.diff : "(no tracked changes)",
523
+ summary: collected.summary,
524
+ effort: normalizeEffort(options.effort),
525
+ mode: resolveReviewMode(options),
526
+ comment: true,
527
+ label: collected.label,
528
+ truncated: collected.truncated,
529
+ });
530
+
531
+ const run =
532
+ deps.runAgentHeadless ||
533
+ (await import("../runtime/headless-runner.js")).runAgentHeadless;
534
+ // Suppress the runner's own stdout/stderr — we only want the structured result.
535
+ const outcome = await run(
536
+ {
537
+ prompt,
538
+ model: options.model,
539
+ provider: options.provider,
540
+ baseUrl: options.baseUrl,
541
+ apiKey: options.apiKey,
542
+ outputFormat: "text",
543
+ permissionMode: "plan",
544
+ maxTurns: Number.isFinite(options.maxTurns) ? options.maxTurns : 20,
545
+ cwd,
546
+ expandFileRefs: false,
547
+ },
548
+ { writeOut: () => {}, writeErr: () => {} },
549
+ );
550
+
551
+ return {
552
+ empty: false,
553
+ pr,
554
+ scope: collected.scope,
555
+ label: collected.label,
556
+ findings: parseFindings(outcome.result || ""),
557
+ isError: outcome.isError === true,
558
+ };
559
+ }
560
+
274
561
  /**
275
562
  * Core review run — collects the diff and dispatches one headless agent turn.
276
563
  * Deps are injected for tests (git / runAgentHeadless / config helpers).
@@ -299,34 +586,16 @@ export async function runReview(options = {}, deps = {}) {
299
586
  paths: options.paths || [],
300
587
  };
301
588
 
302
- const { args: diffArgs, scope, label } = resolveDiffArgs(scopeOpts, false);
303
- const { args: statArgs } = resolveDiffArgs(scopeOpts, true);
304
-
305
- let diff = "";
306
- let summary = "";
307
- try {
308
- diff = git(diffArgs, { cwd });
309
- summary = git(statArgs, { cwd });
310
- } catch (err) {
311
- throw new Error(`git diff failed: ${err.message}`);
312
- }
313
-
314
- // Untracked new files only matter for the default working scope; staged /
315
- // base / range are already fully described by git.
316
- let untracked = { blocks: "", files: [], skipped: [] };
317
- if (scope === "working" && options.untracked !== false) {
318
- untracked = collectUntracked(cwd, git);
319
- }
320
-
321
- const hasDiff = Boolean(diff.trim());
322
- const hasUntracked = Boolean(untracked.blocks);
589
+ const { diff, summary, scope, label, untracked, hasDiff, hasUntracked, truncated } =
590
+ collectReviewDiff(scopeOpts, {
591
+ cwd,
592
+ git,
593
+ includeUntracked: options.untracked !== false,
594
+ });
323
595
  if (!hasDiff && !hasUntracked) {
324
596
  return { exitCode: 0, isError: false, scope, empty: true };
325
597
  }
326
598
 
327
- const truncated = diff.length > MAX_DIFF_CHARS;
328
- if (truncated) diff = diff.slice(0, MAX_DIFF_CHARS);
329
-
330
599
  const prompt = buildReviewPrompt({
331
600
  diff: hasDiff ? diff : "(no tracked changes)",
332
601
  summary,
@@ -341,11 +610,11 @@ export async function runReview(options = {}, deps = {}) {
341
610
  // LLM defaults: honor .chainlesschain/config.json `llm` like cc agent/ask.
342
611
  // Explicit flags win. Best-effort — never block the review.
343
612
  try {
344
- const loadConfig = deps.loadConfig || (await import("../lib/config-manager.js")).loadConfig;
345
- const { applyConfigLlmDefaults } =
346
- deps.applyConfigLlmDefaults
347
- ? { applyConfigLlmDefaults: deps.applyConfigLlmDefaults }
348
- : await import("../lib/llm-config-defaults.js");
613
+ const loadConfig =
614
+ deps.loadConfig || (await import("../lib/config-manager.js")).loadConfig;
615
+ const { applyConfigLlmDefaults } = deps.applyConfigLlmDefaults
616
+ ? { applyConfigLlmDefaults: deps.applyConfigLlmDefaults }
617
+ : await import("../lib/llm-config-defaults.js");
349
618
  applyConfigLlmDefaults(options, loadConfig().llm || {}, {
350
619
  explicitModel: options.model,
351
620
  });
@@ -362,7 +631,8 @@ export async function runReview(options = {}, deps = {}) {
362
631
  ? options.maxTurns
363
632
  : defaultMaxTurns;
364
633
 
365
- const run = deps.runAgentHeadless ||
634
+ const run =
635
+ deps.runAgentHeadless ||
366
636
  (await import("../runtime/headless-runner.js")).runAgentHeadless;
367
637
 
368
638
  const outcome = await run({
@@ -403,12 +673,23 @@ export function registerReviewCommand(program) {
403
673
  .option("--security", "Security-focused review (/security-review parity)")
404
674
  .option("--simplify", "Cleanup-only review, no bug hunt (/simplify parity)")
405
675
  .option("--no-untracked", "Skip untracked new files (working scope)")
406
- .option("--no-checkpoint", "With --fix: do not auto-checkpoint before edits")
676
+ .option(
677
+ "--no-checkpoint",
678
+ "With --fix: do not auto-checkpoint before edits",
679
+ )
407
680
  .option("--model <model>", "Override the review model")
408
681
  .option("--provider <provider>", "Override the LLM provider")
409
682
  .option("--base-url <url>", "Override the API base URL")
410
683
  .option("--api-key <key>", "Override the API key")
411
684
  .option("--max-turns <n>", "Cap agent loop iterations")
685
+ .option(
686
+ "--comment",
687
+ "Post findings as inline comments on the current branch's PR (via gh); defaults the scope to the PR base",
688
+ )
689
+ .option(
690
+ "--dry-run",
691
+ "With --comment: show what would be posted without posting",
692
+ )
412
693
  .option("--json", "Emit the agent result envelope as JSON")
413
694
  .action(async (effortArg, options) => {
414
695
  try {
@@ -439,6 +720,69 @@ export function registerReviewCommand(program) {
439
720
  : mode === "simplify"
440
721
  ? "cleanup-only"
441
722
  : "bugs + cleanup";
723
+
724
+ // ── --comment: review the PR's diff and post inline comments ────────
725
+ if (merged.comment) {
726
+ logger.info(
727
+ chalk.gray(
728
+ `Reviewing PR diff · ${effort} effort · ${modeLabel} · ` +
729
+ (merged.dryRun ? "dry-run" : "will post comments"),
730
+ ),
731
+ );
732
+ const res = await runReviewComment(merged, {});
733
+ if (res.empty) {
734
+ logger.log(chalk.gray("No changes to review on this PR."));
735
+ return;
736
+ }
737
+ logger.log(
738
+ chalk.bold(
739
+ `${res.findings.length} finding(s) for PR #${res.pr.number}`,
740
+ ) + chalk.gray(` ${res.pr.url || ""}`),
741
+ );
742
+ for (const f of res.findings) {
743
+ logger.log(
744
+ ` ${chalk.yellow(`[${f.severity}]`)} ${chalk.cyan(`${f.path}:${f.line}`)} ${f.title}`,
745
+ );
746
+ }
747
+ if (res.findings.length === 0) {
748
+ logger.log(chalk.gray("Nothing to post."));
749
+ return;
750
+ }
751
+ if (merged.dryRun) {
752
+ logger.log(
753
+ chalk.gray("(--dry-run: not posting; re-run without --dry-run)"),
754
+ );
755
+ return;
756
+ }
757
+ // Outward-facing: confirm before posting when interactive.
758
+ if (process.stdin.isTTY) {
759
+ const { confirm } = await import("@inquirer/prompts");
760
+ const ok = await confirm({
761
+ message: `Post ${res.findings.length} comment(s) to PR #${res.pr.number}?`,
762
+ default: false,
763
+ }).catch(() => false);
764
+ if (!ok) {
765
+ logger.log(chalk.gray("Aborted — nothing posted."));
766
+ return;
767
+ }
768
+ }
769
+ try {
770
+ postReviewComments(res.pr, res.findings, {
771
+ cwd: merged.cwd,
772
+ commitId: res.pr.headRefOid,
773
+ });
774
+ logger.log(
775
+ chalk.green(
776
+ `✓ posted ${res.findings.length} comment(s) to PR #${res.pr.number}`,
777
+ ),
778
+ );
779
+ } catch (err) {
780
+ logger.error(chalk.red(`failed to post review: ${err.message}`));
781
+ process.exitCode = 1;
782
+ }
783
+ return;
784
+ }
785
+
442
786
  logger.info(
443
787
  chalk.gray(
444
788
  `Reviewing ${label} · ${effort} effort · ${modeLabel}` +
package/src/index.js CHANGED
@@ -65,6 +65,7 @@ import { registerCommandCommand } from "./commands/command.js";
65
65
  import { registerCompactCommand } from "./commands/compact.js";
66
66
  import { registerLoopCommand } from "./commands/loop.js";
67
67
  import { registerReviewCommand } from "./commands/review.js";
68
+ import { registerInsightsCommand } from "./commands/insights.js";
68
69
  import { registerPermissionsCommand } from "./commands/permissions.js";
69
70
  import { registerOutputStyleCommand } from "./commands/output-style.js";
70
71
  import { registerStatuslineCommand } from "./commands/statusline.js";
@@ -479,6 +480,7 @@ export function createProgram(opts = {}) {
479
480
  registerCompactCommand(program);
480
481
  registerLoopCommand(program);
481
482
  registerReviewCommand(program);
483
+ registerInsightsCommand(program);
482
484
  registerPermissionsCommand(program);
483
485
  registerOutputStyleCommand(program);
484
486
  registerStatuslineCommand(program);
@@ -74,6 +74,10 @@ const {
74
74
  AppleHealthAdapter,
75
75
  NeteaseMusicAdapter,
76
76
  KugouMusicAdapter,
77
+ QQMusicAdapter,
78
+ FanqieReadingAdapter,
79
+ QimaoReadingAdapter,
80
+ JoyrunAdapter,
77
81
  IqiyiVideoAdapter,
78
82
  TencentVideoAdapter,
79
83
  XiguaVideoAdapter,
@@ -85,6 +89,12 @@ const {
85
89
  IXiamenAdapter,
86
90
  MeiyouAdapter,
87
91
  TaxAdapter,
92
+ CmbcBankAdapter,
93
+ BocBankAdapter,
94
+ BankcommBankAdapter,
95
+ IcbcBankAdapter,
96
+ DcepAdapter,
97
+ Tmri12123Adapter,
88
98
  DingTalkPcAdapter,
89
99
  FeishuPcAdapter,
90
100
  WeWorkPcAdapter,
@@ -554,6 +564,10 @@ async function initHub() {
554
564
  AppleHealthAdapter,
555
565
  NeteaseMusicAdapter,
556
566
  KugouMusicAdapter,
567
+ QQMusicAdapter,
568
+ FanqieReadingAdapter,
569
+ QimaoReadingAdapter,
570
+ JoyrunAdapter,
557
571
  IqiyiVideoAdapter,
558
572
  TencentVideoAdapter,
559
573
  XiguaVideoAdapter,
@@ -565,6 +579,12 @@ async function initHub() {
565
579
  IXiamenAdapter,
566
580
  MeiyouAdapter,
567
581
  TaxAdapter,
582
+ CmbcBankAdapter,
583
+ BocBankAdapter,
584
+ BankcommBankAdapter,
585
+ IcbcBankAdapter,
586
+ DcepAdapter,
587
+ Tmri12123Adapter,
568
588
  DingTalkPcAdapter,
569
589
  FeishuPcAdapter,
570
590
  WeWorkPcAdapter,