chainlesschain 0.162.71 → 0.162.72

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 (167) hide show
  1. package/package.json +3 -2
  2. package/src/assets/web-panel/assets/{AIOps-pes7_jGr.js → AIOps-1bl50Cen.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DiHWdeH1.js → ActionButton-Bw4kAx-1.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-C51UX-V_.js → Analytics-junq7r42.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BE6LJLw9.js → AppLayout-vf1TVGeu.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-CtTkLTe2.js → Audit-CBzpgcL9.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-lmpVwPxc.js → Backup-ChwGPeP4.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-Dr7DR1E1.js → BaseInput-2G2KGE6M.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-DXph6klA.js → Chat-Cr9NwfDA.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-RefrXxqp.js → ChatBubbleRenderer-CJvlo_ay.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-BF0aS5R9.js → Checkbox-DN_5PBT7.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-B-oHWNTV.js → Codegen-D4bluAgT.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-B6KdyRTE.js → Col-DBP3UjYW.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-D5ac0KyO.js → Community-ge-SvR3c.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-Dc61O2eQ.js → Compact-DGXvlGNv.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-a48qvNmd.js → Compliance-Cn7nBsFQ.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-CIF9lSRj.js → Cowork-DgHEO2de.js} +3 -3
  18. package/src/assets/web-panel/assets/{Cron-C_gkf4xd.js → Cron-DUbYxPs0.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-CJt15PzW.js → Crosschain-3J0MWPQq.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-D8I_okEj.js → DID-BR_Jpkh4.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-O4q-qCF2.js → Dashboard-ffykLkAJ.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-flRziiaw.js → Dropdown-DaI38dXT.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-CnnkfGPw.js → EmailListRenderer-CnIzkUVG.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CYAJpGqd.js → FamilyGuardDashboard-BxrgAAZg.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-Dm3WqzQ_.js → Federation-BuS_FRh3.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-CpAIter6.js → FormItemContext-DBG-8g1w.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-ChzXcyuN.js → GenericCardRenderer-CmEc8RgH.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-DElmMsL4.js → Git-CK10BYwY.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-EWmgn9io.js → Governance-C8cABM_I.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-VtOR_sef.js → Inference-Dr4_DIw3.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-OMqlGkMR.js → KnowledgeGraph-0_bLuvvb.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-CTgYDsTZ.js → Logs-PVGZxt9z.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-DZIUTbn8.js → Marketplace-BtVnS4HW.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-DWeOErCA.js → McpTools-BVulusCC.js} +3 -3
  35. package/src/assets/web-panel/assets/{Memory-DwFBp-ev.js → Memory-DEMtNbJ9.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-D42xBfE3.js → MobileBridge-5QL654FQ.js} +3 -3
  37. package/src/assets/web-panel/assets/{MobileProjects-BHCHauUl.js → MobileProjects-G5Du9Thr.js} +1 -1
  38. package/src/assets/web-panel/assets/{Mtc-CabnNsyS.js → Mtc-CNFPJej0.js} +4 -4
  39. package/src/assets/web-panel/assets/{MtcAudit-Ddx9Awu5.js → MtcAudit-DAJ81Cej.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-CJpYBZ8f.js → Multisig-Cwj8tXfT.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-BvPJskVG.js → NLProgramming-Di0ptaL6.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-92ELvJM2.js → Notes-Cse_4Ox6.js} +3 -3
  43. package/src/assets/web-panel/assets/{NotificationSettings-CXz0SUzP.js → NotificationSettings-ntpoi5ec.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-4iWRkMr-.js → OrderTableRenderer-CbKsOM0D.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-DblqJPeY.js → Organization-Bhjya5h9.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-CHfS3HwD.js → Overflow-C0u3aive.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P-DIg0pLIG.js → P2P-BWrTwf_a.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-BhD3DGjk.js → PdhVaultBrowser-pld2Qlqk.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-Ct7bwrz8.js → Permissions-CW5FG3mE.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-DG9c1eas.js → PersonalDataHub-BuBmqfDa.js} +2 -2
  51. package/src/assets/web-panel/assets/{Pipeline-BwQnEqG0.js → Pipeline-nZr06BNO.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-BvWaf-Ba.js → Privacy-B_XvMHYv.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-BFzMHtiW.js → ProjectInit-CbRHJy85.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-DDpokSpH.js → ProjectSettings-CCH8SpEa.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-3IL8lyPl.js → Projects-D5Min2Fu.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-C6BsEzSR.js → Providers-DgCY5A8A.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-Mh6690Ey.js → QuickAsk-DEcKTiTV.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-CJbZ6wgA.js → Recommend-BRaq2oKc.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-GDcyl6iQ.js → Reputation-DzdbBdVv.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-6p4DKFSi.js → Row-Ds2JNh7c.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-BLhrkoDq.js → RssFeed-Bk1-t4Ie.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-Ckiyt35t.js → Search-DaVhRwoq.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-qhh-B5Qt.js → Security-D9mXjPSu.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-D7a2OwKm.js → Services-D8sukL97.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-CSMxupKd.js → Skeleton-COCJt30X.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-CGpMng8w.js → Skills-DtFPSPSc.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-CYtaU3Ar.js → Sla-DIab-wjR.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-BTCsu1uM.js → SpeechSettings-xxIH9hgB.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-Cnzx2L5I.js → SyncSettings-DrpxzJOH.js} +2 -2
  70. package/src/assets/web-panel/assets/{Tasks-BhnGtqaZ.js → Tasks-maiJ3jAT.js} +1 -1
  71. package/src/assets/web-panel/assets/{Templates-Ccdx_C3w.js → Templates-COE-dSks.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-ZN8c86j3.js → Tenant-CLGObu4M.js} +1 -1
  73. package/src/assets/web-panel/assets/Terminal-Bw8WBvW3.js +3 -0
  74. package/src/assets/web-panel/assets/{TimelineRenderer-CjgirE9d.js → TimelineRenderer-D4gdk3Qb.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-QoRpi6Wf.js → Tokens-CSoL_uAw.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-CEQKJkhs.js → Trigger-BCRcowFi.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-UTuAzV1q.js → Trust-D5QPZ198.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-JDs9I7fl.js → UkeySign-C7SsMqfZ.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-BACYQQSd.js → VideoEditing-CDQ4HNZL.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-C-SKluhH.js → Wallet-VmG4P_Fm.js} +3 -3
  81. package/src/assets/web-panel/assets/{WebAuthn-9chizTFy.js → WebAuthn-qtC0dZxA.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-0mF-LAUo.js → WorkflowEditor-C_CSdk3l.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-Di7QINiP.js → chat-BGm8YCIo.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-SBmhHMM9.js → colors-BScOmAwk.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BmbETbNj.js → compact-item-HDwaT31n.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-C7hFnsJ7.js → createContext-CheSjPm8.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-CjO6o19j.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-CFtthKDD.js → hasIn-C1_NbX0O.js} +1 -1
  89. package/src/assets/web-panel/assets/index--jhpSxS1.js +1 -0
  90. package/src/assets/web-panel/assets/{index-D6vNUp6c.js → index-6C8mxO8j.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-ClIp4Vin.js → index-B94_DZF-.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-D134XFWR.js → index-BGROuzQG.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-Cib-RTws.js → index-BKQordyU.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-CWDk3nDZ.js → index-BMxPL1oG.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Bpo7UVJe.js → index-Bd2zS3jK.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Dww6gCzI.js → index-ByoUjX8f.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-PN02VlUB.js → index-C4FSaMAu.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CovTrPpI.js → index-C6WXnaG4.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-C6tZzsb9.js → index-C71Z__li.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-sz0w-D-C.js → index-CSaztnyZ.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-sA4vr5WV.js → index-CYkezxqK.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-lRVjtXeH.js → index-Clqj2JTi.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CNpb8m5a.js → index-Cm55PcYG.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C2fhXmhW.js → index-CxoOEb-l.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C2CN7coN.js → index-D2gy4IX0.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-WjZVyLn7.js → index-D8xpncJ0.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-_hO8-EnW.js → index-DB6gbgU2.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CgXQwqXr.js → index-DDk0s3nO.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CcBhsVYn.js → index-DQ01dBAS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D8CeUlN0.js → index-DSuWcpsv.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C07kpleB.js → index-DVyL9jbT.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Dps9xdE8.js → index-DaATJtzu.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DRBc1Ewn.js → index-DbfAaBxL.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Dk4ez5rf.js → index-DhTELUKN.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DI2xH1fU.js → index-Dk2N6hxE.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BcawAm_i.js → index-DkiIxTIS.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-B4etIqbf.js → index-DoZwBGUX.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CSnTUPQx.js → index-DppSbT8L.js} +3 -3
  119. package/src/assets/web-panel/assets/{index-BCcCs7LJ.js → index-DzE-95XH.js} +1 -1
  120. package/src/assets/web-panel/assets/index-J4Rzclyc.js +1 -0
  121. package/src/assets/web-panel/assets/{index-NxxQTlPJ.js → index-KG9xVANC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-_a2NG3iP.js → index-KXrUKw1h.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DWfObC0n.js → index-eSBoP6E_.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D0yO3vWh.js → index-ggl9cj35.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BT2uOwmA.js → index-i-xYmSsZ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DEYnWiq1.js → index-lB5kN9Yc.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BcRTX_WO.js → index-yKmudyK7.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-B1zCwkvT.js → initDefaultProps-D7Q7zDzP.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-BDGIV9KA.js → motion-B4DcaqPb.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-BITqgluK.js → move-CYxmYrFY.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-uD97QKBF.js → omit-ze_9dKw3.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-CZpXhSIE.js → pickAttrs-D24HrRSv.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-ByUvT_08.js → placementArrow-BWJZVYyS.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-BQG9LlBs.js → responsiveObserve-CseJia_L.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Bx9TyeEE.js → slide-CBWNEpey.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-XWaMqYM8.js → statusUtils-f4e6p7yd.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-BZ-nMyDB.js → styleChecker-DZmfWZ8G.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-D_iwA3vx.js → useFlexGapSupport-4RBaBnVI.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-DuvW_aRX.js → useFs-Cv6bNoEA.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-BO7orS0d.js → usePersonalDataHub-DOTETJIA.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-Cc_fqAL4.js → vnode-DqS1K6-J.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-BGkBp90M.js → zoom-C1MYzIJG.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/cowork.js +8 -0
  145. package/src/commands/crosschain.js +32 -4
  146. package/src/commands/init.js +10 -10
  147. package/src/commands/loop.js +9 -3
  148. package/src/commands/memory.js +6 -4
  149. package/src/commands/orchestrate.js +5 -2
  150. package/src/commands/video.js +5 -1
  151. package/src/lib/cowork-workflow.js +357 -136
  152. package/src/lib/micro-compact.js +52 -0
  153. package/src/lib/permission-rules.cjs +39 -0
  154. package/src/lib/skill-loader.js +62 -43
  155. package/src/repl/agent-repl.js +228 -20
  156. package/src/repl/chat-repl.js +4 -2
  157. package/src/repl/permission-tier.js +60 -0
  158. package/src/repl/stream-decision.js +16 -0
  159. package/src/repl/think-command.js +36 -0
  160. package/src/runtime/agent-core.js +42 -6
  161. package/src/runtime/file-ref-expander.js +209 -18
  162. package/src/runtime/headless-runner.js +3 -3
  163. package/src/runtime/headless-stream.js +16 -3
  164. package/src/assets/web-panel/assets/Terminal-BfgM0oyN.js +0 -3
  165. package/src/assets/web-panel/assets/devWarning-gNvbyy4j.js +0 -1
  166. package/src/assets/web-panel/assets/index-BNXpMnIY.js +0 -1
  167. 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
+ }
@@ -13,6 +13,11 @@
13
13
  * Read(./src/**) → read_file/list_dir on a path under <cwd>/src
14
14
  * Edit(//etc/**) → edit_file on an absolute path under /etc
15
15
  * WebFetch(domain:example.com) → web_fetch of https://example.com/…
16
+ * Bash(command:rm*) → run_shell whose `command` arg matches `rm*` (CC
17
+ * 2.1.178 `Tool(param:value)` — matches any named
18
+ * input parameter, incl. arbitrary MCP tool args;
19
+ * `*` crosses `/` here, unlike path globs)
20
+ * mcp__db__query(table:users) → that MCP tool whose `table` arg is "users"
16
21
  * Bash → every run_shell call
17
22
  * * → every tool call (Claude-Code deny-all idiom)
18
23
  * Bash(*) → every run_shell call (lone-`*` pattern = match-all)
@@ -197,6 +202,30 @@ function matchUrl(pattern, url) {
197
202
  return globToRegExp(pattern).test(u);
198
203
  }
199
204
 
205
+ /** Match a single named-parameter value — `Tool(param:value)`. `prefix:*` →
206
+ * starts-with; otherwise glob/exact. Unlike path globs, `*` here crosses `/`
207
+ * because param values are arbitrary strings (commands often embed paths),
208
+ * not filesystem path segments. */
209
+ function matchParamValue(pattern, value) {
210
+ const v = value == null ? "" : String(value);
211
+ if (pattern === "*" || pattern === "**") return true;
212
+ if (pattern.endsWith(":*")) {
213
+ const prefix = pattern.slice(0, -2).trim();
214
+ return v === prefix || v.startsWith(prefix);
215
+ }
216
+ if (pattern.includes("*") || pattern.includes("?")) {
217
+ const re =
218
+ "^" +
219
+ pattern
220
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
221
+ .replace(/\*/g, ".*")
222
+ .replace(/\?/g, ".") +
223
+ "$";
224
+ return new RegExp(re).test(v);
225
+ }
226
+ return v === pattern;
227
+ }
228
+
200
229
  /**
201
230
  * Does `pattern` (the inside of `Tool(...)`, or null for a bare rule) match the
202
231
  * given tool call? `null` pattern always matches.
@@ -208,6 +237,15 @@ function matchPattern(pattern, actualTool, args, cwd) {
208
237
  // command/url/path containing `/` can't slip past a deny-all (globToRegExp's
209
238
  // `*` → `[^/]*` otherwise excludes slashes).
210
239
  if (pattern === "*" || pattern === "**") return true;
240
+ // Claude-Code 2.1.178: `Tool(param:value)` matches a NAMED input parameter,
241
+ // generalizing the positional command/path/url targets below. Treated as a
242
+ // param rule only when `param` is a bare identifier AND an actual key in the
243
+ // tool's args — so command idioms (`git push:*`) and `domain:host` (whose
244
+ // prefix is not an arg key) correctly fall through to the matching below.
245
+ const pv = pattern.match(/^([A-Za-z_]\w*):([\s\S]*)$/);
246
+ if (pv && Object.prototype.hasOwnProperty.call(args || {}, pv[1])) {
247
+ return matchParamValue(pv[2].trim(), (args || {})[pv[1]]);
248
+ }
211
249
  const target = extractTarget(actualTool, args, cwd);
212
250
  if (target.kind === "command") {
213
251
  return target.value ? matchCommand(pattern, target.value) : false;
@@ -328,6 +366,7 @@ module.exports = {
328
366
  extractTarget,
329
367
  matchCommand,
330
368
  matchUrl,
369
+ matchParamValue,
331
370
  matchPattern,
332
371
  evaluatePermissionRules,
333
372
  suggestAllowRule,