chainlesschain 0.162.71 → 0.162.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/package.json +3 -2
  2. package/src/assets/web-panel/assets/{AIOps-pes7_jGr.js → AIOps-DTI_-iZ_.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DiHWdeH1.js → ActionButton-CtpbGicW.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-C51UX-V_.js → Analytics-C1HwMd7E.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BE6LJLw9.js → AppLayout-Db953rqB.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-CtTkLTe2.js → Audit-CuIi9Vup.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-lmpVwPxc.js → Backup-DwR7Wlve.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-Dr7DR1E1.js → BaseInput-B5wNMp7S.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-DXph6klA.js → Chat-DivalHgk.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-RefrXxqp.js → ChatBubbleRenderer-BwPSr02C.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-BF0aS5R9.js → Checkbox-CJrXPCJH.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-B-oHWNTV.js → Codegen-BieZvOkC.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-B6KdyRTE.js → Col-BzvPsQgb.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-D5ac0KyO.js → Community-CWcAMlpQ.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-Dc61O2eQ.js → Compact-Bj_BLBpw.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-a48qvNmd.js → Compliance-DKvo0WAi.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-CIF9lSRj.js → Cowork-DRajk8JO.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-C_gkf4xd.js → Cron-DPz9MoUo.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-CJt15PzW.js → Crosschain-BpSuvmns.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-D8I_okEj.js → DID-Co98G00H.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-O4q-qCF2.js → Dashboard-8TSG0W7f.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-flRziiaw.js → Dropdown-CKViu7w3.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-CnnkfGPw.js → EmailListRenderer-BqfdADvJ.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CYAJpGqd.js → FamilyGuardDashboard-aWu1imGZ.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-Dm3WqzQ_.js → Federation-w4YpT8EN.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-CpAIter6.js → FormItemContext-CAk4CXid.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-ChzXcyuN.js → GenericCardRenderer-MoJw4J2L.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-DElmMsL4.js → Git-HNU_a9Jz.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-EWmgn9io.js → Governance-BkIXWYUS.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-VtOR_sef.js → Inference-CnquB88h.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-OMqlGkMR.js → KnowledgeGraph-PGSMF-uq.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-CTgYDsTZ.js → Logs-DCc-nYzu.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-DZIUTbn8.js → Marketplace-CyGX8XEt.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-DWeOErCA.js → McpTools-DBkZ5yUL.js} +4 -4
  35. package/src/assets/web-panel/assets/{Memory-DwFBp-ev.js → Memory-DmYLRCwo.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-D42xBfE3.js → MobileBridge-CszJjeNc.js} +2 -2
  37. package/src/assets/web-panel/assets/{MobileProjects-BHCHauUl.js → MobileProjects-DWgtDsta.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-CabnNsyS.js → Mtc-Bmt_Pmg4.js} +3 -3
  39. package/src/assets/web-panel/assets/{MtcAudit-Ddx9Awu5.js → MtcAudit-BmG0ys0l.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-CJpYBZ8f.js → Multisig-DNd5iMmD.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-BvPJskVG.js → NLProgramming-yxbNl09B.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-92ELvJM2.js → Notes-CQ0qAzI4.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-CXz0SUzP.js → NotificationSettings-CIzkE4ao.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-4iWRkMr-.js → OrderTableRenderer-e1VMUxTi.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-DblqJPeY.js → Organization-BNBIlf_R.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-CHfS3HwD.js → Overflow-C5GzzJTq.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-DIg0pLIG.js → P2P-DjL2jIED.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-BhD3DGjk.js → PdhVaultBrowser-C2EYDmpW.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-Ct7bwrz8.js → Permissions-BVGCXxDp.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-DG9c1eas.js → PersonalDataHub-B1xBro16.js} +4 -4
  51. package/src/assets/web-panel/assets/{Pipeline-BwQnEqG0.js → Pipeline-DIYWiDnt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-BvWaf-Ba.js → Privacy--Qx3QdO1.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-BFzMHtiW.js → ProjectInit-DYOEcV04.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-DDpokSpH.js → ProjectSettings-BcOx5-KS.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-3IL8lyPl.js → Projects-CO69txk4.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-C6BsEzSR.js → Providers-Bj8pCgzo.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-Mh6690Ey.js → QuickAsk-Cukpq-4s.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-CJbZ6wgA.js → Recommend-DJB5wUfM.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-GDcyl6iQ.js → Reputation-B9t0-nT0.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-6p4DKFSi.js → Row-4cniRgxC.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-BLhrkoDq.js → RssFeed-Y4db_T9t.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-Ckiyt35t.js → Search-DggZDzlc.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-qhh-B5Qt.js → Security-C67A6kED.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-D7a2OwKm.js → Services-BocBjvaa.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-CSMxupKd.js → Skeleton-C9jI-iOy.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-CGpMng8w.js → Skills-2baFHKOW.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-CYtaU3Ar.js → Sla-CnowXeRb.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-BTCsu1uM.js → SpeechSettings-DWGBkmUt.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-Cnzx2L5I.js → SyncSettings-B89qwCgX.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-C1_WvNc0.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-Ccdx_C3w.js → Templates-P8dBhbxa.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-ZN8c86j3.js → Tenant-DHo0pxrm.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-Dr-HvjH-.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-CjgirE9d.js → TimelineRenderer-DM7dOaUR.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-QoRpi6Wf.js → Tokens-DnJxqOPM.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-CEQKJkhs.js → Trigger-C-FLgMzr.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-UTuAzV1q.js → Trust-CIT_RVqA.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-JDs9I7fl.js → UkeySign-Cg9VS6y6.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-BACYQQSd.js → VideoEditing-BzoxE8mA.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-C-SKluhH.js → Wallet-ZkmCII8R.js} +3 -3
  81. package/src/assets/web-panel/assets/{WebAuthn-9chizTFy.js → WebAuthn-CptQdp3u.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-0mF-LAUo.js → WorkflowEditor-Vkz28khO.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-Di7QINiP.js → chat-DXdmvvEA.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-SBmhHMM9.js → colors-De7FCj5l.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BmbETbNj.js → compact-item-DnT3XzME.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-C7hFnsJ7.js → createContext-ECZfCCqd.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-gaA8VqZf.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-CFtthKDD.js → hasIn-Uodg6pAt.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-DRBc1Ewn.js → index-1dWvOqru.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-WjZVyLn7.js → index-BC8SOuGi.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-CovTrPpI.js → index-BUMNJRCl.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-CSnTUPQx.js → index-Bg1RsfAJ.js} +3 -3
  93. package/src/assets/web-panel/assets/{index-NxxQTlPJ.js → index-Blo85ZKd.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-ClIp4Vin.js → index-BtJ8BHU0.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B4etIqbf.js → index-C01WM7Pk.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DWfObC0n.js → index-C4KhsGXo.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-sz0w-D-C.js → index-C6JgjkY7.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-lRVjtXeH.js → index-C9_Cnvha.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BCcCs7LJ.js → index-CCguvASR.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C6tZzsb9.js → index-CLzPxAp4.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-D0yO3vWh.js → index-CMuqxCVw.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BcawAm_i.js → index-COTabJQd.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-Cib-RTws.js → index-CPjI3AGE.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C07kpleB.js → index-CaDZ-LMg.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DEYnWiq1.js → index-CbbfcGeJ.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CgXQwqXr.js → index-CcLDjTgI.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-C2CN7coN.js → index-CffZBdA1.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-PN02VlUB.js → index-CwXP0KcT.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-_hO8-EnW.js → index-D2YOclGO.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Dk4ez5rf.js → index-DBsl2SuZ.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-D6vNUp6c.js → index-DCvmjxu9.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-sA4vr5WV.js → index-DGwgEqwl.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DI2xH1fU.js → index-DOIeo8Qs.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-_a2NG3iP.js → index-DPcpxSQt.js} +1 -1
  115. package/src/assets/web-panel/assets/index-DTpmiTGK.js +1 -0
  116. package/src/assets/web-panel/assets/{index-CWDk3nDZ.js → index-Db33l8Ix.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CNpb8m5a.js → index-Dbfj4QL5.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dww6gCzI.js → index-Dd9Bx3tJ.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bpo7UVJe.js → index-Dkvf5upf.js} +1 -1
  120. package/src/assets/web-panel/assets/index-DwpvMYUU.js +1 -0
  121. package/src/assets/web-panel/assets/{index-BT2uOwmA.js → index-Dy0AT-uc.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C2fhXmhW.js → index-FU8Zo5cp.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BcRTX_WO.js → index-JVwNC4yP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-Dps9xdE8.js → index-JqSxr1A7.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-D134XFWR.js → index-KV6dXwKC.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D8CeUlN0.js → index-LwNszM-5.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CcBhsVYn.js → index-cHnmjGqB.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-B1zCwkvT.js → initDefaultProps-B3H1sf95.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-BDGIV9KA.js → motion-DreYO5eb.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-BITqgluK.js → move-B0OVU04M.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-uD97QKBF.js → omit-PcEEXHLZ.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-CZpXhSIE.js → pickAttrs-DH6-hDkF.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-ByUvT_08.js → placementArrow-DFamUSEw.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-BQG9LlBs.js → responsiveObserve-DT1grAyh.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Bx9TyeEE.js → slide-41lCsY6d.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-XWaMqYM8.js → statusUtils-FzJ7j2T7.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-BZ-nMyDB.js → styleChecker-D0Zvn50h.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-D_iwA3vx.js → useFlexGapSupport-BTxsJE5n.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-DuvW_aRX.js → useFs-DRVttEr3.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-BO7orS0d.js → usePersonalDataHub-BSe7NVv0.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-Cc_fqAL4.js → vnode-D8O7tUXh.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-BGkBp90M.js → zoom-CMQc1RZ4.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +12 -0
  145. package/src/commands/cowork.js +8 -0
  146. package/src/commands/crosschain.js +32 -4
  147. package/src/commands/init.js +10 -10
  148. package/src/commands/loop.js +9 -3
  149. package/src/commands/memory.js +6 -4
  150. package/src/commands/orchestrate.js +5 -2
  151. package/src/commands/video.js +5 -1
  152. package/src/lib/agents.js +16 -5
  153. package/src/lib/cowork-workflow.js +357 -136
  154. package/src/lib/micro-compact.js +52 -0
  155. package/src/lib/output-styles.js +41 -7
  156. package/src/lib/permission-rules.cjs +39 -0
  157. package/src/lib/project-root.cjs +87 -0
  158. package/src/lib/settings-hooks.cjs +18 -6
  159. package/src/lib/settings-loader.cjs +12 -5
  160. package/src/lib/skill-loader.js +62 -43
  161. package/src/lib/slash-commands.js +18 -2
  162. package/src/repl/agent-repl.js +228 -20
  163. package/src/repl/chat-repl.js +4 -2
  164. package/src/repl/permission-tier.js +60 -0
  165. package/src/repl/stream-decision.js +16 -0
  166. package/src/repl/think-command.js +36 -0
  167. package/src/runtime/agent-core.js +67 -10
  168. package/src/runtime/file-ref-expander.js +209 -18
  169. package/src/runtime/headless-runner.js +3 -3
  170. package/src/runtime/headless-stream.js +16 -3
  171. package/src/runtime/mcp-config.js +78 -1
  172. package/src/assets/web-panel/assets/Tasks-BhnGtqaZ.js +0 -1
  173. package/src/assets/web-panel/assets/Terminal-BfgM0oyN.js +0 -3
  174. package/src/assets/web-panel/assets/devWarning-gNvbyy4j.js +0 -1
  175. package/src/assets/web-panel/assets/index-BNXpMnIY.js +0 -1
  176. package/src/assets/web-panel/assets/index-gfHxqT1Q.js +0 -1
@@ -625,6 +625,206 @@ export async function runLoopStep({
625
625
  };
626
626
  }
627
627
 
628
+ // ─── Step node + no-barrier pipeline ──────────────────────────────────────────
629
+
630
+ /**
631
+ * Run a single step to completion, resolving its when-gate / loop / forEach /
632
+ * plain task exactly as the batch executor does, and storing results (including
633
+ * a forEach parent aggregate) in `resultsById`. Returns `{ outcomes, failed }`:
634
+ * `outcomes` are the entries to add to the run's step list (forEach contributes
635
+ * its children, not the parent); `failed` is true when any non-skipped outcome
636
+ * is not "completed". Used by the no-barrier pipeline scheduler.
637
+ */
638
+ export async function runStepNode(step, ctx) {
639
+ const { resultsById, cwd, llmOptions, onStepStart, onStepComplete } = ctx;
640
+ const recordId = step.id;
641
+ const single = (status, summary) => {
642
+ const o = { id: recordId, status, taskId: null, result: { summary } };
643
+ resultsById.set(recordId, o);
644
+ return {
645
+ outcomes: [o],
646
+ failed: status !== "completed" && status !== "skipped",
647
+ };
648
+ };
649
+
650
+ let runThis;
651
+ try {
652
+ runThis = shouldRunStep(step, resultsById);
653
+ } catch (err) {
654
+ return single("failed", err.message);
655
+ }
656
+ if (!runThis) return single("skipped", "when-condition false");
657
+
658
+ if (isLoopStep(step)) {
659
+ if (onStepStart) onStepStart({ stepId: recordId, message: step.message });
660
+ const o = await runLoopStep({
661
+ step,
662
+ recordId,
663
+ cwd,
664
+ llmOptions,
665
+ resultsById,
666
+ });
667
+ resultsById.set(recordId, o);
668
+ if (onStepComplete) onStepComplete(o);
669
+ return {
670
+ outcomes: [o],
671
+ failed: o.status !== "completed" && o.status !== "skipped",
672
+ };
673
+ }
674
+
675
+ if (step.forEach !== undefined) {
676
+ let items;
677
+ try {
678
+ items = resolveForEachItems(step.forEach, resultsById);
679
+ } catch (err) {
680
+ return single("failed", err.message);
681
+ }
682
+ if (items.length === 0) return single("skipped", "forEach items empty");
683
+ const children = await Promise.all(
684
+ items.map(async (item, k) => {
685
+ const childId = `${recordId}[${k}]`;
686
+ const withItem = substituteItem(step.message, item);
687
+ const msg = substitutePlaceholders(withItem, resultsById);
688
+ if (onStepStart) onStepStart({ stepId: childId, message: msg });
689
+ const r = await runStepWithRetry({
690
+ step,
691
+ message: msg,
692
+ cwd,
693
+ llmOptions,
694
+ });
695
+ const co = outcomeFromRetry(childId, r);
696
+ resultsById.set(childId, co);
697
+ if (onStepComplete) onStepComplete(co);
698
+ return co;
699
+ }),
700
+ );
701
+ const allOk = children.every((c) => c.status === "completed");
702
+ const anyOk = children.some((c) => c.status === "completed");
703
+ resultsById.set(recordId, {
704
+ id: recordId,
705
+ status: allOk ? "completed" : anyOk ? "partial" : "failed",
706
+ taskId: null,
707
+ result: {
708
+ summary: children.map((c) => c.result?.summary ?? "").join("\n"),
709
+ children: children.length,
710
+ },
711
+ });
712
+ return {
713
+ outcomes: children,
714
+ failed: children.some((c) => c.status !== "completed"),
715
+ };
716
+ }
717
+
718
+ const message = substitutePlaceholders(step.message, resultsById);
719
+ if (onStepStart) onStepStart({ stepId: recordId, message });
720
+ const r = await runStepWithRetry({ step, message, cwd, llmOptions });
721
+ const o = outcomeFromRetry(recordId, r);
722
+ resultsById.set(recordId, o);
723
+ if (onStepComplete) onStepComplete(o);
724
+ return { outcomes: [o], failed: o.status !== "completed" };
725
+ }
726
+
727
+ /**
728
+ * No-barrier pipeline scheduler: start each step the instant *its own*
729
+ * dependencies finish, rather than waiting for the whole dependency level.
730
+ * Up to `maxParallel` step nodes run concurrently. On failure with
731
+ * `continueOnError` off, no new steps are scheduled (in-flight ones finish) and
732
+ * the rest are marked skipped. Produces the same outcome set as the batch
733
+ * executor — only the wall-clock idle between levels is removed.
734
+ */
735
+ export async function runPipeline({
736
+ steps,
737
+ resultsById,
738
+ maxParallel = 4,
739
+ continueOnError = false,
740
+ cwd,
741
+ llmOptions = {},
742
+ onStepStart,
743
+ onStepComplete,
744
+ }) {
745
+ const limit = Math.max(1, Math.floor(maxParallel) || 1);
746
+ const remainingDeps = new Map(
747
+ steps.map((s) => [s.id, new Set(s.dependsOn || [])]),
748
+ );
749
+ const dependents = new Map(steps.map((s) => [s.id, []]));
750
+ for (const s of steps) {
751
+ for (const d of s.dependsOn || []) {
752
+ if (dependents.has(d)) dependents.get(d).push(s.id);
753
+ }
754
+ }
755
+ const scheduled = new Set();
756
+ const stepOutcomes = [];
757
+ let anyFailure = false;
758
+ let halted = false;
759
+ let active = 0;
760
+
761
+ await new Promise((resolve) => {
762
+ function pump() {
763
+ if (!halted) {
764
+ for (const s of steps) {
765
+ if (active >= limit) break;
766
+ if (scheduled.has(s.id)) continue;
767
+ if (remainingDeps.get(s.id).size !== 0) continue;
768
+ scheduled.add(s.id);
769
+ active++;
770
+ launch(s);
771
+ }
772
+ }
773
+ if (active === 0 && (halted || scheduled.size === steps.length)) {
774
+ for (const s of steps) {
775
+ if (scheduled.has(s.id)) continue;
776
+ const o = {
777
+ id: s.id,
778
+ status: "skipped",
779
+ taskId: null,
780
+ result: { summary: "skipped due to earlier failure" },
781
+ };
782
+ resultsById.set(s.id, o);
783
+ stepOutcomes.push(o);
784
+ scheduled.add(s.id);
785
+ }
786
+ resolve();
787
+ }
788
+ }
789
+
790
+ async function launch(step) {
791
+ let res;
792
+ try {
793
+ res = await runStepNode(step, {
794
+ resultsById,
795
+ cwd,
796
+ llmOptions,
797
+ onStepStart,
798
+ onStepComplete,
799
+ });
800
+ } catch (err) {
801
+ const o = {
802
+ id: step.id,
803
+ status: "failed",
804
+ taskId: null,
805
+ result: { summary: `Step threw: ${err.message}` },
806
+ };
807
+ resultsById.set(step.id, o);
808
+ res = { outcomes: [o], failed: true };
809
+ }
810
+ stepOutcomes.push(...res.outcomes);
811
+ active--;
812
+ if (res.failed) {
813
+ anyFailure = true;
814
+ if (!continueOnError) halted = true;
815
+ }
816
+ for (const depId of dependents.get(step.id) || []) {
817
+ remainingDeps.get(depId).delete(step.id);
818
+ }
819
+ pump();
820
+ }
821
+
822
+ pump();
823
+ });
824
+
825
+ return { stepOutcomes, anyFailure };
826
+ }
827
+
628
828
  // ─── Execution ───────────────────────────────────────────────────────────────
629
829
 
630
830
  /**
@@ -646,8 +846,12 @@ export async function runLoopStep({
646
846
  * @param {object} options
647
847
  * @param {object} options.workflow - Workflow definition
648
848
  * @param {string} [options.cwd] - Working directory for history
649
- * @param {number} [options.maxParallel] - Max parallel steps per batch
849
+ * @param {number} [options.maxParallel] - Max parallel steps (per batch, or
850
+ * concurrent step nodes in pipeline mode)
650
851
  * @param {boolean} [options.continueOnError] - Keep running after a failure
852
+ * @param {boolean} [options.pipeline] - No-barrier scheduling: start each step
853
+ * as soon as its own deps finish instead of waiting for the dependency level.
854
+ * Defaults to `workflow.pipeline ?? false`. Same outcomes, less idle wait.
651
855
  * @param {object} [options.llmOptions] - Forwarded to each task
652
856
  * @param {function} [options.onStepStart]
653
857
  * @param {function} [options.onStepComplete]
@@ -668,6 +872,7 @@ export async function executeWorkflow(options = {}) {
668
872
  llmOptions = {},
669
873
  onStepStart,
670
874
  onStepComplete,
875
+ pipeline,
671
876
  } = options;
672
877
 
673
878
  const { valid, errors } = validateWorkflow(workflow);
@@ -678,79 +883,54 @@ export async function executeWorkflow(options = {}) {
678
883
  );
679
884
  }
680
885
 
681
- const batches = planBatches(workflow.steps);
886
+ const usePipeline = pipeline ?? workflow.pipeline ?? false;
682
887
  const resultsById = new Map();
683
- const stepOutcomes = [];
684
888
  const startedAt = new Date(_deps.now()).toISOString();
685
- let anyFailure = false;
889
+ let stepOutcomes;
890
+ let anyFailure;
686
891
 
687
- for (const batch of batches) {
688
- // Respect maxParallel by slicing batch into chunks
689
- const chunks = [];
690
- for (let i = 0; i < batch.length; i += maxParallel) {
691
- chunks.push(batch.slice(i, i + maxParallel));
692
- }
892
+ if (usePipeline) {
893
+ ({ stepOutcomes, anyFailure } = await runPipeline({
894
+ steps: workflow.steps,
895
+ resultsById,
896
+ maxParallel,
897
+ continueOnError,
898
+ cwd,
899
+ llmOptions,
900
+ onStepStart,
901
+ onStepComplete,
902
+ }));
903
+ } else {
904
+ stepOutcomes = [];
905
+ anyFailure = false;
906
+ const batches = planBatches(workflow.steps);
907
+ for (const batch of batches) {
908
+ // Respect maxParallel by slicing batch into chunks
909
+ const chunks = [];
910
+ for (let i = 0; i < batch.length; i += maxParallel) {
911
+ chunks.push(batch.slice(i, i + maxParallel));
912
+ }
693
913
 
694
- for (const chunk of chunks) {
695
- // Expand forEach / when into concrete tasks for this chunk
696
- const runnable = []; // { step, message, recordId, parentId }
697
- const preOutcomes = []; // outcomes produced synchronously (skipped)
698
- for (const step of chunk) {
699
- if (anyFailure && !continueOnError) {
700
- const outcome = {
701
- id: step.id,
702
- status: "skipped",
703
- taskId: null,
704
- result: { summary: "skipped due to earlier failure" },
705
- };
706
- resultsById.set(step.id, outcome);
707
- preOutcomes.push(outcome);
708
- continue;
709
- }
710
- // when-gate
711
- let runThis = true;
712
- try {
713
- runThis = shouldRunStep(step, resultsById);
714
- } catch (err) {
715
- anyFailure = true;
716
- const outcome = {
717
- id: step.id,
718
- status: "failed",
719
- taskId: null,
720
- result: { summary: err.message },
721
- };
722
- resultsById.set(step.id, outcome);
723
- preOutcomes.push(outcome);
724
- continue;
725
- }
726
- if (!runThis) {
727
- const outcome = {
728
- id: step.id,
729
- status: "skipped",
730
- taskId: null,
731
- result: { summary: "when-condition false" },
732
- };
733
- resultsById.set(step.id, outcome);
734
- preOutcomes.push(outcome);
735
- continue;
736
- }
737
- // loop node — runs its body repeatedly; per-iteration substitution
738
- // happens inside runLoopStep, so push the raw template.
739
- if (isLoopStep(step)) {
740
- runnable.push({
741
- step,
742
- message: step.message,
743
- recordId: step.id,
744
- parentId: null,
745
- isLoop: true,
746
- });
747
- continue;
748
- }
749
- // forEach-expansion
750
- if (step.forEach !== undefined) {
751
- let items;
914
+ for (const chunk of chunks) {
915
+ // Expand forEach / when into concrete tasks for this chunk
916
+ const runnable = []; // { step, message, recordId, parentId }
917
+ const preOutcomes = []; // outcomes produced synchronously (skipped)
918
+ for (const step of chunk) {
919
+ if (anyFailure && !continueOnError) {
920
+ const outcome = {
921
+ id: step.id,
922
+ status: "skipped",
923
+ taskId: null,
924
+ result: { summary: "skipped due to earlier failure" },
925
+ };
926
+ resultsById.set(step.id, outcome);
927
+ preOutcomes.push(outcome);
928
+ continue;
929
+ }
930
+ // when-gate
931
+ let runThis = true;
752
932
  try {
753
- items = resolveForEachItems(step.forEach, resultsById);
933
+ runThis = shouldRunStep(step, resultsById);
754
934
  } catch (err) {
755
935
  anyFailure = true;
756
936
  const outcome = {
@@ -763,91 +943,132 @@ export async function executeWorkflow(options = {}) {
763
943
  preOutcomes.push(outcome);
764
944
  continue;
765
945
  }
766
- if (items.length === 0) {
946
+ if (!runThis) {
767
947
  const outcome = {
768
948
  id: step.id,
769
949
  status: "skipped",
770
950
  taskId: null,
771
- result: { summary: "forEach items empty" },
951
+ result: { summary: "when-condition false" },
772
952
  };
773
953
  resultsById.set(step.id, outcome);
774
954
  preOutcomes.push(outcome);
775
955
  continue;
776
956
  }
777
- for (let k = 0; k < items.length; k++) {
778
- const childId = `${step.id}[${k}]`;
779
- const withItem = substituteItem(step.message, items[k]);
780
- const msg = substitutePlaceholders(withItem, resultsById);
957
+ // loop node runs its body repeatedly; per-iteration substitution
958
+ // happens inside runLoopStep, so push the raw template.
959
+ if (isLoopStep(step)) {
781
960
  runnable.push({
782
961
  step,
783
- message: msg,
784
- recordId: childId,
785
- parentId: step.id,
962
+ message: step.message,
963
+ recordId: step.id,
964
+ parentId: null,
965
+ isLoop: true,
786
966
  });
967
+ continue;
787
968
  }
788
- continue;
789
- }
790
- const message = substitutePlaceholders(step.message, resultsById);
791
- runnable.push({ step, message, recordId: step.id, parentId: null });
792
- }
793
-
794
- const promises = runnable.map(
795
- async ({ step, message, recordId, isLoop }) => {
796
- if (onStepStart) onStepStart({ stepId: recordId, message });
797
- let outcome;
798
- if (isLoop) {
799
- outcome = await runLoopStep({
800
- step,
801
- recordId,
802
- cwd,
803
- llmOptions,
804
- resultsById,
805
- });
806
- } else {
807
- const r = await runStepWithRetry({
808
- step,
809
- message,
810
- cwd,
811
- llmOptions,
812
- });
813
- outcome = outcomeFromRetry(recordId, r);
969
+ // forEach-expansion
970
+ if (step.forEach !== undefined) {
971
+ let items;
972
+ try {
973
+ items = resolveForEachItems(step.forEach, resultsById);
974
+ } catch (err) {
975
+ anyFailure = true;
976
+ const outcome = {
977
+ id: step.id,
978
+ status: "failed",
979
+ taskId: null,
980
+ result: { summary: err.message },
981
+ };
982
+ resultsById.set(step.id, outcome);
983
+ preOutcomes.push(outcome);
984
+ continue;
985
+ }
986
+ if (items.length === 0) {
987
+ const outcome = {
988
+ id: step.id,
989
+ status: "skipped",
990
+ taskId: null,
991
+ result: { summary: "forEach items empty" },
992
+ };
993
+ resultsById.set(step.id, outcome);
994
+ preOutcomes.push(outcome);
995
+ continue;
996
+ }
997
+ for (let k = 0; k < items.length; k++) {
998
+ const childId = `${step.id}[${k}]`;
999
+ const withItem = substituteItem(step.message, items[k]);
1000
+ const msg = substitutePlaceholders(withItem, resultsById);
1001
+ runnable.push({
1002
+ step,
1003
+ message: msg,
1004
+ recordId: childId,
1005
+ parentId: step.id,
1006
+ });
1007
+ }
1008
+ continue;
814
1009
  }
815
- if (outcome.status !== "completed") anyFailure = true;
816
- resultsById.set(recordId, outcome);
817
- if (onStepComplete) onStepComplete(outcome);
818
- return outcome;
819
- },
820
- );
1010
+ const message = substitutePlaceholders(step.message, resultsById);
1011
+ runnable.push({ step, message, recordId: step.id, parentId: null });
1012
+ }
821
1013
 
822
- const results = await Promise.all(promises);
823
- stepOutcomes.push(...preOutcomes, ...results);
824
-
825
- // Aggregate forEach children into a parent entry so downstream
826
- // `${step.<parent>.summary}` references still work.
827
- const byParent = new Map();
828
- for (let k = 0; k < runnable.length; k++) {
829
- const r = runnable[k];
830
- if (!r.parentId) continue;
831
- if (!byParent.has(r.parentId)) byParent.set(r.parentId, []);
832
- byParent.get(r.parentId).push(results[k]);
833
- }
834
- for (const [parentId, children] of byParent) {
835
- const allOk = children.every((c) => c.status === "completed");
836
- const anyOk = children.some((c) => c.status === "completed");
837
- const status = allOk ? "completed" : anyOk ? "partial" : "failed";
838
- resultsById.set(parentId, {
839
- id: parentId,
840
- status,
841
- taskId: null,
842
- result: {
843
- summary: children.map((c) => c.result?.summary ?? "").join("\n"),
844
- children: children.length,
1014
+ const promises = runnable.map(
1015
+ async ({ step, message, recordId, isLoop }) => {
1016
+ if (onStepStart) onStepStart({ stepId: recordId, message });
1017
+ let outcome;
1018
+ if (isLoop) {
1019
+ outcome = await runLoopStep({
1020
+ step,
1021
+ recordId,
1022
+ cwd,
1023
+ llmOptions,
1024
+ resultsById,
1025
+ });
1026
+ } else {
1027
+ const r = await runStepWithRetry({
1028
+ step,
1029
+ message,
1030
+ cwd,
1031
+ llmOptions,
1032
+ });
1033
+ outcome = outcomeFromRetry(recordId, r);
1034
+ }
1035
+ if (outcome.status !== "completed") anyFailure = true;
1036
+ resultsById.set(recordId, outcome);
1037
+ if (onStepComplete) onStepComplete(outcome);
1038
+ return outcome;
845
1039
  },
846
- });
1040
+ );
1041
+
1042
+ const results = await Promise.all(promises);
1043
+ stepOutcomes.push(...preOutcomes, ...results);
1044
+
1045
+ // Aggregate forEach children into a parent entry so downstream
1046
+ // `${step.<parent>.summary}` references still work.
1047
+ const byParent = new Map();
1048
+ for (let k = 0; k < runnable.length; k++) {
1049
+ const r = runnable[k];
1050
+ if (!r.parentId) continue;
1051
+ if (!byParent.has(r.parentId)) byParent.set(r.parentId, []);
1052
+ byParent.get(r.parentId).push(results[k]);
1053
+ }
1054
+ for (const [parentId, children] of byParent) {
1055
+ const allOk = children.every((c) => c.status === "completed");
1056
+ const anyOk = children.some((c) => c.status === "completed");
1057
+ const status = allOk ? "completed" : anyOk ? "partial" : "failed";
1058
+ resultsById.set(parentId, {
1059
+ id: parentId,
1060
+ status,
1061
+ taskId: null,
1062
+ result: {
1063
+ summary: children.map((c) => c.result?.summary ?? "").join("\n"),
1064
+ children: children.length,
1065
+ },
1066
+ });
1067
+ }
847
1068
  }
848
- }
849
1069
 
850
- if (anyFailure && !continueOnError) break;
1070
+ if (anyFailure && !continueOnError) break;
1071
+ }
851
1072
  }
852
1073
 
853
1074
  const finishedAt = new Date(_deps.now()).toISOString();
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Micro-compaction (Claude-Code `/microcompact` parity). Where full compaction
3
+ * summarizes the whole history when it grows large, micro-compaction is
4
+ * surgical: it trims the bulkiest OLD items — large tool results — in place,
5
+ * keeping the conversation flow and the most-recent messages verbatim. Because
6
+ * it only SHORTENS a tool message's content (never removes the message), it can
7
+ * never orphan a tool_call→tool_result pair, so it's safe to run any time.
8
+ *
9
+ * Pure → unit-testable.
10
+ */
11
+
12
+ const DEFAULT_KEEP_RECENT = 6; // last N messages kept verbatim
13
+ const DEFAULT_MAX_TOOL_CHARS = 400; // trim older tool results longer than this
14
+
15
+ /**
16
+ * @param {Array} messages OpenAI-shaped messages ({role, content, …}).
17
+ * @param {object} [opts] { keepRecent, maxToolChars }
18
+ * @returns {{ messages: Array, stats: {trimmed:number, saved:number, kept:number} }}
19
+ * A NEW array (originals untouched); `saved` ≈ characters freed.
20
+ */
21
+ export function microCompact(messages, opts = {}) {
22
+ if (!Array.isArray(messages)) {
23
+ return { messages, stats: { trimmed: 0, saved: 0, kept: 0 } };
24
+ }
25
+ const keepRecent = Number.isFinite(opts.keepRecent)
26
+ ? opts.keepRecent
27
+ : DEFAULT_KEEP_RECENT;
28
+ const maxChars = Number.isFinite(opts.maxToolChars)
29
+ ? opts.maxToolChars
30
+ : DEFAULT_MAX_TOOL_CHARS;
31
+ // messages at index >= cutoff are "recent" and never touched.
32
+ const cutoff = Math.max(0, messages.length - keepRecent);
33
+
34
+ let trimmed = 0;
35
+ let saved = 0;
36
+ const out = messages.map((m, i) => {
37
+ if (i >= cutoff) return m; // recent → verbatim
38
+ if (!m || m.role !== "tool") return m; // only old tool results
39
+ const content = typeof m.content === "string" ? m.content : "";
40
+ if (content.length <= maxChars) return m; // small enough already
41
+ trimmed += 1;
42
+ saved += content.length - maxChars;
43
+ const head = content.slice(0, maxChars);
44
+ return {
45
+ ...m,
46
+ content: `${head}\n… [tool result trimmed — ${content.length} chars; older context dropped to save space]`,
47
+ _microCompacted: true,
48
+ };
49
+ });
50
+
51
+ return { messages: out, stats: { trimmed, saved, kept: keepRecent } };
52
+ }
@@ -17,6 +17,7 @@
17
17
  import fsDefault from "node:fs";
18
18
  import pathDefault from "node:path";
19
19
  import { homedir as homedirDefault } from "node:os";
20
+ import { projectRootBase } from "./project-root.cjs";
20
21
 
21
22
  export const _deps = {
22
23
  fs: fsDefault,
@@ -46,7 +47,8 @@ export const BUILTIN_OUTPUT_STYLES = Object.freeze({
46
47
  },
47
48
  learning: {
48
49
  name: "learning",
49
- description: "Collaborative — leaves small instructive pieces for the user.",
50
+ description:
51
+ "Collaborative — leaves small instructive pieces for the user.",
50
52
  body: [
51
53
  "## Output style: Learning",
52
54
  "Work collaboratively. When a small, well-scoped piece of the task would be",
@@ -82,11 +84,31 @@ function parseFrontmatter(content) {
82
84
  /** Directories scanned for style files (project first, then personal). */
83
85
  function styleDirs(cwd, home) {
84
86
  const { path } = _deps;
85
- return [
86
- { dir: path.join(cwd, ".chainlesschain", "output-styles"), scope: "project" },
87
+ const dirs = [
88
+ {
89
+ dir: path.join(cwd, ".chainlesschain", "output-styles"),
90
+ scope: "project",
91
+ },
87
92
  { dir: path.join(cwd, ".claude", "output-styles"), scope: "project" },
88
- { dir: path.join(home, ".claude", "output-styles"), scope: "personal" },
89
93
  ];
94
+ // Subdirectory run: also scan the project-root `.claude` (closest cwd wins on
95
+ // a name clash via the reverse + last-write-wins in discoverOutputStyles).
96
+ const root = projectRootBase(cwd, { fs: _deps.fs, path });
97
+ if (root) {
98
+ dirs.push({
99
+ dir: path.join(root, ".chainlesschain", "output-styles"),
100
+ scope: "project",
101
+ });
102
+ dirs.push({
103
+ dir: path.join(root, ".claude", "output-styles"),
104
+ scope: "project",
105
+ });
106
+ }
107
+ dirs.push({
108
+ dir: path.join(home, ".claude", "output-styles"),
109
+ scope: "personal",
110
+ });
111
+ return dirs;
90
112
  }
91
113
 
92
114
  /** Discover all styles: built-ins + files (a file shadows a built-in by name). */
@@ -155,7 +177,11 @@ export function settingsDefaultOutputStyle(cwd = process.cwd(), opts = {}) {
155
177
  try {
156
178
  if (!fs.existsSync(f)) continue;
157
179
  const data = JSON.parse(fs.readFileSync(f, "utf-8"));
158
- if (data && typeof data.outputStyle === "string" && data.outputStyle.trim()) {
180
+ if (
181
+ data &&
182
+ typeof data.outputStyle === "string" &&
183
+ data.outputStyle.trim()
184
+ ) {
159
185
  value = data.outputStyle.trim();
160
186
  }
161
187
  } catch {
@@ -170,8 +196,16 @@ export function settingsDefaultOutputStyle(cwd = process.cwd(), opts = {}) {
170
196
  * Precedence: explicit name → settings.json `outputStyle` → none.
171
197
  * Returns `{ name, body }` (body may be "" for `default`) or null if unresolved.
172
198
  */
173
- export function resolveOutputStyle(explicitName, cwd = process.cwd(), opts = {}) {
174
- const name = (explicitName || settingsDefaultOutputStyle(cwd, opts) || "").trim();
199
+ export function resolveOutputStyle(
200
+ explicitName,
201
+ cwd = process.cwd(),
202
+ opts = {},
203
+ ) {
204
+ const name = (
205
+ explicitName ||
206
+ settingsDefaultOutputStyle(cwd, opts) ||
207
+ ""
208
+ ).trim();
175
209
  if (!name) return null;
176
210
  const style = getOutputStyle(name, cwd, opts);
177
211
  if (!style) return { name, body: "", missing: true };