chainlesschain 0.162.162 → 0.162.164
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.
- package/package.json +3 -1
- package/src/assets/web-panel/assets/{AIOps-ClI2ALgv.js → AIOps-BqRkaHGb.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BDjRcJaK.js → ActionButton-DWO7OZLC.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DikSRsaT.js → Analytics-C5oaVezM.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-9mLhMFmz.js → AppLayout-CsUESDoZ.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-BSr88BrH.js → Artifacts-Dragqu5k.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CdvyimOF.js → Audit-CQsaHctY.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D3_hCedh.js → BackgroundAgents-DdG1jNSM.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cyvv9RHf.js → Backup-DN6sjK4z.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BZM14kt8.js → BaseInput-Cxm_ZTCl.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DrQSokVz.js → Chat-DVXGmA56.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-HwJR-C6B.js → ChatBubbleRenderer-BdaCL_iE.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-bFLYeWMV.js → Checkbox-DEc4vD_A.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-7mN7xJXT.js → Codegen-CKiTcv36.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DAB5ZWm7.js → Col-Br9UUNN0.js} +1 -1
- package/src/assets/web-panel/assets/{Community-B_1TymaK.js → Community-NeUH_70T.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Bq1uSWLJ.js → Compact-BqR-z2Df.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CyiE1jEe.js → Compliance-DcWB_SgZ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Cpk0D7vm.js → Cowork-BfhgcudF.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-d_Lv3rdB.js → Cron-LaU29LgD.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DMqhHjMR.js → Crosschain-B2ZB9uwW.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Br-oPuBw.js → DID-BuHl38A2.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CfLW_RaP.js → Dashboard-m627yqvZ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DZnTOExV.js → Dropdown-C7bxF8F5.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DHIUHDv1.js → EmailListRenderer-DPLPQzLp.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bw3t3myu.js → FamilyGuardDashboard-cOiH6ike.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D9cpQPAY.js → Federation-Bvkzg88z.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Jdczr9Mr.js → FormItemContext-BTsiA7h_.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BT8ZMpC5.js → GenericCardRenderer-BGnVE5qu.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DjARip2b.js → Git-DS_j6r25.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BgWbSRcj.js → Governance-CKRG3Rsl.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CfouJciM.js → Inference-DW8INoNQ.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-50l7mrAr.js → KnowledgeGraph-BhEYeFhC.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-rq50H84B.js → Logs-wqi0uxuR.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DUPIEdQH.js → MarkdownRenderer-DS8dE8ty.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BYgPDmHU.js → Marketplace-CMlTuPLT.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-5DVgcFdx.js → McpTools-CSx4m5JJ.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-B70LPk7f.js → Memory-vnQCUy-_.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-De8ssA5Y.js → MobileBridge-BV2NA742.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-Bw0k8e1B.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-RJsOTsIA.js → Mtc-CzK_FPB1.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-Crh-6BEK.js → MtcAudit-Cb7G9oL3.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-wuoR5l3x.js → Multisig-qJxlUyzr.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-U2Mji4fZ.js → NLProgramming-DqaBJ7Te.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CdTZAyDH.js → Notes-CwhTJkRi.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C-FucWE7.js → NotificationSettings-YDs4Fal4.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DCYFTeaI.js → OrderTableRenderer-CvEALpq7.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-an3OF85L.js → Organization-CEmQm9n8.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-C-1vmYFe.js → Overflow-zby_P_LA.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Cwh47xKg.js → P2P-DsmDNFNT.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Dm38GT0k.js → PdhVaultBrowser-FWwFlZGF.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DS2Y8awD.js → Permissions-DuzQ6me5.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BQNziA0I.js → PersonalDataHub-DZbeN613.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-DF85L1ue.js → Pipeline-CoNSVAUS.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BuLornF-.js → Privacy-OYJEAaMC.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-C3Y31IwX.js → ProjectInit-CWIapV--.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BCPiI8aD.js → ProjectSettings-CX8xMxZn.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BZ6s4k6g.js → Projects-BLCN8YyY.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-D3Wp022X.js → Providers-BV_sxp75.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CUJfQkH4.js → QrScannerModal-BTnRrHRp.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-UAc0EO8l.js → QuickAsk-D1KZg018.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BaxKupcs.js → Recommend-COm5cuNg.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C75NNnXZ.js → RemoteSession-0saWEkYI.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BVXynZAk.js → Reputation-Dr7iKLS2.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C5MRZ0bi.js → Row-C1vpPBcr.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DAKkEYka.js → RssFeed-CxlWrtNj.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DvWv9YOA.js → Search-BT2V8dPN.js} +1 -1
- package/src/assets/web-panel/assets/{Security-B5peafW1.js → Security-bm9V3c5k.js} +4 -4
- package/src/assets/web-panel/assets/{Services-UQmvPEaG.js → Services-CocH1yyX.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-C3bhWpuF.js → Skeleton-DHItlMdd.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DfkKf9_H.js → Skills-C59sLc4w.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DqMSjlBM.js → Sla-Crj4BMc8.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C-WbxWUX.js → SpeechSettings-DX4KFceY.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CYuHZ4N2.js → SyncSettings-BD_iwQLr.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CyeAyB9d.js → Tasks-BmCTzYsH.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BTCeQnpq.js → Templates-BGUaxZYl.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BifQuA9Y.js → Tenant-BS0tJx2O.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Bx_9Bocf.js → Terminal--tHSAsld.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BX0RFCOm.js → TimelineRenderer-D9-MFxS4.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CGHrCmUS.js → Tokens-CiCB485f.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DlqaY4SO.js → Trigger-SmCFuW_l.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DfOmj-ay.js → Trust-DkK3Rqe0.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B72jH5fE.js → UkeySign-CDM4LGdB.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BT-63fqv.js → VideoEditing-IDB7DJXt.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dsul3sHr.js → Wallet-Bikj5cmt.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Izkwwdgy.js → WebAuthn-C9abWlAw.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-D3FHSiH1.js → WorkflowEditor-DrbRKVky.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CmVz5z3U.js → chat-CccCSDQf.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CuLgyJBp.js → colors-CXObXLhb.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Ml1YkXpw.js → compact-item-B5kfYAxC.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BvjJ48bs.js → createContext-DmiPBfip.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CvKrADNa.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DVC0157C.js → hasIn-Q6lYteAc.js} +1 -1
- package/src/assets/web-panel/assets/{index-C229ABfy.js → index-25Wlqps4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ck_52dz_.js → index-33U29UNV.js} +1 -1
- package/src/assets/web-panel/assets/{index-QXzlT9KD.js → index-4oXBDczR.js} +1 -1
- package/src/assets/web-panel/assets/{index-4SBta3d7.js → index-BGYXvMc5.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0S8NzO6.js → index-BJCCa0s_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJyN28Et.js → index-BJJ5DhKI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DC_OI9H2.js → index-BLOzViJ6.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_XuRgGn.js → index-BRrbUMoG.js} +1 -1
- package/src/assets/web-panel/assets/{index-wvb_FtaV.js → index-BUFpT17Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-KMqhcF7l.js → index-BkRDiqGc.js} +1 -1
- package/src/assets/web-panel/assets/{index-vG4XSJ1d.js → index-BsfvW6my.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYXHFr4r.js → index-By-kfPED.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuGszaWY.js → index-BzFTcQsc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXkJH-lK.js → index-C2FXdboq.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dt5KMjwJ.js → index-C5XOlTHN.js} +1 -1
- package/src/assets/web-panel/assets/{index-4wcgvPoF.js → index-CLhBDS2w.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_H_S-DY.js → index-CMq7UeoT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BydjdZnl.js → index-CVMTWNKl.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjHBpRYZ.js → index-Caghi-yL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bzr0rB5T.js → index-CdB6FuSH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbPtzB8M.js → index-CoK8-kWQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUt8kTIB.js → index-CsO3GUAY.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_vRgTl9.js → index-CwZBa20Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-DukDVXCv.js → index-D-kASucw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbepULSc.js → index-D8eBw7vW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfuKP4qe.js → index-D9wgifk4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiC6dQZG.js → index-DAYCTc07.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmFNvNLZ.js → index-DF6Q8l2h.js} +1 -1
- package/src/assets/web-panel/assets/index-DTdFUWc_.js +1 -0
- package/src/assets/web-panel/assets/{index-KjgKdZe-.js → index-DgTLApS9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpFJHiTv.js → index-DgxVJ8pg.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cw0Rjy87.js → index-DlJvIqoR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFYVQMvu.js → index-Dw4eHfsG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CudmwNBV.js → index-Rh-ytwow.js} +3 -3
- package/src/assets/web-panel/assets/{index-DDGaOWBV.js → index-StAEt2pq.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3lD5qap.js → index-bzfw951k.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzG-x9p4.js → index-fSUMbMvv.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_EvG_GW.js → index-tFHy5Wol.js} +1 -1
- package/src/assets/web-panel/assets/index-zQ0M_kz-.js +1 -0
- package/src/assets/web-panel/assets/{initDefaultProps-BDgd2YZ8.js → initDefaultProps-BNq7X72N.js} +1 -1
- package/src/assets/web-panel/assets/{motion-ErtrXdYe.js → motion-DOf9viTc.js} +1 -1
- package/src/assets/web-panel/assets/{move-_GPPNCgs.js → move-CRHTcW4x.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DRLL-8V2.js → mtc-parser-Cyoozgm2.js} +1 -1
- package/src/assets/web-panel/assets/{omit-p86sl023.js → omit-6-TjFNru.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BTu7cMLH.js → pickAttrs-DlUmO1zi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BEKz6Isr.js → placementArrow-CFOL8mIR.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Ck42c9MP.js → responsiveObserve-BtaFK5zd.js} +1 -1
- package/src/assets/web-panel/assets/{slide-1CEvuPsB.js → slide-BIbc2bur.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BDfdx1GJ.js → statusUtils-BXX9d6-w.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B4K46m5w.js → styleChecker-BGv10Bpn.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DoIVpJNq.js → useFlexGapSupport-bKnKT8tw.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DdAWi-ln.js → useFs-FY4IL4jn.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-iUu6k8dx.js → usePersonalDataHub-Bwl9TEgu.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DZz4R6Tw.js → vnode-BM3OHxAT.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DXlf9sA3.js → zoom-D1fbFiHB.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +320 -32
- package/src/commands/agent.js +105 -11
- package/src/commands/context.js +125 -14
- package/src/commands/doctor.js +85 -1
- package/src/commands/hook.js +181 -7
- package/src/commands/plugin.js +456 -1
- package/src/commands/review.js +363 -2
- package/src/commands/session.js +191 -0
- package/src/commands/team.js +19 -1
- package/src/data/changelog.json +10 -4
- package/src/gateways/ws/remote-session-protocol.js +39 -0
- package/src/gateways/ws/session-protocol.js +55 -2
- package/src/gateways/ws/ws-agent-handler.js +50 -0
- package/src/harness/jsonl-session-store.js +60 -0
- package/src/harness/worktree-isolator.js +140 -5
- package/src/lib/agent-schedule-store.js +318 -10
- package/src/lib/agent-team/team-worktree.js +37 -2
- package/src/lib/agent-tool-admission.js +125 -0
- package/src/lib/app-preview.js +360 -0
- package/src/lib/async-hook-supervisor.cjs +54 -0
- package/src/lib/capability-manifest.js +319 -0
- package/src/lib/capability-negotiation.js +23 -12
- package/src/lib/channels/channel-manager.js +54 -2
- package/src/lib/cli-context-engineering.js +9 -2
- package/src/lib/context-breakdown.js +116 -0
- package/src/lib/diagnostic-bundle.js +230 -0
- package/src/lib/doctor-checkup.js +275 -4
- package/src/lib/execution-location.js +286 -0
- package/src/lib/headless-manifest.js +13 -40
- package/src/lib/hook-event-log.cjs +193 -0
- package/src/lib/hook-stats-store.cjs +197 -0
- package/src/lib/idempotency.js +109 -0
- package/src/lib/interaction-adapter.js +34 -4
- package/src/lib/json-schema-output.js +46 -12
- package/src/lib/json-schema-validate.js +143 -3
- package/src/lib/jsonl-session-store.js +1 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +58 -0
- package/src/lib/lsp/lsp-manager.js +56 -0
- package/src/lib/monitor-event.js +290 -0
- package/src/lib/operation-fingerprint.js +217 -0
- package/src/lib/plugin-runtime/bin.js +37 -0
- package/src/lib/plugin-runtime/capabilities.js +19 -0
- package/src/lib/plugin-runtime/capability-consent.js +203 -0
- package/src/lib/plugin-runtime/hooks.js +37 -0
- package/src/lib/plugin-runtime/lsp.js +38 -0
- package/src/lib/plugin-runtime/mcp.js +40 -0
- package/src/lib/plugin-runtime/monitors.js +37 -0
- package/src/lib/plugin-runtime/plugin-options.js +151 -0
- package/src/lib/plugin-runtime/policy.js +62 -0
- package/src/lib/plugin-runtime/scopes.js +20 -4
- package/src/lib/pr-automation-policy.js +224 -0
- package/src/lib/project-instructions.js +128 -0
- package/src/lib/remote-approval-bridge.js +66 -13
- package/src/lib/repl-goal.js +132 -0
- package/src/lib/repl-rewind.js +153 -0
- package/src/lib/review-comment-anchor.js +241 -0
- package/src/lib/review-pipeline.js +46 -7
- package/src/lib/runtime-checkup.js +221 -0
- package/src/lib/schedule-planner.js +17 -1
- package/src/lib/secret-scan.js +409 -0
- package/src/lib/session-branch.js +0 -0
- package/src/lib/settings-hook-events.cjs +13 -0
- package/src/lib/settings-loader.cjs +42 -0
- package/src/lib/side-effect-ledger-store.js +88 -0
- package/src/lib/side-effect-ledger.js +401 -0
- package/src/lib/skill-loader.js +32 -0
- package/src/lib/skill-path-scope.js +63 -0
- package/src/lib/sub-agent-context.js +110 -9
- package/src/lib/sub-agent-registry.js +19 -0
- package/src/lib/subagent-inheritance.js +112 -0
- package/src/lib/telemetry/span-recorder.js +17 -4
- package/src/lib/terminal-context.js +195 -0
- package/src/lib/turn-binding-store.js +119 -0
- package/src/lib/unattended-action-policy.js +182 -0
- package/src/lib/worktree-cleanup-safety.js +138 -0
- package/src/lib/worktree-isolator.js +8 -0
- package/src/lib/worktree-sparse.js +131 -0
- package/src/repl/agent-repl.js +280 -30
- package/src/repl/permission-tier.js +28 -0
- package/src/runtime/agent-core.js +565 -21
- package/src/runtime/coding-agent-contract-shared.cjs +60 -1
- package/src/runtime/diagnostics.js +60 -0
- package/src/runtime/headless-runner.js +393 -1
- package/src/runtime/headless-stream.js +60 -1
- package/src/assets/web-panel/assets/MobileProjects-D10VISps.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DhiGrbsh.js +0 -1
- package/src/assets/web-panel/assets/index-B7a1TrU6.js +0 -1
- package/src/assets/web-panel/assets/index-C2B1KRja.js +0 -1
package/src/commands/agenda.js
CHANGED
|
@@ -7,20 +7,26 @@
|
|
|
7
7
|
* cc agenda list [--json] show all scheduled entries
|
|
8
8
|
* cc agenda run [--json] [--dry-run] fire everything due right now
|
|
9
9
|
* cc agenda cancel <id> remove one entry
|
|
10
|
+
* cc agenda prune [--older-than N] drop finished entries
|
|
10
11
|
*
|
|
11
12
|
* `run` for each due entry:
|
|
12
13
|
* - wakeup → spawn `cc agent -p <prompt>`, mark fired
|
|
13
14
|
* - cron → spawn `cc agent -p <prompt>`, advance to next fire time
|
|
14
|
-
* - monitor →
|
|
15
|
-
*
|
|
15
|
+
* - monitor → check its source (a shell <command>'s output, a <watchFile>'s
|
|
16
|
+
* content / appearance / modification, or a <watchUrl>'s response
|
|
17
|
+
* body / 2xx); if it matches stop_when, send the notification and
|
|
18
|
+
* stop; else re-arm for the next interval
|
|
16
19
|
*/
|
|
17
20
|
|
|
18
21
|
import { spawn, execSync } from "node:child_process";
|
|
22
|
+
import { readFileSync, statSync } from "node:fs";
|
|
19
23
|
import { fileURLToPath } from "node:url";
|
|
20
24
|
import chalk from "chalk";
|
|
21
25
|
import { AgentScheduleStore } from "../lib/agent-schedule-store.js";
|
|
22
26
|
import { sendAgentNotification } from "../lib/agent-notify.js";
|
|
23
|
-
import { nextWakeupAt } from "../lib/schedule-planner.js";
|
|
27
|
+
import { nextWakeupAt, partitionSchedule } from "../lib/schedule-planner.js";
|
|
28
|
+
import { monitorEventEnvelope, capEventPayload } from "../lib/monitor-event.js";
|
|
29
|
+
import { unattendedDisallowedTools } from "../lib/unattended-action-policy.js";
|
|
24
30
|
|
|
25
31
|
const BIN_PATH = fileURLToPath(
|
|
26
32
|
new URL("../../bin/chainlesschain.js", import.meta.url),
|
|
@@ -58,6 +64,20 @@ export function registerAgendaCommand(program) {
|
|
|
58
64
|
.action((id, options) => {
|
|
59
65
|
process.exitCode = runAgendaCancel(id, options);
|
|
60
66
|
});
|
|
67
|
+
|
|
68
|
+
cmd
|
|
69
|
+
.command("prune")
|
|
70
|
+
.description(
|
|
71
|
+
"Remove finished entries (fired / matched / exhausted / expired)",
|
|
72
|
+
)
|
|
73
|
+
.option(
|
|
74
|
+
"--older-than <seconds>",
|
|
75
|
+
"Only prune entries that finished more than N seconds ago",
|
|
76
|
+
)
|
|
77
|
+
.option("--json", "Machine-readable JSON output")
|
|
78
|
+
.action((options) => {
|
|
79
|
+
process.exitCode = runAgendaPrune(options);
|
|
80
|
+
});
|
|
61
81
|
}
|
|
62
82
|
|
|
63
83
|
export function runAgendaList(options = {}, _deps = {}) {
|
|
@@ -80,17 +100,30 @@ export function runAgendaList(options = {}, _deps = {}) {
|
|
|
80
100
|
log("");
|
|
81
101
|
log(chalk.bold(" Agenda:\n"));
|
|
82
102
|
for (const e of entries) {
|
|
103
|
+
const monitorWhat =
|
|
104
|
+
e.source === "file"
|
|
105
|
+
? `file ${e.watchFile}`
|
|
106
|
+
: e.source === "http"
|
|
107
|
+
? `url ${e.watchUrl}`
|
|
108
|
+
: `every ${Math.round(e.intervalMs / 1000)}s`;
|
|
83
109
|
const when =
|
|
84
110
|
e.kind === "wakeup"
|
|
85
111
|
? new Date(e.dueAt).toISOString()
|
|
86
112
|
: e.kind === "cron"
|
|
87
113
|
? `${e.cron} (next ${new Date(e.nextAt).toISOString()})`
|
|
88
|
-
:
|
|
114
|
+
: `${monitorWhat} (next ${new Date(e.nextAt).toISOString()})`;
|
|
115
|
+
const expiry =
|
|
116
|
+
e.expiresAt != null
|
|
117
|
+
? chalk.dim(` · expires ${new Date(e.expiresAt).toISOString()}`)
|
|
118
|
+
: "";
|
|
119
|
+
const policy = e.runPolicy
|
|
120
|
+
? chalk.dim(` · ${describePolicy(e.runPolicy)}`)
|
|
121
|
+
: "";
|
|
89
122
|
log(
|
|
90
123
|
` ${chalk.cyan(e.kind.padEnd(8))} ${chalk.dim(e.id.slice(0, 8))} ` +
|
|
91
|
-
`${statusBadge(e.status)} ${e.label || truncate(e.prompt || e.command, 40)}`,
|
|
124
|
+
`${statusBadge(e.status)} ${e.label || truncate(e.prompt || e.command || e.watchFile || e.watchUrl, 40)}`,
|
|
92
125
|
);
|
|
93
|
-
log(` ${chalk.dim(when)}`);
|
|
126
|
+
log(` ${chalk.dim(when)}${expiry}${policy}`);
|
|
94
127
|
}
|
|
95
128
|
if (nextAt != null) {
|
|
96
129
|
const rel = Math.max(0, Math.round((nextAt - now) / 1000));
|
|
@@ -120,6 +153,54 @@ export function runAgendaCancel(id, options = {}, _deps = {}) {
|
|
|
120
153
|
return 2;
|
|
121
154
|
}
|
|
122
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Remove finished (terminal) entries so the store does not grow without bound.
|
|
158
|
+
* `--older-than <seconds>` keeps entries that finished more recently.
|
|
159
|
+
*/
|
|
160
|
+
export function runAgendaPrune(options = {}, _deps = {}) {
|
|
161
|
+
const log = _deps.log || ((m) => console.log(m));
|
|
162
|
+
const store = _deps.store || new AgentScheduleStore();
|
|
163
|
+
const now = _deps.now ? _deps.now() : Date.now();
|
|
164
|
+
|
|
165
|
+
let before = Infinity;
|
|
166
|
+
if (options.olderThan != null) {
|
|
167
|
+
const secs = Number(options.olderThan);
|
|
168
|
+
if (!Number.isFinite(secs) || secs < 0) {
|
|
169
|
+
log(chalk.red(`\n ✖ invalid --older-than: ${options.olderThan}\n`));
|
|
170
|
+
return 2;
|
|
171
|
+
}
|
|
172
|
+
before = now - secs * 1000;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const removed = store.pruneTerminal({ before });
|
|
176
|
+
if (options.json) {
|
|
177
|
+
log(
|
|
178
|
+
JSON.stringify(
|
|
179
|
+
{
|
|
180
|
+
pruned: removed.map((e) => ({
|
|
181
|
+
id: e.id,
|
|
182
|
+
kind: e.kind,
|
|
183
|
+
status: e.status,
|
|
184
|
+
})),
|
|
185
|
+
},
|
|
186
|
+
null,
|
|
187
|
+
2,
|
|
188
|
+
),
|
|
189
|
+
);
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
if (removed.length === 0) {
|
|
193
|
+
log(chalk.gray("\n No finished entries to prune.\n"));
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
log(
|
|
197
|
+
chalk.green(
|
|
198
|
+
`\n ✓ Pruned ${removed.length} finished entr${removed.length === 1 ? "y" : "ies"}\n`,
|
|
199
|
+
),
|
|
200
|
+
);
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
123
204
|
/**
|
|
124
205
|
* Fire due entries. Returns 0 unless a monitor command / agent spawn failed in
|
|
125
206
|
* a way worth signalling; JSON summary lists every action taken.
|
|
@@ -129,8 +210,16 @@ export async function runAgendaRun(options = {}, _deps = {}) {
|
|
|
129
210
|
const store = _deps.store || new AgentScheduleStore();
|
|
130
211
|
const spawnAgent = _deps.spawnAgent || defaultSpawnAgent;
|
|
131
212
|
const runCommand = _deps.runCommand || defaultRunCommand;
|
|
213
|
+
const readWatchedFile = _deps.readWatchedFile || defaultReadWatchedFile;
|
|
214
|
+
const fetchUrl = _deps.fetchUrl || defaultFetchUrl;
|
|
132
215
|
const notify = _deps.notify || sendAgentNotification;
|
|
133
|
-
const
|
|
216
|
+
const now = _deps.now ? _deps.now() : Date.now();
|
|
217
|
+
// Retire expired entries BEFORE firing due ones — an expired task never gets
|
|
218
|
+
// a final fire (schedule-planner semantics). Dry-run inspects without mutating.
|
|
219
|
+
const retired = options.dryRun
|
|
220
|
+
? partitionSchedule(store.list(), { now }).expired
|
|
221
|
+
: store.retireExpired(now);
|
|
222
|
+
const due = store.due(null, now);
|
|
134
223
|
const actions = [];
|
|
135
224
|
|
|
136
225
|
for (const entry of due) {
|
|
@@ -140,32 +229,112 @@ export async function runAgendaRun(options = {}, _deps = {}) {
|
|
|
140
229
|
}
|
|
141
230
|
try {
|
|
142
231
|
if (entry.kind === "wakeup") {
|
|
143
|
-
await spawnAgent(entry.prompt);
|
|
232
|
+
await spawnAgent(entry.prompt, entry.runPolicy);
|
|
144
233
|
store.markWakeupFired(entry.id);
|
|
145
234
|
actions.push({ id: entry.id, kind: "wakeup", action: "fired" });
|
|
146
235
|
} else if (entry.kind === "cron") {
|
|
147
|
-
await spawnAgent(entry.prompt);
|
|
236
|
+
await spawnAgent(entry.prompt, entry.runPolicy);
|
|
148
237
|
store.advanceCron(entry.id);
|
|
149
238
|
actions.push({ id: entry.id, kind: "cron", action: "fired" });
|
|
150
239
|
} else if (entry.kind === "monitor") {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
240
|
+
// Three sources: a shell command (match its output), a watched file
|
|
241
|
+
// (match its content, or — with no stopWhen — fire when it appears),
|
|
242
|
+
// or an HTTP endpoint (match its response body, or fire on 2xx).
|
|
243
|
+
let output = "";
|
|
244
|
+
let matched = false;
|
|
245
|
+
let mtimeMs = null;
|
|
246
|
+
if (entry.source === "file") {
|
|
247
|
+
const file = await readWatchedFile(entry.watchFile);
|
|
248
|
+
output = file.content;
|
|
249
|
+
mtimeMs = file.mtimeMs ?? null;
|
|
250
|
+
if (entry.watchChange) {
|
|
251
|
+
// Fire once the file's mtime advances past the baseline recorded on
|
|
252
|
+
// the first check. The first check only establishes the baseline.
|
|
253
|
+
matched =
|
|
254
|
+
entry.lastMtimeMs != null &&
|
|
255
|
+
mtimeMs != null &&
|
|
256
|
+
mtimeMs > entry.lastMtimeMs;
|
|
257
|
+
} else {
|
|
258
|
+
matched = entry.stopWhen
|
|
259
|
+
? new RegExp(entry.stopWhen).test(file.content)
|
|
260
|
+
: file.exists; // no pattern → the file appearing is the signal
|
|
261
|
+
}
|
|
262
|
+
} else if (entry.source === "http") {
|
|
263
|
+
const res = await fetchUrl(entry.watchUrl);
|
|
264
|
+
output = res.body;
|
|
265
|
+
matched = entry.stopWhen
|
|
266
|
+
? new RegExp(entry.stopWhen).test(res.body)
|
|
267
|
+
: res.ok; // no pattern → a 2xx response is the signal
|
|
268
|
+
} else {
|
|
269
|
+
output = await runCommand(entry.command);
|
|
270
|
+
matched = entry.stopWhen
|
|
271
|
+
? new RegExp(entry.stopWhen).test(output)
|
|
272
|
+
: false;
|
|
273
|
+
}
|
|
155
274
|
if (matched) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
275
|
+
const what =
|
|
276
|
+
entry.source === "file"
|
|
277
|
+
? entry.watchFile
|
|
278
|
+
: entry.source === "http"
|
|
279
|
+
? entry.watchUrl
|
|
280
|
+
: entry.command;
|
|
281
|
+
// Stamp the firing with the shared delivery guarantees (monitor-event.js):
|
|
282
|
+
// a deterministic event_id (audit identity, RNG-free) + a SYSTEM
|
|
283
|
+
// authority envelope (steer only — a monitor firing can NEVER answer a
|
|
284
|
+
// permission gate) + a byte-safe payload cap.
|
|
285
|
+
const envelope = monitorEventEnvelope(
|
|
286
|
+
entry.id,
|
|
287
|
+
{ what, output },
|
|
288
|
+
{ at: now, source: entry.source },
|
|
289
|
+
);
|
|
290
|
+
// At-most-once dedup: a persisted lastEventId equal to this event_id
|
|
291
|
+
// means this exact observation already fired (e.g. a resident daemon
|
|
292
|
+
// re-observing the same state) — record but do not re-notify.
|
|
293
|
+
const duplicate =
|
|
294
|
+
entry.lastEventId != null &&
|
|
295
|
+
entry.lastEventId === envelope.event_id;
|
|
296
|
+
// Persist the firing (status→matched + event_id + authority audit)
|
|
297
|
+
// BEFORE the notification side-effect so the record is durable even if
|
|
298
|
+
// the alert delivery fails; delivery itself is best-effort.
|
|
299
|
+
const updated = store.recordMonitorCheck(entry.id, {
|
|
300
|
+
matched: true,
|
|
301
|
+
mtimeMs,
|
|
302
|
+
eventId: envelope.event_id,
|
|
303
|
+
authority: envelope.authority,
|
|
304
|
+
});
|
|
305
|
+
const action = {
|
|
306
|
+
id: entry.id,
|
|
307
|
+
kind: "monitor",
|
|
308
|
+
action: duplicate ? "duplicate" : "matched",
|
|
309
|
+
status: updated?.status,
|
|
310
|
+
event_id: envelope.event_id,
|
|
311
|
+
authority: envelope.authority,
|
|
312
|
+
};
|
|
313
|
+
if (envelope.truncated) action.truncated = true;
|
|
314
|
+
if (!duplicate) {
|
|
315
|
+
try {
|
|
316
|
+
await notify({
|
|
317
|
+
title: entry.notify?.title || `Monitor matched: ${what}`,
|
|
318
|
+
body: capEventPayload(output, 500).value,
|
|
319
|
+
level: "success",
|
|
320
|
+
});
|
|
321
|
+
} catch (notifyErr) {
|
|
322
|
+
action.notifyError = notifyErr.message;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
actions.push(action);
|
|
326
|
+
} else {
|
|
327
|
+
const updated = store.recordMonitorCheck(entry.id, {
|
|
328
|
+
matched: false,
|
|
329
|
+
mtimeMs,
|
|
330
|
+
});
|
|
331
|
+
actions.push({
|
|
332
|
+
id: entry.id,
|
|
333
|
+
kind: "monitor",
|
|
334
|
+
action: "checked",
|
|
335
|
+
status: updated?.status,
|
|
160
336
|
});
|
|
161
337
|
}
|
|
162
|
-
const updated = store.recordMonitorCheck(entry.id, { matched });
|
|
163
|
-
actions.push({
|
|
164
|
-
id: entry.id,
|
|
165
|
-
kind: "monitor",
|
|
166
|
-
action: matched ? "matched" : "checked",
|
|
167
|
-
status: updated?.status,
|
|
168
|
-
});
|
|
169
338
|
}
|
|
170
339
|
} catch (err) {
|
|
171
340
|
actions.push({
|
|
@@ -177,11 +346,25 @@ export async function runAgendaRun(options = {}, _deps = {}) {
|
|
|
177
346
|
}
|
|
178
347
|
}
|
|
179
348
|
|
|
349
|
+
const retiredSummary = retired.map((e) => ({ id: e.id, kind: e.kind }));
|
|
180
350
|
if (options.json) {
|
|
181
|
-
log(
|
|
182
|
-
|
|
351
|
+
log(
|
|
352
|
+
JSON.stringify(
|
|
353
|
+
{ due: due.length, retired: retiredSummary, actions },
|
|
354
|
+
null,
|
|
355
|
+
2,
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
} else if (actions.length === 0 && retired.length === 0) {
|
|
183
359
|
log(chalk.gray(" Nothing due.\n"));
|
|
184
360
|
} else {
|
|
361
|
+
for (const e of retired) {
|
|
362
|
+
log(
|
|
363
|
+
chalk.gray(
|
|
364
|
+
` ${e.kind} ${e.id.slice(0, 8)}: ${options.dryRun ? "would-expire" : "expired"}`,
|
|
365
|
+
),
|
|
366
|
+
);
|
|
367
|
+
}
|
|
185
368
|
for (const a of actions) {
|
|
186
369
|
const colour = a.action === "error" ? chalk.red : chalk.green;
|
|
187
370
|
log(colour(` ${a.kind} ${a.id.slice(0, 8)}: ${a.action}`));
|
|
@@ -192,13 +375,72 @@ export async function runAgendaRun(options = {}, _deps = {}) {
|
|
|
192
375
|
|
|
193
376
|
// ─── default effectful deps (overridable in tests) ─────────────────────────
|
|
194
377
|
|
|
195
|
-
|
|
378
|
+
/**
|
|
379
|
+
* Build the `cc agent` argv for a scheduled prompt, appending the entry's
|
|
380
|
+
* per-task run policy as real `cc agent` flags. A missing / empty policy adds
|
|
381
|
+
* nothing, so an unpolicied task spawns exactly `cc agent -p <prompt>` as
|
|
382
|
+
* before (byte-identical). Exported for unit tests.
|
|
383
|
+
*/
|
|
384
|
+
export function buildAgentArgs(prompt, policy = null) {
|
|
385
|
+
const args = ["agent", "-p", prompt];
|
|
386
|
+
// P1-8: a scheduled run is UNATTENDED — deny high-risk external tools
|
|
387
|
+
// (publish_artifact / notify) by default so no timer-fired agent can publish
|
|
388
|
+
// or message outward on its own. A task opts specific action classes back in
|
|
389
|
+
// via runPolicy.unattendedAllowlist; those tools are then NOT disallowed.
|
|
390
|
+
const disallow = unattendedDisallowedTools({
|
|
391
|
+
attended: false,
|
|
392
|
+
allowlist:
|
|
393
|
+
policy && Array.isArray(policy.unattendedAllowlist)
|
|
394
|
+
? policy.unattendedAllowlist
|
|
395
|
+
: [],
|
|
396
|
+
});
|
|
397
|
+
if (disallow.length > 0) {
|
|
398
|
+
args.push("--disallowed-tools", disallow.join(","));
|
|
399
|
+
}
|
|
400
|
+
if (policy && typeof policy === "object") {
|
|
401
|
+
if (
|
|
402
|
+
typeof policy.permissionMode === "string" &&
|
|
403
|
+
policy.permissionMode.length > 0
|
|
404
|
+
) {
|
|
405
|
+
args.push("--permission-mode", policy.permissionMode);
|
|
406
|
+
}
|
|
407
|
+
if (policy.worktree === true) args.push("--worktree");
|
|
408
|
+
if (Number.isFinite(policy.maxTurns) && policy.maxTurns > 0) {
|
|
409
|
+
args.push("--max-turns", String(policy.maxTurns));
|
|
410
|
+
}
|
|
411
|
+
if (
|
|
412
|
+
typeof policy.goalCondition === "string" &&
|
|
413
|
+
policy.goalCondition.length > 0
|
|
414
|
+
) {
|
|
415
|
+
args.push("--goal-condition", policy.goalCondition);
|
|
416
|
+
if (Number.isFinite(policy.maxOuterTurns) && policy.maxOuterTurns > 0) {
|
|
417
|
+
args.push("--max-outer-turns", String(policy.maxOuterTurns));
|
|
418
|
+
}
|
|
419
|
+
if (Number.isFinite(policy.goalMaxTokens) && policy.goalMaxTokens > 0) {
|
|
420
|
+
args.push("--goal-max-tokens", String(policy.goalMaxTokens));
|
|
421
|
+
}
|
|
422
|
+
if (Number.isFinite(policy.goalMaxCost) && policy.goalMaxCost > 0) {
|
|
423
|
+
args.push("--goal-max-cost", String(policy.goalMaxCost));
|
|
424
|
+
}
|
|
425
|
+
if (Number.isFinite(policy.goalMaxTime) && policy.goalMaxTime > 0) {
|
|
426
|
+
args.push("--goal-max-time", String(policy.goalMaxTime));
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return args;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function defaultSpawnAgent(prompt, policy = null) {
|
|
196
434
|
return new Promise((resolve, reject) => {
|
|
197
|
-
const child = spawn(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
435
|
+
const child = spawn(
|
|
436
|
+
process.execPath,
|
|
437
|
+
[BIN_PATH, ...buildAgentArgs(prompt, policy)],
|
|
438
|
+
{
|
|
439
|
+
stdio: "ignore",
|
|
440
|
+
detached: false,
|
|
441
|
+
env: process.env,
|
|
442
|
+
},
|
|
443
|
+
);
|
|
202
444
|
child.on("error", reject);
|
|
203
445
|
child.on("close", (code) =>
|
|
204
446
|
code === 0 || code == null
|
|
@@ -221,6 +463,40 @@ function defaultRunCommand(command) {
|
|
|
221
463
|
}
|
|
222
464
|
}
|
|
223
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Read a watched file → { exists, content, mtimeMs }. A missing file is not an
|
|
468
|
+
* error. mtimeMs feeds watchChange monitors (fire when the file is modified).
|
|
469
|
+
*/
|
|
470
|
+
function defaultReadWatchedFile(filePath) {
|
|
471
|
+
try {
|
|
472
|
+
const content = readFileSync(filePath, "utf-8");
|
|
473
|
+
let mtimeMs = null;
|
|
474
|
+
try {
|
|
475
|
+
mtimeMs = statSync(filePath).mtimeMs;
|
|
476
|
+
} catch {
|
|
477
|
+
/* content read but stat failed — treat mtime as unknown */
|
|
478
|
+
}
|
|
479
|
+
return { exists: true, content, mtimeMs };
|
|
480
|
+
} catch {
|
|
481
|
+
return { exists: false, content: "", mtimeMs: null };
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* GET a watched URL → { ok, status, body }. Any failure (network, timeout,
|
|
487
|
+
* non-2xx) is not an error here — it just yields ok:false so the monitor
|
|
488
|
+
* re-arms and tries again next interval.
|
|
489
|
+
*/
|
|
490
|
+
async function defaultFetchUrl(url) {
|
|
491
|
+
try {
|
|
492
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(30000) });
|
|
493
|
+
const body = await res.text();
|
|
494
|
+
return { ok: res.ok, status: res.status, body };
|
|
495
|
+
} catch {
|
|
496
|
+
return { ok: false, status: 0, body: "" };
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
224
500
|
function statusBadge(status) {
|
|
225
501
|
switch (status) {
|
|
226
502
|
case "pending":
|
|
@@ -231,6 +507,8 @@ function statusBadge(status) {
|
|
|
231
507
|
return chalk.cyan(status);
|
|
232
508
|
case "exhausted":
|
|
233
509
|
return chalk.yellow(status);
|
|
510
|
+
case "expired":
|
|
511
|
+
return chalk.gray(status);
|
|
234
512
|
default:
|
|
235
513
|
return status;
|
|
236
514
|
}
|
|
@@ -240,3 +518,13 @@ function truncate(text, n) {
|
|
|
240
518
|
const s = String(text || "");
|
|
241
519
|
return s.length > n ? s.slice(0, n) + "…" : s;
|
|
242
520
|
}
|
|
521
|
+
|
|
522
|
+
/** Compact human summary of a scheduled entry's per-task run policy. */
|
|
523
|
+
function describePolicy(policy) {
|
|
524
|
+
const parts = [];
|
|
525
|
+
if (policy.permissionMode) parts.push(policy.permissionMode);
|
|
526
|
+
if (policy.worktree === true) parts.push("worktree");
|
|
527
|
+
if (Number.isFinite(policy.maxTurns)) parts.push(`≤${policy.maxTurns} turns`);
|
|
528
|
+
if (policy.goalCondition) parts.push(`goal: ${policy.goalCondition}`);
|
|
529
|
+
return parts.join(", ");
|
|
530
|
+
}
|
package/src/commands/agent.js
CHANGED
|
@@ -204,6 +204,10 @@ export function registerAgentCommand(program) {
|
|
|
204
204
|
"--otlp <file>",
|
|
205
205
|
"Write the agent run's OpenTelemetry spans (model/tool/retry) as OTLP/JSON to <file>",
|
|
206
206
|
)
|
|
207
|
+
.option(
|
|
208
|
+
"--otlp-content",
|
|
209
|
+
"Include prompt/response CONTENT in --otlp spans (off by default; content is redacted unless this is set)",
|
|
210
|
+
)
|
|
207
211
|
.option(
|
|
208
212
|
"--auto-rewake",
|
|
209
213
|
"When an async `asyncRewake` hook (e.g. a background test) fails at turn end, re-engage the agent to fix it (bounded by --max-rewakes)",
|
|
@@ -311,6 +315,30 @@ export function registerAgentCommand(program) {
|
|
|
311
315
|
"--goal-assess",
|
|
312
316
|
"After the run, ask the model to assess goal progress and persist it (opt-in; costs one extra completion; requires --goal)",
|
|
313
317
|
)
|
|
318
|
+
.option(
|
|
319
|
+
"--goal-condition <spec>",
|
|
320
|
+
"Session completion condition; re-drives outer turns until met. Prefix exit-zero:/file-exists:/contains:/regex: (deterministic) or model:<desc> (model-judged)",
|
|
321
|
+
)
|
|
322
|
+
.option(
|
|
323
|
+
"--max-outer-turns <n>",
|
|
324
|
+
"Max outer re-drive turns for --goal-condition (default 10, hard cap 100)",
|
|
325
|
+
(v) => parseInt(v, 10),
|
|
326
|
+
)
|
|
327
|
+
.option(
|
|
328
|
+
"--goal-max-tokens <n>",
|
|
329
|
+
"Token budget across --goal-condition outer turns",
|
|
330
|
+
(v) => parseInt(v, 10),
|
|
331
|
+
)
|
|
332
|
+
.option(
|
|
333
|
+
"--goal-max-cost <usd>",
|
|
334
|
+
"Cost budget (USD) across --goal-condition outer turns",
|
|
335
|
+
(v) => parseFloat(v),
|
|
336
|
+
)
|
|
337
|
+
.option(
|
|
338
|
+
"--goal-max-time <ms>",
|
|
339
|
+
"Wall-clock budget (ms) across --goal-condition outer turns",
|
|
340
|
+
(v) => parseInt(v, 10),
|
|
341
|
+
)
|
|
314
342
|
.option(
|
|
315
343
|
"--mcp-config <file>",
|
|
316
344
|
"Load ad-hoc MCP servers from a JSON file for this run (headless); their tools become callable (mcp__<server>__<tool>)",
|
|
@@ -871,6 +899,11 @@ export function registerAgentCommand(program) {
|
|
|
871
899
|
maxCostUsd,
|
|
872
900
|
priceTable,
|
|
873
901
|
chatFn: fallbackChatFn,
|
|
902
|
+
// --json-schema: structured output for stream-INPUT mode. The schema
|
|
903
|
+
// is resolved + meta-validated up front, its output contract injected
|
|
904
|
+
// into the system prompt, and a per-turn `structured_result` event is
|
|
905
|
+
// appended after each turn (parity with single-prompt --json-schema).
|
|
906
|
+
jsonSchema: options.jsonSchema || null,
|
|
874
907
|
});
|
|
875
908
|
} catch (err) {
|
|
876
909
|
process.stderr.write(`Error: ${err.message}\n`);
|
|
@@ -1001,6 +1034,19 @@ export function registerAgentCommand(program) {
|
|
|
1001
1034
|
}
|
|
1002
1035
|
const { runAgentHeadless, parseToolList } =
|
|
1003
1036
|
await import("../runtime/headless-runner.js");
|
|
1037
|
+
// --goal-condition: validate the spec up front so a bad prefix fails
|
|
1038
|
+
// fast (before any model call) with a clear message.
|
|
1039
|
+
if (options.goalCondition) {
|
|
1040
|
+
try {
|
|
1041
|
+
const { parseGoalCondition } =
|
|
1042
|
+
await import("../lib/goal-condition-engine.js");
|
|
1043
|
+
parseGoalCondition(options.goalCondition);
|
|
1044
|
+
} catch (e) {
|
|
1045
|
+
process.stderr.write(`--goal-condition: ${e.message}\n`);
|
|
1046
|
+
await _finishWorktree();
|
|
1047
|
+
process.exit(1);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1004
1050
|
const maxTurns = options.maxTurns
|
|
1005
1051
|
? parseInt(options.maxTurns, 10)
|
|
1006
1052
|
: undefined;
|
|
@@ -1027,6 +1073,9 @@ export function registerAgentCommand(program) {
|
|
|
1027
1073
|
autoCheckpoint,
|
|
1028
1074
|
// --otlp <file>: capture + export the run's OTel spans as OTLP/JSON.
|
|
1029
1075
|
otlp: options.otlp || null,
|
|
1076
|
+
// --otlp-content: opt in to emitting prompt/response CONTENT in those
|
|
1077
|
+
// spans. Default false → content stays redacted (privacy by default).
|
|
1078
|
+
otlpContent: options.otlpContent === true,
|
|
1030
1079
|
// --auto-rewake / --max-rewakes: bounded re-drive on async-hook failure.
|
|
1031
1080
|
// --max-rewakes implies --auto-rewake (a positive budget turns it on).
|
|
1032
1081
|
autoRewake:
|
|
@@ -1052,6 +1101,21 @@ export function registerAgentCommand(program) {
|
|
|
1052
1101
|
goal: options.goal,
|
|
1053
1102
|
// --goal-assess: run-end LLM progress assessment (Phase 2)
|
|
1054
1103
|
goalAssess: options.goalAssess === true,
|
|
1104
|
+
// --goal-condition: session-level completion-condition engine — drives
|
|
1105
|
+
// outer turns until the condition is met or a budget is exhausted.
|
|
1106
|
+
goalCondition: options.goalCondition || null,
|
|
1107
|
+
maxOuterTurns: Number.isFinite(options.maxOuterTurns)
|
|
1108
|
+
? options.maxOuterTurns
|
|
1109
|
+
: undefined,
|
|
1110
|
+
goalMaxTokens: Number.isFinite(options.goalMaxTokens)
|
|
1111
|
+
? options.goalMaxTokens
|
|
1112
|
+
: undefined,
|
|
1113
|
+
goalMaxCostUsd: Number.isFinite(options.goalMaxCost)
|
|
1114
|
+
? options.goalMaxCost
|
|
1115
|
+
: undefined,
|
|
1116
|
+
goalMaxTimeMs: Number.isFinite(options.goalMaxTime)
|
|
1117
|
+
? options.goalMaxTime
|
|
1118
|
+
: undefined,
|
|
1055
1119
|
// --mcp-config: connect ad-hoc MCP servers + expose their tools
|
|
1056
1120
|
mcpConfig: options.mcpConfig || null,
|
|
1057
1121
|
// --no-mcp: skip registered (cc mcp add) auto-connect servers
|
|
@@ -1081,21 +1145,51 @@ export function registerAgentCommand(program) {
|
|
|
1081
1145
|
chatFn: fallbackChatFn,
|
|
1082
1146
|
};
|
|
1083
1147
|
|
|
1084
|
-
// --json-schema: structured output
|
|
1085
|
-
//
|
|
1086
|
-
//
|
|
1087
|
-
//
|
|
1148
|
+
// --json-schema: structured output. Accepts a file path OR inline JSON.
|
|
1149
|
+
// - text/json output: wrap the runner with capture + validate + retry
|
|
1150
|
+
// (json-schema-output.js); prints only the validated JSON.
|
|
1151
|
+
// - stream-json output: stream events normally, then emit a terminal
|
|
1152
|
+
// `structured_result` event (schema_digest + valid + value/errors) as
|
|
1153
|
+
// the last NDJSON line, so the two protocols are now compatible.
|
|
1088
1154
|
if (options.jsonSchema) {
|
|
1155
|
+
const jso = await import("../lib/json-schema-output.js");
|
|
1089
1156
|
if (options.outputFormat === "stream-json") {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1157
|
+
try {
|
|
1158
|
+
const schema = jso.loadSchemaFile(
|
|
1159
|
+
jso._deps.fs,
|
|
1160
|
+
options.jsonSchema,
|
|
1161
|
+
);
|
|
1162
|
+
const instruction = jso.buildSchemaInstruction(schema);
|
|
1163
|
+
const outcome = await runAgentHeadless({
|
|
1164
|
+
...headlessOptions,
|
|
1165
|
+
appendSystemPrompt: [
|
|
1166
|
+
headlessOptions.appendSystemPrompt,
|
|
1167
|
+
instruction,
|
|
1168
|
+
]
|
|
1169
|
+
.filter(Boolean)
|
|
1170
|
+
.join("\n\n"),
|
|
1171
|
+
});
|
|
1172
|
+
// The normal stream (init … result) has already been written to
|
|
1173
|
+
// stdout by the runner. Append the structured verdict as the final
|
|
1174
|
+
// NDJSON line, built from the run's final text.
|
|
1175
|
+
const parsed = jso.extractJsonPayload(
|
|
1176
|
+
String(outcome?.result ?? ""),
|
|
1177
|
+
);
|
|
1178
|
+
const evt = jso.buildStructuredResult(
|
|
1179
|
+
schema,
|
|
1180
|
+
parsed.ok ? parsed.value : null,
|
|
1181
|
+
);
|
|
1182
|
+
process.stdout.write(JSON.stringify(evt) + "\n");
|
|
1183
|
+
await _finishWorktree();
|
|
1184
|
+
process.exit(evt.valid ? 0 : 1);
|
|
1185
|
+
} catch (err) {
|
|
1186
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
1187
|
+
await _finishWorktree();
|
|
1188
|
+
process.exit(1);
|
|
1189
|
+
}
|
|
1094
1190
|
}
|
|
1095
1191
|
try {
|
|
1096
|
-
const
|
|
1097
|
-
await import("../lib/json-schema-output.js");
|
|
1098
|
-
const code = await runJsonSchemaConstrained({
|
|
1192
|
+
const code = await jso.runJsonSchemaConstrained({
|
|
1099
1193
|
schemaFile: options.jsonSchema,
|
|
1100
1194
|
baseOptions: headlessOptions,
|
|
1101
1195
|
runHeadless: runAgentHeadless,
|