chainlesschain 0.162.167 → 0.162.169
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 +1 -1
- package/src/assets/web-panel/assets/{AIOps-BZJrchIA.js → AIOps-DCeNRK8z.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Bhlrylt7.js → ActionButton-ZfD0HgVe.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-pHtXVQYs.js → Analytics-Ccn40f9E.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-ORpuri4R.js → AppLayout-DyXs4nSt.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-eC77yr1_.js → Artifacts-CYjMh5KR.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B2dZIiqz.js → Audit-DZIhvx88.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-COZiTiwP.js → BackgroundAgents-C1XJsa2d.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-vY_Srl5d.js → Backup-CMXC0oUN.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Dili5BdM.js → BaseInput-CRVmIH1t.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-EzKBf0XL.js → Chat-acBud5Yj.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-D1CtRAyy.js → ChatBubbleRenderer-CTjqFhdD.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Beh6BmuW.js → Checkbox-CZem825o.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-C3fA6kBU.js → Codegen-B9UjZsww.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CefMqONH.js → Col-Dtu6Frtj.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CBAxFJtB.js → Community-9bV55Huv.js} +1 -1
- package/src/assets/web-panel/assets/{Compact--flHc-sM.js → Compact-g-kQ4c84.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CPeNLvA6.js → Compliance-CQjHzBO1.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bv5yv4BU.js → Cowork-D1Qm_Xhi.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-C22yMEas.js → Cron-992qo8zX.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dsb2bcpu.js → Crosschain-4TiqEwuc.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DAxei4w0.js → DID-BbsXzXCb.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DEUwuVZ8.js → Dashboard-Dx5aO9d3.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BVp4si2j.js → Dropdown-BhzW6i6i.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CyFkybOG.js → EmailListRenderer-qEib4yiq.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BWmmsbVx.js → FamilyGuardDashboard-BZ3N-u3h.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Cxw27A5d.js → Federation-CcOqwzHY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Q9XthzL1.js → FormItemContext-dbi8mohd.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DS5DIdsW.js → GenericCardRenderer-57dqulUe.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BOliHfxP.js → Git-DtSV7C5g.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CD4oxa-W.js → Governance-CLnmH-RD.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CMlcivo8.js → Inference-wXiLeDnk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BwhERcC4.js → KnowledgeGraph-NGdIX2Gx.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BjVcZR5P.js → Logs-Dz0HQn69.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-CSRZ9da3.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DQLU3E2w.js → Marketplace-DpPDmY3W.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CeK0XkpB.js → McpTools-UMysoRQm.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DLFkgwaz.js → Memory-DsnBpQnY.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bh6ymXyj.js → MobileBridge-DweooAfG.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-D950tUIe.js → MobileProjects-UdLfZOVA.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Bx5x9_2m.js → Mtc-oXWhJNgC.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-a1-Fexsq.js → MtcAudit-CXTD7qrm.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-eaw0X8X1.js → Multisig-BKt5mJ9O.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BaNsPV4k.js → NLProgramming-C-zcYzje.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C7pevN2X.js → Notes-CGaZ_jep.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-HDqeoP0r.js → NotificationSettings-BwX-tDbq.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DvzVl5T3.js → OrderTableRenderer-Cc9Se8H-.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-D_xHDlGW.js → Organization-8BXdC7Im.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B5sRnueL.js → Overflow-zCisFuGU.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-C-IRjOPW.js → P2P-BehHH9Ro.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DVuXYKAR.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-Bm_T1uWw.js → Permissions-BVDATm3p.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-DujDllye.js → PersonalDataHub-C43nnYoi.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DyNPOLIG.js → Pipeline-D9E7aSVD.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CYKTW3iK.js → Privacy-CRbIchdL.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CGf03uZ0.js → ProjectInit-CTsy8lhL.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DIec4bTI.js → ProjectSettings-CPEKWWJ5.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BY43-bmi.js → Projects-CNnW0v5N.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-RrnUmgPk.js → Providers-BeZnDL9Y.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BBWfqd4y.js → QrScannerModal-CaydwuIU.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BsICSrFp.js → QuickAsk-qYWbu7kw.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-B8y0b4ys.js → Recommend-RV_ogHrM.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-0QgdB1Oe.js → RemoteSession-Mah1i41_.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DBJGM0YO.js → Reputation-xZQhGktc.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DtWQ5otv.js → Row-B6cVbPbJ.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-2zBxHd5H.js → RssFeed-C6hKjDPz.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BofliSkZ.js → Search-0jti_-Pe.js} +1 -1
- package/src/assets/web-panel/assets/{Security-ockRBBEL.js → Security-Cy48feGz.js} +3 -3
- package/src/assets/web-panel/assets/{Services-QyvG7Vd0.js → Services-BW3ObFxH.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DwbOndX3.js → Skeleton-CfrZRvAM.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-cHWa63sZ.js → Skills-yoccdk3t.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BHnTEydQ.js → Sla-AKBBdri6.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DE2hrrLb.js → SpeechSettings-DH87GbkH.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CZ9vnbJH.js → SyncSettings-DUuO-ZSw.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-ZTUfOzMZ.js +1 -0
- package/src/assets/web-panel/assets/{Templates-DiR3ad4X.js → Templates-shPrQ4NE.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-NqcW3frV.js → Tenant-C_inPunR.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-iYeqRQZ0.js → Terminal-CvVtx6ie.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C5GOoxFz.js → TimelineRenderer-Bzp_T3Xc.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-82dz0XdU.js → Tokens-kUFRLdtp.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B3JCNrOi.js → Trigger-BsTU2blQ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BehFYsN_.js → Trust-DEKkuAsi.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BfOxJjVf.js → UkeySign-D1KEEgbK.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DdITCCPz.js → VideoEditing-C2yYkm9W.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B0EhkCmD.js → Wallet-BKKod4qb.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DJ4i1f3-.js → WebAuthn-XXUgED6d.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-Dr9XTqIT.js → WorkflowEditor-DnlEyYTi.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Dc2nFyOj.js → chat-BaVjI6nu.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Drw9djBR.js → colors-DQ0yx43H.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BdLXbU52.js → compact-item-DEyWDp0v.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BpQMZiWY.js → createContext-SuPOfylZ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-C_RK48j-.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CbYwawHf.js → hasIn-CQz1JNtC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO7LD_1t.js → index-3xcB2i6I.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bo_KwJTF.js → index-57GdL9ro.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJQiSQw7.js → index-BHJhyrFr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTeqWdAS.js → index-BIgWgye3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSmZjrFy.js → index-BJEIjYhV.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7Ipfs4F.js → index-BffmUosH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9_u4Qhe.js → index-ByGF9ev7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyU21xVi.js → index-C-IKjQD3.js} +1 -1
- package/src/assets/web-panel/assets/{index-GG_MXjSL.js → index-C2k8eHyq.js} +3 -3
- package/src/assets/web-panel/assets/{index-Blv7c80V.js → index-C3Vlo45C.js} +1 -1
- package/src/assets/web-panel/assets/index-CDqhisfz.js +1 -0
- package/src/assets/web-panel/assets/{index-C1eo1Qkd.js → index-CEfLMvKf.js} +1 -1
- package/src/assets/web-panel/assets/{index-COoIIMbO.js → index-CGu-b0RE.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu8Vy-mj.js → index-CI5jlfyn.js} +1 -1
- package/src/assets/web-panel/assets/index-CKUoX6Yi.js +1 -0
- package/src/assets/web-panel/assets/{index-BmQlot_u.js → index-COsmMpAO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWUN8c01.js → index-CZrARoXd.js} +1 -1
- package/src/assets/web-panel/assets/{index-IG3__pGj.js → index-C_fcNCoV.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1ANzVc6.js → index-CfVW-cd_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAq-4KqY.js → index-CgvnudM_.js} +1 -1
- package/src/assets/web-panel/assets/{index-aHrUfrv1.js → index-CnhJU5To.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_lkTnZ0.js → index-CpR6M7eQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWUoc9-s.js → index-D-gXgEsU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZxzdAI0.js → index-D5SY6Lwu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiGDrEt4.js → index-DB8AJ6T-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHMeEu-P.js → index-DNYVGZzG.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3Alz2QD.js → index-DWIuZ9bI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKQlF7Pw.js → index-DXczrVij.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKmz3Is-.js → index-Dfh6OJKz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIcEW07n.js → index-DhBeUGCp.js} +1 -1
- package/src/assets/web-panel/assets/{index-UX_Mfyfv.js → index-DjZ6szGM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBwQwtsE.js → index-DpPv8zeU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpmlTfpv.js → index-XjQfQBXH.js} +1 -1
- package/src/assets/web-panel/assets/{index-_vVucYqC.js → index-ZKOZ-YFJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-XYe6kBmi.js → index-ZMgCYtI7.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5KboakZ.js → index-fGgx2f1y.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3uRI8_y.js → index-fcA6tfBA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBueKSTR.js → index-v8PYYw05.js} +1 -1
- package/src/assets/web-panel/assets/{index-VIyNlXPX.js → index-wBsuJZcz.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DybC85E4.js → initDefaultProps-KetDXPXx.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BNNuyDg7.js → motion-BfAtwo2m.js} +1 -1
- package/src/assets/web-panel/assets/{move-Bm8gSjEN.js → move-BnJvzHgx.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CuHQvzzr.js → mtc-parser-DZxDclhM.js} +1 -1
- package/src/assets/web-panel/assets/{omit-lv4NO7Ng.js → omit-CmqfX2P_.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BoSMfjHq.js → pickAttrs-B2B2ahzC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BOMDSvgz.js → placementArrow-C1SIgWRj.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C064Ubmu.js → responsiveObserve-Dy_adDTl.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CeqhbKoG.js → slide-hDO9sBPk.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CunFoYww.js → statusUtils-DlpTjRpg.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Cxz3wPL7.js → styleChecker-DAv9eo6h.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DJsIaU2S.js → useFlexGapSupport-vfoXaeH8.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DnAygceJ.js → useFs-Dzji-S7v.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CrEUY7ta.js → usePersonalDataHub-jKcLN_Gj.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cq3rN2eT.js → vnode-DAWM5GgY.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-TMzcOx__.js → zoom-q3XgSOUd.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/plugin.js +49 -5
- package/src/data/changelog.json +18 -4
- package/src/harness/worktree-isolator.js +10 -2
- package/src/lib/agent-core.js +1 -0
- package/src/lib/background-agent-phase.js +22 -0
- package/src/lib/background-phase-reporter.js +153 -0
- package/src/lib/hook-runner.cjs +248 -36
- package/src/lib/install-command-policy.js +40 -1
- package/src/lib/lsp/code-intelligence.js +5 -1
- package/src/lib/lsp/workspace-roots.js +115 -0
- package/src/lib/session-lifecycle.js +3 -0
- package/src/lib/settings-hook-events.cjs +16 -3
- package/src/lib/sub-agent-context.js +13 -0
- package/src/runtime/agent-core.js +442 -89
- package/src/runtime/headless-runner.js +75 -8
- package/src/runtime/headless-stream.js +175 -2
- package/src/workers/background-agent-worker.js +22 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BfRhXdyG.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-BqgUPlcU.js +0 -7
- package/src/assets/web-panel/assets/Tasks-DWgoAHvM.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CnfpDzMr.js +0 -1
- package/src/assets/web-panel/assets/index-CYTEB0tb.js +0 -1
- package/src/assets/web-panel/assets/index-CgsEp5bm.js +0 -1
|
@@ -75,6 +75,7 @@ import {
|
|
|
75
75
|
exitCodeForEndReason,
|
|
76
76
|
} from "../lib/exit-codes.cjs";
|
|
77
77
|
import { isolationLevel } from "../lib/agent-sandbox.js";
|
|
78
|
+
import { createBackgroundPhaseReporter } from "../lib/background-phase-reporter.js";
|
|
78
79
|
import { withQuietStdout } from "./quiet-stdout.js";
|
|
79
80
|
import { CostBudget } from "../lib/cost-budget.js";
|
|
80
81
|
import {
|
|
@@ -702,6 +703,15 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
702
703
|
// mid-flight does NOT blindly replay an effect that may already have landed.
|
|
703
704
|
// Only active when persisting (an ephemeral/one-shot run can't be resumed);
|
|
704
705
|
// the byte-for-byte default path is untouched when no dangerous tool runs.
|
|
706
|
+
// Background phase reporter (P0 state-machine producer): when this run IS a
|
|
707
|
+
// background agent's turn child (CC_BACKGROUND_AGENT_ID set by the worker),
|
|
708
|
+
// human-blocking windows are surfaced into the shared state file. Created
|
|
709
|
+
// here — before the resume reconcile below — so an UNKNOWN-outcome side
|
|
710
|
+
// effect found on resume can be reported too. For every non-background run
|
|
711
|
+
// this is a disabled no-op.
|
|
712
|
+
const _bgPhase =
|
|
713
|
+
deps.backgroundPhaseReporter || createBackgroundPhaseReporter();
|
|
714
|
+
|
|
705
715
|
const sideEffectRunNonce = String(deps.now ? deps.now() : Date.now());
|
|
706
716
|
let sideEffectLedger = new SideEffectLedger({ clock: deps.now || null });
|
|
707
717
|
let sideEffectSeq = 0;
|
|
@@ -764,6 +774,11 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
764
774
|
writeErr(
|
|
765
775
|
`⚠ ${plan.inspect.length} interrupted side-effect(s) need verification before replay (resume ${resumeId}).\n`,
|
|
766
776
|
);
|
|
777
|
+
// P0 state machine: a background child resuming with UNKNOWN-outcome
|
|
778
|
+
// ops advertises `uncertain_side_effect` (dashboard: Needs input) —
|
|
779
|
+
// someone must confirm before any replay. No-op unless this run is a
|
|
780
|
+
// background turn child; best-effort by construction.
|
|
781
|
+
_bgPhase.reportUncertainSideEffects(plan.inspect.length);
|
|
767
782
|
}
|
|
768
783
|
} catch {
|
|
769
784
|
resumeSideEffectContext = null;
|
|
@@ -1108,6 +1123,25 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1108
1123
|
}
|
|
1109
1124
|
}
|
|
1110
1125
|
|
|
1126
|
+
// Seed MCP roots for --add-dir (Claude-Code roots/list_changed parity): a
|
|
1127
|
+
// headless session started with extra workspace roots must advertise the FULL
|
|
1128
|
+
// root list to connected MCP servers, exactly like the REPL /add-dir path —
|
|
1129
|
+
// otherwise a server's roots/list only ever sees the cwd. Only meaningful when
|
|
1130
|
+
// extra roots exist (setRoots fires only when the list actually changes); no
|
|
1131
|
+
// --add-dir → workspaceRootDirs = [cwd] and this is a no-op. Best-effort.
|
|
1132
|
+
if (mcp?.mcpClient && additionalDirectories.length > 0) {
|
|
1133
|
+
try {
|
|
1134
|
+
const { notifyMcpRootsChanged, workspaceRootDirs } =
|
|
1135
|
+
await import("../repl/add-dir.js");
|
|
1136
|
+
notifyMcpRootsChanged(
|
|
1137
|
+
[mcp.mcpClient],
|
|
1138
|
+
workspaceRootDirs(options.cwd || process.cwd(), additionalDirectories),
|
|
1139
|
+
);
|
|
1140
|
+
} catch {
|
|
1141
|
+
// best-effort — root advertisement never blocks a run
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1111
1145
|
// IDE live context (Claude-Code parity): when an IDE bridge is connected,
|
|
1112
1146
|
// share the editor's selection/active file/open tabs with this turn. Appended
|
|
1113
1147
|
// to the in-flight user message only — AFTER persistence — so a resumed
|
|
@@ -1136,6 +1170,10 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1136
1170
|
// IDE context is optional polish — never fail the run over it.
|
|
1137
1171
|
}
|
|
1138
1172
|
|
|
1173
|
+
// (`_bgPhase` — the background phase reporter — is created before the resume
|
|
1174
|
+
// reconcile block above; the confirmers below reuse it to surface their
|
|
1175
|
+
// pending window as `phase: "waiting_permission"` + `pendingApprovals`.)
|
|
1176
|
+
|
|
1139
1177
|
// --permission-prompt-tool: route every CONFIRM-tier approval to an MCP tool
|
|
1140
1178
|
// (loaded via --mcp-config) instead of headless fail-closed. Overrides the
|
|
1141
1179
|
// permission-mode confirmer on the gate for this session.
|
|
@@ -1156,13 +1194,15 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1156
1194
|
}
|
|
1157
1195
|
if (approvalGate && typeof approvalGate.setConfirmer === "function") {
|
|
1158
1196
|
approvalGate.setConfirmer(
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1197
|
+
_bgPhase.wrapConfirmer(
|
|
1198
|
+
makePermissionPromptConfirmer({
|
|
1199
|
+
mcpClient: mcp.mcpClient,
|
|
1200
|
+
server: ppt.server,
|
|
1201
|
+
tool: ppt.tool,
|
|
1202
|
+
writeErr,
|
|
1203
|
+
isText,
|
|
1204
|
+
}),
|
|
1205
|
+
),
|
|
1166
1206
|
);
|
|
1167
1207
|
}
|
|
1168
1208
|
}
|
|
@@ -1186,7 +1226,9 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1186
1226
|
isText,
|
|
1187
1227
|
});
|
|
1188
1228
|
if (approvalGate && typeof approvalGate.setConfirmer === "function") {
|
|
1189
|
-
approvalGate.setConfirmer(
|
|
1229
|
+
approvalGate.setConfirmer(
|
|
1230
|
+
_bgPhase.wrapConfirmer(_remoteApproval.confirmer),
|
|
1231
|
+
);
|
|
1190
1232
|
}
|
|
1191
1233
|
} catch (err) {
|
|
1192
1234
|
// Remote approval could not come up → keep headless fail-closed rather
|
|
@@ -1294,6 +1336,31 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1294
1336
|
enabledToolNames,
|
|
1295
1337
|
disabledTools,
|
|
1296
1338
|
iterationBudget: budget,
|
|
1339
|
+
// `ask_user_question` in a BACKGROUND turn child (P0 state-machine
|
|
1340
|
+
// producer for `needs_input`): there is no live channel to a human
|
|
1341
|
+
// mid-turn, but the question IS the structured needs-input signal. Park
|
|
1342
|
+
// it — record `phase: "needs_input"` + the question in the shared state
|
|
1343
|
+
// file (dashboard "Needs input" gets real data; the user's reply arrives
|
|
1344
|
+
// as the next attach prompt) and tell the model to end the turn. A
|
|
1345
|
+
// non-background run supplies no interaction → the handler's existing
|
|
1346
|
+
// `user_not_reachable` path stays byte-identical.
|
|
1347
|
+
...(_bgPhase.enabled
|
|
1348
|
+
? {
|
|
1349
|
+
interaction: {
|
|
1350
|
+
askUser: async ({ question, options: qOptions } = {}) => {
|
|
1351
|
+
_bgPhase.reportQuestion({
|
|
1352
|
+
question: typeof question === "string" ? question : "",
|
|
1353
|
+
options: Array.isArray(qOptions) ? qOptions : null,
|
|
1354
|
+
});
|
|
1355
|
+
throw new Error(
|
|
1356
|
+
"question parked for the user (background session). End this " +
|
|
1357
|
+
"turn now — the user's reply will arrive as the next " +
|
|
1358
|
+
"message. Do not repeat the question.",
|
|
1359
|
+
);
|
|
1360
|
+
},
|
|
1361
|
+
},
|
|
1362
|
+
}
|
|
1363
|
+
: {}),
|
|
1297
1364
|
// --mcp-config wiring: tool defs for the LLM + dispatch map + live client.
|
|
1298
1365
|
mcpClient: mcp?.mcpClient || null,
|
|
1299
1366
|
extraToolDefinitions: mcp?.extraToolDefinitions || undefined,
|
|
@@ -75,6 +75,15 @@ import {
|
|
|
75
75
|
rebuildMessages as jsonlRebuildMessages,
|
|
76
76
|
sessionExists as jsonlSessionExists,
|
|
77
77
|
} from "../harness/jsonl-session-store.js";
|
|
78
|
+
import {
|
|
79
|
+
reconcileSideEffects,
|
|
80
|
+
classifyToolSideEffect,
|
|
81
|
+
} from "../lib/side-effect-ledger.js";
|
|
82
|
+
import {
|
|
83
|
+
loadSideEffectLedger,
|
|
84
|
+
persistSideEffectLedger,
|
|
85
|
+
} from "../lib/side-effect-ledger-store.js";
|
|
86
|
+
import { operationIdempotencyKey } from "../lib/idempotency.js";
|
|
78
87
|
import { getPlanModeManager } from "../lib/plan-mode.js";
|
|
79
88
|
|
|
80
89
|
/**
|
|
@@ -527,6 +536,46 @@ export async function* readJsonLines(input, opts = {}) {
|
|
|
527
536
|
if (!overflow && buf.trim()) yield buf;
|
|
528
537
|
}
|
|
529
538
|
|
|
539
|
+
/**
|
|
540
|
+
* P0-2: on a stream resume, surface any irreversible tool that was in flight
|
|
541
|
+
* when the prior run died. Same reconcile + wording as the single-prompt
|
|
542
|
+
* runner (headless-runner.js) and the WS bridge (session-protocol.js): a
|
|
543
|
+
* `started`-but-unsettled op's outcome is UNKNOWN, so the model must VERIFY
|
|
544
|
+
* before any replay rather than silently re-issue the effect. Returns
|
|
545
|
+
* {count, items, notice} or null when nothing needs verification — a clean
|
|
546
|
+
* (or absent) ledger keeps the resume byte-identical to today.
|
|
547
|
+
*/
|
|
548
|
+
function buildSideEffectRecovery(ledger) {
|
|
549
|
+
try {
|
|
550
|
+
const plan = reconcileSideEffects(ledger);
|
|
551
|
+
if (!plan.inspect.length) return null;
|
|
552
|
+
const items = plan.plans
|
|
553
|
+
.filter((p) => p.action === "inspect")
|
|
554
|
+
.map((p) => {
|
|
555
|
+
const op = ledger.get(p.opId) || {};
|
|
556
|
+
return {
|
|
557
|
+
kind: op.kind || "unknown",
|
|
558
|
+
key: op.key || null,
|
|
559
|
+
reason: p.reason,
|
|
560
|
+
};
|
|
561
|
+
});
|
|
562
|
+
const notice =
|
|
563
|
+
"Recovery notice — the previous run was interrupted while these " +
|
|
564
|
+
"irreversible operations were in flight; their outcome is UNKNOWN. Do " +
|
|
565
|
+
"NOT blindly re-run them. Verify whether each already took effect before " +
|
|
566
|
+
"repeating it, and ask the user if unsure:\n" +
|
|
567
|
+
items
|
|
568
|
+
.map(
|
|
569
|
+
(it) =>
|
|
570
|
+
` • [${it.kind}]${it.key ? ` (${it.key})` : ""} — ${it.reason}`,
|
|
571
|
+
)
|
|
572
|
+
.join("\n");
|
|
573
|
+
return { count: items.length, items, notice };
|
|
574
|
+
} catch {
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
530
579
|
/**
|
|
531
580
|
* Run a single turn through the core agent loop, emitting NDJSON events.
|
|
532
581
|
* Returns the turn outcome so the caller can grow history + the result line.
|
|
@@ -534,7 +583,7 @@ export async function* readJsonLines(input, opts = {}) {
|
|
|
534
583
|
async function runTurn(
|
|
535
584
|
messages,
|
|
536
585
|
loopOptions,
|
|
537
|
-
{ runLoop, emit, costBudget, nextToolUseId },
|
|
586
|
+
{ runLoop, emit, costBudget, nextToolUseId, sideEffects },
|
|
538
587
|
) {
|
|
539
588
|
const usage = {
|
|
540
589
|
input_tokens: 0,
|
|
@@ -546,6 +595,10 @@ async function runTurn(
|
|
|
546
595
|
let finalText = "";
|
|
547
596
|
let endReason = "complete";
|
|
548
597
|
let stopForCost = false;
|
|
598
|
+
// P0-2: the side-effect op currently in flight (at most one — the loop runs
|
|
599
|
+
// tools serially). Non-null only between a dangerous tool's tool-executing
|
|
600
|
+
// and its tool-result.
|
|
601
|
+
let currentSideEffectOpId = null;
|
|
549
602
|
|
|
550
603
|
// Collapse consecutive same-role turns before the model call ONLY when the
|
|
551
604
|
// caller flags a resume-degenerate transcript (`mergeRoles`): a resumed
|
|
@@ -583,10 +636,52 @@ async function runTurn(
|
|
|
583
636
|
tool: event.tool,
|
|
584
637
|
args: event.args,
|
|
585
638
|
});
|
|
639
|
+
// P0-2: record an irreversible effect as STARTED (persisted before it
|
|
640
|
+
// settles) so a crash before the matching tool-result leaves a
|
|
641
|
+
// reconcilable "in flight" marker instead of a silent replay — mirrors
|
|
642
|
+
// the single-prompt runner and the WS bridge. `sideEffects` is null
|
|
643
|
+
// when the session doesn't persist, keeping that path byte-identical.
|
|
644
|
+
currentSideEffectOpId = null;
|
|
645
|
+
if (sideEffects) {
|
|
646
|
+
const se = classifyToolSideEffect(event.tool, event.args);
|
|
647
|
+
if (se) {
|
|
648
|
+
const opId = sideEffects.nextOpId();
|
|
649
|
+
currentSideEffectOpId = opId;
|
|
650
|
+
sideEffects.ledger
|
|
651
|
+
.prepare(opId, {
|
|
652
|
+
kind: se.kind,
|
|
653
|
+
key: se.key,
|
|
654
|
+
// Content-addressed key: a resumed replay of the SAME effect
|
|
655
|
+
// derives the SAME key, so an external provider can de-dupe
|
|
656
|
+
// and countDuplicateCommittedEffects can measure `0` repeats.
|
|
657
|
+
meta: {
|
|
658
|
+
tool: event.tool,
|
|
659
|
+
idempotencyKey: operationIdempotencyKey({
|
|
660
|
+
tool: event.tool,
|
|
661
|
+
args: event.args,
|
|
662
|
+
}),
|
|
663
|
+
},
|
|
664
|
+
})
|
|
665
|
+
.start(opId);
|
|
666
|
+
sideEffects.persist();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
586
669
|
break;
|
|
587
670
|
}
|
|
588
671
|
case "tool-result": {
|
|
589
672
|
const err = event.error || event.result?.error || null;
|
|
673
|
+
// P0-2: settle the in-flight side-effect (commit on success, fail on
|
|
674
|
+
// a clean error) and persist the updated ledger snapshot.
|
|
675
|
+
if (sideEffects && currentSideEffectOpId) {
|
|
676
|
+
if (err)
|
|
677
|
+
sideEffects.ledger.fail(
|
|
678
|
+
currentSideEffectOpId,
|
|
679
|
+
String(err).slice(0, 200),
|
|
680
|
+
);
|
|
681
|
+
else sideEffects.ledger.commit(currentSideEffectOpId);
|
|
682
|
+
sideEffects.persist();
|
|
683
|
+
currentSideEffectOpId = null;
|
|
684
|
+
}
|
|
590
685
|
// The loop runs tools serially, so this result settles the most
|
|
591
686
|
// recent tool_use (same adjacency rule the is_error attribution
|
|
592
687
|
// below has always used).
|
|
@@ -846,6 +941,39 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
846
941
|
// id is kept for event correlation only; nothing is written or replayed).
|
|
847
942
|
const persist = Boolean(options.sessionId) && options.ephemeral !== true;
|
|
848
943
|
|
|
944
|
+
// ── P0-2: crash-safe side-effect ledger — the stream twin of the
|
|
945
|
+
// single-prompt runner (headless-runner.js) and the WS bridge
|
|
946
|
+
// (ws-agent-handler.js). Dangerous tools (file writes, opaque shell,
|
|
947
|
+
// git push, publish/schedule/notify/browser actions) are recorded
|
|
948
|
+
// prepare→start→commit|fail with the snapshot persisted BEFORE the effect
|
|
949
|
+
// settles, so an IDE chat-panel worker killed mid-flight is surfaced for
|
|
950
|
+
// verification on resume instead of being blindly replayed. Only active when
|
|
951
|
+
// persisting (an anonymous/--ephemeral stream can't be resumed); a run that
|
|
952
|
+
// touches no dangerous tool writes nothing.
|
|
953
|
+
const loadLedger = deps.loadSideEffectLedger || loadSideEffectLedger;
|
|
954
|
+
const persistLedger = deps.persistSideEffectLedger || persistSideEffectLedger;
|
|
955
|
+
let sideEffectLedger = null;
|
|
956
|
+
if (persist) {
|
|
957
|
+
try {
|
|
958
|
+
sideEffectLedger = loadLedger(sessionId);
|
|
959
|
+
} catch {
|
|
960
|
+
// ledger is best-effort — never block the stream over it
|
|
961
|
+
sideEffectLedger = null;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
let sideEffectSeq = 0;
|
|
965
|
+
// Run-scoped nonce keeps op ids unique even when two runs resume the same
|
|
966
|
+
// session (prepare() is idempotent on opId, so a collision would silently
|
|
967
|
+
// drop the newer record).
|
|
968
|
+
const sideEffectRunNonce = String(deps.now ? deps.now() : Date.now());
|
|
969
|
+
const sideEffects = sideEffectLedger
|
|
970
|
+
? {
|
|
971
|
+
ledger: sideEffectLedger,
|
|
972
|
+
persist: () => persistLedger(sessionId, sideEffectLedger),
|
|
973
|
+
nextOpId: () => `${sideEffectRunNonce}:${sideEffectSeq++}`,
|
|
974
|
+
}
|
|
975
|
+
: null;
|
|
976
|
+
|
|
849
977
|
// ── Interactive approvals (--interactive-approvals; chat-panel UX) ────────
|
|
850
978
|
// CONFIRM-tier decisions (risky shell via the ApprovalGate, settings/hook
|
|
851
979
|
// `ask`) normally fail closed in headless. With this opt-in they become a
|
|
@@ -1163,9 +1291,21 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
1163
1291
|
// Resume: replay the persisted conversation (fresh system prompt always
|
|
1164
1292
|
// leads; persisted system turns are dropped, mirroring runAgentHeadless).
|
|
1165
1293
|
let resumedMessages = 0;
|
|
1294
|
+
let sideEffectRecovery = null;
|
|
1166
1295
|
if (persist) {
|
|
1167
1296
|
try {
|
|
1168
1297
|
if (store.sessionExists(sessionId)) {
|
|
1298
|
+
// P0-2: reconcile the crash-safe ledger on resume (parity with
|
|
1299
|
+
// runAgentHeadless + the WS bridge). The verify-before-replay system
|
|
1300
|
+
// note goes BEFORE the replayed history — the same slot the
|
|
1301
|
+
// single-prompt runner uses — which also keeps the trailing-role
|
|
1302
|
+
// resume-degeneracy check below intact.
|
|
1303
|
+
if (sideEffectLedger) {
|
|
1304
|
+
sideEffectRecovery = buildSideEffectRecovery(sideEffectLedger);
|
|
1305
|
+
}
|
|
1306
|
+
if (sideEffectRecovery) {
|
|
1307
|
+
messages.push({ role: "system", content: sideEffectRecovery.notice });
|
|
1308
|
+
}
|
|
1169
1309
|
const history = (store.rebuildMessages(sessionId) || []).filter(
|
|
1170
1310
|
(m) => m && m.role !== "system",
|
|
1171
1311
|
);
|
|
@@ -1225,6 +1365,22 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
1225
1365
|
resumed_messages: resumedMessages,
|
|
1226
1366
|
});
|
|
1227
1367
|
|
|
1368
|
+
// P0-2 visible recovery notice: same `raw` info-line contract as
|
|
1369
|
+
// provider_fallback / version_skew (the shipped IDE panels map `raw` → an
|
|
1370
|
+
// info line), so both panels render it with zero IDE changes. Emitted right
|
|
1371
|
+
// after `init` so consumers keep seeing init as the first line; absent
|
|
1372
|
+
// entirely on a clean (or ledger-free) resume.
|
|
1373
|
+
if (sideEffectRecovery) {
|
|
1374
|
+
emit({
|
|
1375
|
+
type: "raw",
|
|
1376
|
+
subtype: "side_effect_recovery",
|
|
1377
|
+
text: `⚠️ ${sideEffectRecovery.count} interrupted side-effect(s) need verification before replay (resume ${sessionId}).`,
|
|
1378
|
+
count: sideEffectRecovery.count,
|
|
1379
|
+
items: sideEffectRecovery.items,
|
|
1380
|
+
session_id: sessionId,
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1228
1384
|
// Goal binding (cc goal, Phase 1) — resolved once and injected on every turn.
|
|
1229
1385
|
// `--goal <id>` binds explicitly; `--goal` with no value auto-resolves.
|
|
1230
1386
|
let goalPrepareCallFn;
|
|
@@ -1302,6 +1458,23 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
1302
1458
|
}
|
|
1303
1459
|
}
|
|
1304
1460
|
|
|
1461
|
+
// Seed MCP roots for --add-dir (roots/list_changed parity): advertise the full
|
|
1462
|
+
// workspace-root list to connected MCP servers when the stream session started
|
|
1463
|
+
// with extra roots. No --add-dir → workspaceRootDirs = [cwd] → no-op. Mirrors
|
|
1464
|
+
// the single-prompt runner + the REPL /add-dir path. Best-effort.
|
|
1465
|
+
if (mcp?.mcpClient && additionalDirectories.length > 0) {
|
|
1466
|
+
try {
|
|
1467
|
+
const { notifyMcpRootsChanged, workspaceRootDirs } =
|
|
1468
|
+
await import("../repl/add-dir.js");
|
|
1469
|
+
notifyMcpRootsChanged(
|
|
1470
|
+
[mcp.mcpClient],
|
|
1471
|
+
workspaceRootDirs(options.cwd || process.cwd(), additionalDirectories),
|
|
1472
|
+
);
|
|
1473
|
+
} catch {
|
|
1474
|
+
// best-effort — root advertisement never blocks a run
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1305
1478
|
// --permission-prompt-tool: defer CONFIRM-tier approvals to an MCP tool
|
|
1306
1479
|
// (loaded via --mcp-config) instead of headless fail-closed.
|
|
1307
1480
|
if (options.permissionPromptTool) {
|
|
@@ -1993,7 +2166,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
1993
2166
|
// Resume-degenerate role merge for the first live model call only.
|
|
1994
2167
|
mergeRoles: mergeRolesThisTurn,
|
|
1995
2168
|
},
|
|
1996
|
-
{ runLoop, emit, costBudget, nextToolUseId },
|
|
2169
|
+
{ runLoop, emit, costBudget, nextToolUseId, sideEffects },
|
|
1997
2170
|
);
|
|
1998
2171
|
} catch (err) {
|
|
1999
2172
|
currentAbort = null;
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
writeBackgroundAgentState,
|
|
25
25
|
} from "../lib/background-agent-supervisor.js";
|
|
26
26
|
import { startBackgroundSessionServer } from "../lib/background-session-transport.js";
|
|
27
|
+
import { idlePhaseFor } from "../lib/background-agent-phase.js";
|
|
27
28
|
|
|
28
29
|
const jobFile = process.argv[2];
|
|
29
30
|
let job;
|
|
@@ -124,6 +125,15 @@ function startTurn(argv, promptText) {
|
|
|
124
125
|
status: "running",
|
|
125
126
|
phase,
|
|
126
127
|
turnCount,
|
|
128
|
+
// A fresh turn has nothing pending; also clears a stale count left behind
|
|
129
|
+
// if the previous turn's child was hard-killed mid-approval (the child's
|
|
130
|
+
// phase reporter clears on settle, but SIGKILL never settles).
|
|
131
|
+
pendingApprovals: 0,
|
|
132
|
+
// The incoming prompt IS the user's reply to any parked question, and the
|
|
133
|
+
// uncertain-side-effect annotation only covers the verify turn it was
|
|
134
|
+
// raised in — both reset at the turn boundary.
|
|
135
|
+
pendingQuestion: null,
|
|
136
|
+
uncertainSideEffects: 0,
|
|
127
137
|
agentPid: child.pid,
|
|
128
138
|
// Identity anchor for the supervisor's orphan reclaim (Gap 2): pairs
|
|
129
139
|
// with agentPid the way startedAt pairs with the worker pid, so a
|
|
@@ -163,9 +173,20 @@ function maybeContinue() {
|
|
|
163
173
|
return;
|
|
164
174
|
}
|
|
165
175
|
if (server && server.clientCount() > 0) {
|
|
166
|
-
|
|
176
|
+
// Parked between turns. Normally `idle` — but a turn that parked an
|
|
177
|
+
// unanswered ask_user_question stays `needs_input` until the user's reply
|
|
178
|
+
// starts the next turn (the reply prompt clears pendingQuestion).
|
|
179
|
+
phase = idlePhaseFor(current);
|
|
167
180
|
mergeState({
|
|
168
181
|
phase,
|
|
182
|
+
// Between turns no APPROVAL can be pending — the approval-owning child
|
|
183
|
+
// has exited. Honest zero keeps a killed-mid-approval count from
|
|
184
|
+
// parking the session in "Needs input" forever. (A parked QUESTION is
|
|
185
|
+
// different: it awaits the user, so pendingQuestion survives idle.)
|
|
186
|
+
pendingApprovals: 0,
|
|
187
|
+
// The verify turn for any uncertain side effects has now run its
|
|
188
|
+
// course — the annotation does not outlive it.
|
|
189
|
+
uncertainSideEffects: 0,
|
|
169
190
|
agentPid: null,
|
|
170
191
|
agentStartedAt: null,
|
|
171
192
|
heartbeatAt: Date.now(),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{P as c,J as p,b as s}from"./vendor-Bn1JzzAn.js";import{r as a}from"./markdown-Yo_c6Krv.js";import{_ as d}from"./index-GG_MXjSL.js";const _={__name:"MarkdownRenderer",props:{content:{type:String,default:""}},setup(t,{expose:o}){o();const e=t,r=s(()=>a(e.content||"")),n={props:e,rendered:r,computed:s,get renderMarkdown(){return a}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}},i=["innerHTML"];function m(t,o,e,r,n,u){return c(),p("div",{class:"markdown-content",innerHTML:r.rendered},null,8,i)}const w=d(_,[["render",m],["__scopeId","data-v-0b0b9f63"],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/components/MarkdownRenderer.vue"]]);export{w as M};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./ChatBubbleRenderer-D1CtRAyy.js","./vendor-Bn1JzzAn.js","./index-GG_MXjSL.js","./icons-DG5UD-6K.js","./index-Cq93VfoF.css","./ChatBubbleRenderer-gy5SDGw2.css","./OrderTableRenderer-DvzVl5T3.js","./OrderTableRenderer-CfrDjSHT.css","./TimelineRenderer-C5GOoxFz.js","./TimelineRenderer-BlTAtkOc.css","./EmailListRenderer-CyFkybOG.js","./EmailListRenderer-DTPZPx_S.css","./GenericCardRenderer-DS5DIdsW.js","./GenericCardRenderer-o85VDYQS.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{E as ue,r as R,b as C,I as y,P as u,J as O,U as v,c,S as w,V as E,_ as M,F as V,Z as se,a0 as le,R as x,K as m,Q as b,W as L,o as J}from"./vendor-Bn1JzzAn.js";import{u as U}from"./usePersonalDataHub-CrEUY7ta.js";import{_ as D,e as F,d as P}from"./index-GG_MXjSL.js";import{aa as q,ag as Q,M as z,aI as G,v as H,aH as K,aq as W,ac as Y,e as de,d as fe,k as pe,ai as me,aA as _e,R as ge}from"./icons-DG5UD-6K.js";const I=Object.freeze({q:"",category:null,adapter:null,subtype:null,since:null,until:null}),B=50,Z=300,X=ue("pdhBrowser",()=>{const r=R({...I}),t=R([]),n=R(null),e=R(!1),o=R(!1),l=R(null),a=R(null),s=R(!1),i=R({byCategory:{},byAdapter:{},bySubtype:{},total:0});let d=0,_=null;const A=C(()=>t.value.length>0),j=C(()=>n.value!=null);function h(S={}){const p={},f=r.value;return f.q&&f.q.trim()&&(p.q=f.q.trim()),f.category&&(p.category=f.category),f.adapter&&(p.adapter=f.adapter),f.subtype&&(p.subtype=f.subtype),Number.isFinite(f.since)&&(p.since=f.since),Number.isFinite(f.until)&&(p.until=f.until),{...p,...S}}async function g(){const S=++d;e.value=!0,l.value=null;const p=U();try{const[f,T]=await Promise.all([p.searchEvents(h({limit:B})),p.facetCounts({...r.value.q&&r.value.q.trim()?{q:r.value.q.trim()}:{},...Number.isFinite(r.value.since)?{since:r.value.since}:{},...Number.isFinite(r.value.until)?{until:r.value.until}:{}})]);if(S!==d)return;t.value=f.rows||[],n.value=f.nextCursor||null,a.value=f.mode||"like",s.value=!!f.shortQuery,i.value={byCategory:T.byCategory||{},byAdapter:T.byAdapter||{},bySubtype:T.bySubtype||{},total:T.total||0}}catch(f){if(S!==d)return;l.value=f&&f.message?f.message:String(f),t.value=[],n.value=null}finally{S===d&&(e.value=!1)}}async function k(){if(!n.value||o.value)return;o.value=!0,l.value=null;const S=U();try{const p=await S.searchEvents(h({cursor:n.value,limit:B}));t.value=t.value.concat(p.rows||[]),n.value=p.nextCursor||null,a.value=p.mode||a.value}catch(p){l.value=p&&p.message?p.message:String(p)}finally{o.value=!1}}function ae(S,p){if(!(S in I))throw new Error(`pdhBrowser.setFilter: unknown key "${S}"`);r.value={...r.value,[S]:p},_&&clearTimeout(_),_=setTimeout(()=>{_=null,g()},Z)}function ie(S){return r.value={...I,...S},_&&(clearTimeout(_),_=null),g()}function ce(){r.value={...I},t.value=[],n.value=null,l.value=null,i.value={byCategory:{},byAdapter:{},bySubtype:{},total:0}}return{filters:r,results:t,cursor:n,isLoading:e,isAppending:o,error:l,mode:a,shortQuery:s,facets:i,hasResults:A,canLoadMore:j,search:g,loadMore:k,setFilter:ae,setFilters:ie,reset:ce,PAGE_SIZE:B,SEARCH_DEBOUNCE_MS:Z}}),ye=Object.freeze(["chat","social","email","shopping","travel","system","ai-chat","other"]),ve=Object.freeze({chat:"社交聊天",social:"内容平台",email:"邮件",shopping:"支付订单",travel:"出行",system:"系统数据","ai-chat":"AI 对话",other:"其他"});function N(r){return ve[r]||r||"未知"}const be=Object.freeze([["wechat","chat"],["messaging-","chat"],["social-","social"],["email-","email"],["shopping-","shopping"],["alipay-","shopping"],["travel-","travel"],["system-data","system"],["browser-","system"],["vscode","system"],["win-recent","system"],["git-activity","system"],["shell-history","system"],["local-files","system"],["ai-chat-","ai-chat"]]);function $(r){if(typeof r!="string"||r.length===0)return"other";for(const[t,n]of be)if(t.endsWith("-")||t==="system-data"){if(r.startsWith(t))return n}else if(r===t)return n;return"other"}const he={__name:"CategorySidebar",props:{selected:{type:String,default:null},facets:{type:Object,default:()=>({byCategory:{},total:0})}},emits:["select"],setup(r,{expose:t}){t();const n=r,e=C(()=>n.facets.total||0),o={chat:Y,social:W,email:K,shopping:H,travel:G,system:z,"ai-chat":Q,other:q};function l(i){return o[i]||q}function a(i){return i?{backgroundColor:"#fff",color:"#1677ff"}:{backgroundColor:"#f0f0f0",color:"#666"}}const s={props:n,total:e,ICONS:o,iconFor:l,badgeStyle:a,computed:C,get AppstoreOutlined(){return q},get MessageOutlined(){return Y},get PlayCircleOutlined(){return W},get MailOutlined(){return K},get ShoppingOutlined(){return H},get CarOutlined(){return G},get MobileOutlined(){return z},get RobotOutlined(){return Q},get CATEGORIES(){return ye},get categoryLabel(){return N}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},Se={class:"pdh-sidebar"},Oe=["onClick"],Ce={class:"label"};function we(r,t,n,e,o,l){const a=y("a-badge");return u(),O("div",Se,[t[2]||(t[2]=v("div",{class:"sidebar-title"},"数据类型",-1)),v("div",{class:M(["cat-item",{active:n.selected===null}]),onClick:t[0]||(t[0]=s=>r.$emit("select",null))},[c(e.AppstoreOutlined,{class:"icon"}),t[1]||(t[1]=v("span",{class:"label"},"全部",-1)),e.total>0?(u(),w(a,{key:0,count:e.total,"number-style":e.badgeStyle(n.selected===null),"overflow-count":9999},null,8,["count","number-style"])):E("v-if",!0)],2),(u(!0),O(V,null,se(e.CATEGORIES,s=>(u(),O("div",{key:s,class:M(["cat-item",{active:n.selected===s,dim:!n.facets.byCategory[s]}]),onClick:i=>r.$emit("select",s)},[(u(),w(le(e.iconFor(s)),{class:"icon"})),v("span",Ce,x(e.categoryLabel(s)),1),n.facets.byCategory[s]?(u(),w(a,{key:0,count:n.facets.byCategory[s],"number-style":e.badgeStyle(n.selected===s),"overflow-count":9999},null,8,["count","number-style"])):E("v-if",!0)],10,Oe))),128))])}const ke=D(he,[["render",we],["__scopeId","data-v-6b62a22e"],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/components/pdh/CategorySidebar.vue"]]),Ee={__name:"SearchFilterBar",props:{filters:{type:Object,required:!0},facets:{type:Object,default:()=>({byAdapter:{}})},isLoading:{type:Boolean,default:!1},mode:{type:String,default:null},shortQuery:{type:Boolean,default:!1}},emits:["set-filter","reset"],setup(r,{expose:t,emit:n}){t();const e=r,o=n,l=C(()=>e.filters.category?`在「${e.filters.category}」类目内搜索…`:"搜索关键词(如:支付宝、罗技、Kotlin)…"),a=C(()=>Object.entries(e.facets.byAdapter||{}).sort((g,k)=>k[1]-g[1]).map(([g,k])=>({value:g,label:`${g} (${k})`}))),s=C(()=>!e.filters.since&&!e.filters.until?null:[e.filters.since?new Date(e.filters.since):null,e.filters.until?new Date(e.filters.until):null]),i=C(()=>!!(e.filters.q||e.filters.adapter||e.filters.subtype||e.filters.since||e.filters.until));function d(h){o("set-filter","q",h||"")}function _(h){o("set-filter","q",h||"")}function A(h){if(!h||h.length===0){o("set-filter","since",null),o("set-filter","until",null);return}const[g,k]=h;o("set-filter","since",g?+g:null),o("set-filter","until",k?+k:null)}const j={props:e,emit:o,placeholderText:l,adapterOptions:a,dateRangeValue:s,hasActiveFilters:i,onQInput:d,onSearch:_,onDateChange:A,computed:C,get SearchOutlined(){return pe},get CloseCircleOutlined(){return fe},get InfoCircleOutlined(){return de}};return Object.defineProperty(j,"__isScriptSetup",{enumerable:!1,value:!0}),j}},Re={class:"pdh-filter-bar"},xe={key:1,class:"hint"},Ae={key:2,class:"hint"};function je(r,t,n,e,o,l){const a=y("a-input-search"),s=y("a-select"),i=y("a-range-picker"),d=y("a-button");return u(),O("div",Re,[c(a,{value:n.filters.q,placeholder:e.placeholderText,"enter-button":"搜索","allow-clear":"",loading:n.isLoading,style:{flex:"1","max-width":"480px"},"onUpdate:value":e.onQInput,onSearch:e.onSearch},{prefix:m(()=>[c(e.SearchOutlined)]),_:1},8,["value","placeholder","loading"]),c(s,{value:n.filters.adapter,placeholder:"所有 adapter","allow-clear":"",options:e.adapterOptions,style:{width:"200px"},"onUpdate:value":t[0]||(t[0]=_=>r.$emit("set-filter","adapter",_||null))},null,8,["value","options"]),c(i,{value:e.dateRangeValue,placeholder:["开始日期","结束日期"],style:{width:"280px"},"onUpdate:value":e.onDateChange},null,8,["value"]),e.hasActiveFilters?(u(),w(d,{key:0,type:"link",danger:"",onClick:t[1]||(t[1]=_=>r.$emit("reset"))},{icon:m(()=>[c(e.CloseCircleOutlined)]),default:m(()=>[t[2]||(t[2]=b(" 清空筛选 ",-1))]),_:1})):E("v-if",!0),n.shortQuery?(u(),O("span",xe,[c(e.InfoCircleOutlined),t[3]||(t[3]=b(" 关键词需至少 3 字 (FTS5 trigram 限制) ",-1))])):n.mode==="like"?(u(),O("span",Ae,[c(e.InfoCircleOutlined),t[4]||(t[4]=b(" 当前为 LIKE 兜底模式 ",-1))])):E("v-if",!0)])}const Le=D(Ee,[["render",je],["__scopeId","data-v-d7cce6e9"],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/components/pdh/SearchFilterBar.vue"]]),Fe={__name:"RendererDispatcher",props:{event:{type:Object,required:!0}},setup(r,{expose:t}){t();const n=L(()=>F(()=>import("./ChatBubbleRenderer-D1CtRAyy.js"),__vite__mapDeps([0,1,2,3,4,5]),import.meta.url)),e=L(()=>F(()=>import("./OrderTableRenderer-DvzVl5T3.js"),__vite__mapDeps([6,1,2,3,4,7]),import.meta.url)),o=L(()=>F(()=>import("./TimelineRenderer-C5GOoxFz.js"),__vite__mapDeps([8,1,2,3,4,9]),import.meta.url)),l=L(()=>F(()=>import("./EmailListRenderer-CyFkybOG.js"),__vite__mapDeps([10,1,2,3,4,11]),import.meta.url)),a=L(()=>F(()=>import("./GenericCardRenderer-DS5DIdsW.js"),__vite__mapDeps([12,1,2,3,4,13]),import.meta.url));function s(d){const _=d&&d.source&&d.source.adapter;switch($(_)){case"chat":case"ai-chat":return n;case"shopping":return e;case"travel":return o;case"email":return l;default:return a}}const i={ChatBubbleRenderer:n,OrderTableRenderer:e,TimelineRenderer:o,EmailListRenderer:l,GenericCardRenderer:a,rendererFor:s,defineAsyncComponent:L,get getCategory(){return $}};return Object.defineProperty(i,"__isScriptSetup",{enumerable:!1,value:!0}),i}};function De(r,t,n,e,o,l){return u(),w(le(e.rendererFor(n.event)),{event:n.event},null,8,["event"])}const Te=D(Fe,[["render",De],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/components/pdh/renderers/RendererDispatcher.vue"]]);function ee(r){return JSON.stringify(r,null,2)}function te(r){return r.map(t=>JSON.stringify(t)).join(`
|
|
3
|
-
`)+`
|
|
4
|
-
`}function ne(r){const n=["id","subtype","occurredAt","occurredAtIso","actor","place","adapter","summary","contentJson","extraJson"].join(","),e=r.map(o=>{const l=Number.isFinite(o.occurredAt)?o.occurredAt:null,a=l?new Date(l).toISOString():"",s=o.source&&o.source.adapter||"",i=o.content&&(o.content.text||o.content.title||o.content.subject)||"";return[o.id||"",o.subtype||"",l!=null?String(l):"",a,o.actor||"",o.place||"",s,i,o.content?JSON.stringify(o.content):"",o.extra?JSON.stringify(o.extra):""].map(Ie).join(",")});return[n,...e].join(`
|
|
5
|
-
`)+`
|
|
6
|
-
`}function Ie(r){const t=String(r??"");return t.includes(",")||t.includes('"')||t.includes(`
|
|
7
|
-
`)||t.includes("\r")?'"'+t.replace(/"/g,'""')+'"':t}function re(r,t,n="application/octet-stream"){if(typeof window>"u"||typeof document>"u")return t;const e=new Blob([r],{type:n}),o=URL.createObjectURL(e),l=document.createElement("a");return l.href=o,l.download=t,document.body.appendChild(l),l.click(),document.body.removeChild(l),setTimeout(()=>URL.revokeObjectURL(o),1e3),t}function oe(r,t=null){const n=new Date,e=n.getFullYear(),o=String(n.getMonth()+1).padStart(2,"0"),l=String(n.getDate()).padStart(2,"0"),a=r==="ndjson"?"ndjson":r,s=t?`-${t}`:"";return`pdh-events-${e}-${o}-${l}${s}.${a}`}const Pe={__name:"ExportDropdown",props:{events:{type:Array,required:!0},category:{type:String,default:null}},setup(r,{expose:t}){t();const n=r,e=C(()=>n.events.length>0),o={json:"application/json;charset=utf-8",ndjson:"application/x-ndjson;charset=utf-8",csv:"text/csv;charset=utf-8"};function l(i){switch(i){case"json":return ee(n.events);case"ndjson":return te(n.events);case"csv":return ne(n.events);default:throw new Error(`unknown format: ${i}`)}}function a({key:i}){try{const d=l(i),_=oe(i,n.category);re(d,_,o[i]),P.success(`已导出 ${n.events.length} 条到 ${_}`)}catch(d){P.error(`导出失败: ${d.message||d}`)}}const s={props:n,hasResults:e,MIME:o,serialize:l,onClick:a,computed:C,get DownloadOutlined(){return _e},get DownOutlined(){return me},get message(){return P},get eventsToJson(){return ee},get eventsToNdjson(){return te},get eventsToCsv(){return ne},get downloadAs(){return re},get suggestFilename(){return oe}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}};function qe(r,t,n,e,o,l){const a=y("a-button"),s=y("a-menu-item"),i=y("a-menu"),d=y("a-dropdown");return u(),w(d,{disabled:!e.hasResults},{overlay:m(()=>[c(i,{onClick:e.onClick},{default:m(()=>[c(s,{key:"json"},{default:m(()=>[...t[0]||(t[0]=[b("JSON (.json)",-1)])]),_:1}),c(s,{key:"ndjson"},{default:m(()=>[...t[1]||(t[1]=[b("NDJSON (.ndjson)",-1)])]),_:1}),c(s,{key:"csv"},{default:m(()=>[...t[2]||(t[2]=[b("CSV (.csv)",-1)])]),_:1})]),_:1})]),default:m(()=>[c(a,{disabled:!e.hasResults},{icon:m(()=>[c(e.DownloadOutlined)]),default:m(()=>[b(" 导出 ("+x(n.events.length)+") ",1),c(e.DownOutlined)]),_:1},8,["disabled"])]),_:1},8,["disabled"])}const Be=D(Pe,[["render",qe],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/components/pdh/ExportDropdown.vue"]]),Ve={__name:"PdhVaultBrowser",setup(r,{expose:t}){t();const n=X(),e=C(()=>n.filters.q?`没有匹配 "${n.filters.q}" 的事件 — 试试更短的关键词或换个类目`:n.filters.category?`「${N(n.filters.category)}」类目下还没有数据 — 去采集页同步对应 adapter`:"Vault 里还没有数据 — 去「个人数据中台」页面同步任意 adapter");function o(s){n.filters.category=s,n.search()}function l(s,i){n.setFilter(s,i)}J(()=>{!n.hasResults&&!n.isLoading&&n.search()});const a={store:n,emptyHint:e,onCategorySelect:o,onSetFilter:l,onMounted:J,computed:C,get ReloadOutlined(){return ge},get usePdhBrowserStore(){return X},get categoryLabel(){return N},CategorySidebar:ke,SearchFilterBar:Le,RendererDispatcher:Te,ExportDropdown:Be};return Object.defineProperty(a,"__isScriptSetup",{enumerable:!1,value:!0}),a}},Ne={class:"pdh-browser-page"},Me={class:"page-header"},Je={class:"main-pane"},Ue={class:"results-summary"},Qe={key:0},ze={key:0},Ge={key:1},He={class:"loaded-of"},Ke={class:"results-list"},We={key:2,class:"load-more"};function Ye(r,t,n,e,o,l){const a=y("a-tag"),s=y("a-button"),i=y("a-space"),d=y("a-col"),_=y("a-spin"),A=y("a-alert"),j=y("a-empty"),h=y("a-row");return u(),O("div",Ne,[v("div",Me,[t[6]||(t[6]=v("div",null,[v("h2",{class:"page-title"},"数据浏览器"),v("p",{class:"page-sub"}," Vault 里所有已采集的数据,按类目浏览 / 全文检索 / 时间窗口筛选。 完全离线,不外传。 ")],-1)),c(i,null,{default:m(()=>[e.store.mode==="fts5"?(u(),w(a,{key:0,color:"green"},{default:m(()=>[...t[3]||(t[3]=[b("FTS5 trigram",-1)])]),_:1})):e.store.mode==="like"?(u(),w(a,{key:1,color:"orange"},{default:m(()=>[...t[4]||(t[4]=[b("LIKE 兜底",-1)])]),_:1})):E("v-if",!0),c(e.ExportDropdown,{events:e.store.results,category:e.store.filters.category},null,8,["events","category"]),c(s,{onClick:t[0]||(t[0]=g=>e.store.search()),loading:e.store.isLoading},{icon:m(()=>[c(e.ReloadOutlined)]),default:m(()=>[t[5]||(t[5]=b(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),c(h,{gutter:16,class:"browser-layout"},{default:m(()=>[c(d,{xs:24,sm:24,md:6,lg:5,xl:4},{default:m(()=>[c(e.CategorySidebar,{selected:e.store.filters.category,facets:e.store.facets,onSelect:e.onCategorySelect},null,8,["selected","facets"])]),_:1}),c(d,{xs:24,sm:24,md:18,lg:19,xl:20},{default:m(()=>[v("div",Je,[c(e.SearchFilterBar,{filters:e.store.filters,facets:e.store.facets,"is-loading":e.store.isLoading,mode:e.store.mode,"short-query":e.store.shortQuery,onSetFilter:e.onSetFilter,onReset:t[1]||(t[1]=g=>{e.store.reset(),e.store.search()})},null,8,["filters","facets","is-loading","mode","short-query"]),v("div",Ue,[e.store.isLoading&&e.store.results.length===0?(u(),O("span",Qe,[c(_,{size:"small"}),t[7]||(t[7]=b(" 载入中… ",-1))])):(u(),O(V,{key:1},[v("strong",null,x(e.store.facets.total),1),t[11]||(t[11]=b(" 条事件 ",-1)),e.store.filters.category?(u(),O("span",ze,[t[8]||(t[8]=b(" / 当前类目 ",-1)),v("strong",null,x(e.categoryLabel(e.store.filters.category)),1),v("strong",null,x(e.store.facets.byCategory[e.store.filters.category]||0),1)])):E("v-if",!0),e.store.filters.q?(u(),O("span",Ge,[t[9]||(t[9]=b(' / 关键词 "',-1)),v("em",null,x(e.store.filters.q),1),t[10]||(t[10]=b('"',-1))])):E("v-if",!0),v("span",He," / 已显示 "+x(e.store.results.length),1)],64))]),e.store.error?(u(),w(A,{key:0,type:"error","show-icon":"",message:e.store.error,closable:"",style:{margin:"12px 0"}},null,8,["message"])):E("v-if",!0),!e.store.isLoading&&e.store.results.length===0&&!e.store.error?(u(),w(j,{key:1,description:e.emptyHint,style:{"margin-top":"40px"}},null,8,["description"])):E("v-if",!0),v("div",Ke,[(u(!0),O(V,null,se(e.store.results,(g,k)=>(u(),w(e.RendererDispatcher,{key:`r-${k}-${g.id}`,event:g},null,8,["event"]))),128))]),e.store.canLoadMore?(u(),O("div",We,[c(s,{loading:e.store.isAppending,onClick:t[2]||(t[2]=g=>e.store.loadMore()),block:""},{default:m(()=>[...t[12]||(t[12]=[b(" 加载下一页 (50 条) ",-1)])]),_:1},8,["loading"])])):E("v-if",!0)])]),_:1})]),_:1})])}const tt=D(Ve,[["render",Ye],["__scopeId","data-v-0f7c02cd"],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/views/PdhVaultBrowser.vue"]]);export{tt as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{E as F,b as D,r as R,I as p,J as c,U as _,c as n,K as a,S,V as x,o as I,x as V,P as i,Q as k,R as r,F as T,Z as O}from"./vendor-Bn1JzzAn.js";import{u as P,_ as E}from"./index-GG_MXjSL.js";import{R as U}from"./icons-DG5UD-6K.js";const B=F("tasks",()=>{const y=R([]),l=R(!1);let u=null,t=null,d=null;const b=D(()=>y.value.filter(e=>e.status==="running")),v=D(()=>y.value.filter(e=>e.status==="pending")),w=D(()=>y.value.filter(e=>e.status==="completed"||e.status==="failed"||e.status==="timeout"));async function s(){const e=P();l.value=!0;try{const g=await e.sendRaw({type:"tasks-list"});g&&Array.isArray(g.tasks)&&(y.value=g.tasks)}catch{}finally{l.value=!1}}async function m(e){const g=P();try{await g.sendRaw({type:"tasks-stop",taskId:e})}catch{}finally{await s()}}const f=R(null);function h(e=5e3){N(),s(),u=setInterval(s,e),C()}function N(){u&&(clearInterval(u),u=null),t&&(t(),t=null),d&&(clearTimeout(d),d=null)}function C(){const e=P();if(t)return;const g=z=>{z.type==="task:notification"&&z.payload?.task&&(f.value=z.payload.task,s(),d&&clearTimeout(d),d=setTimeout(()=>{f.value=null,d=null},8e3))};t=e.onRuntimeEvent(g)}function A(e){return!e||e<0?"-":e<1e3?`${e}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${(e/6e4).toFixed(1)}m`}function o(e){switch(e){case"running":return"processing";case"pending":return"default";case"completed":return"success";case"failed":return"error";case"timeout":return"warning";default:return"default"}}return{tasks:y,loading:l,running:b,pending:v,completed:w,lastNotification:f,fetchTasks:s,stopTask:m,startPolling:h,stopPolling:N,formatDuration:A,getStatusColor:o}}),L={__name:"Tasks",setup(y,{expose:l}){l();const u=B(),t=[{title:"状态",key:"status",width:90},{title:"描述",key:"description",ellipsis:!0},{title:"类型",dataIndex:"type",width:100},{title:"耗时",key:"duration",width:90},{title:"创建时间",key:"createdAt",width:180},{title:"结果",key:"result",ellipsis:!0},{title:"操作",key:"action",width:80}];function d(s){return s.status==="running"&&s.startedAt?u.formatDuration(Date.now()-s.startedAt):s.completedAt&&s.startedAt?u.formatDuration(s.completedAt-s.startedAt):"-"}function b(s){return s?new Date(s).toLocaleString():"-"}function v(s,m){return s?s.length>m?`${s.slice(0,m)}...`:s:""}I(()=>u.startPolling(5e3)),V(()=>u.stopPolling());const w={store:u,columns:t,getDuration:d,formatTime:b,truncate:v,onMounted:I,onUnmounted:V,get ReloadOutlined(){return U},get useTasksStore(){return B}};return Object.defineProperty(w,"__isScriptSetup",{enumerable:!1,value:!0}),w}},j={class:"page-header"},J={key:0,class:"error-text"},K={key:1},M={class:"task-header"},Q={class:"task-desc"},W={class:"task-id"},Z={class:"task-meta"},q=["title"],G={key:0,class:"error-text"},H={key:1,class:"success-text"},X={key:2,class:"muted-text"};function Y(y,l,u,t,d,b){const v=p("a-button"),w=p("a-space"),s=p("a-alert"),m=p("a-statistic"),f=p("a-card"),h=p("a-col"),N=p("a-row"),C=p("a-tag"),A=p("a-table");return i(),c("div",null,[_("div",j,[l[3]||(l[3]=_("div",null,[_("h2",{class:"page-title"},"后台任务"),_("p",{class:"page-sub"},"查看后台任务队列、实时通知和任务执行结果。")],-1)),n(w,null,{default:a(()=>[n(v,{ghost:"",loading:t.store.loading,onClick:l[0]||(l[0]=o=>t.store.fetchTasks())},{icon:a(()=>[n(t.ReloadOutlined)]),default:a(()=>[l[2]||(l[2]=k(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),t.store.lastNotification?(i(),S(s,{key:0,type:t.store.lastNotification.status==="completed"?"success":"error","show-icon":"",closable:"",class:"banner",onClose:l[1]||(l[1]=o=>t.store.lastNotification=null)},{message:a(()=>[k(" 任务"+r(t.store.lastNotification.status==="completed"?"完成":"结束")+": "+r(t.store.lastNotification.description||t.store.lastNotification.id.slice(0,16)),1)]),description:a(()=>[t.store.lastNotification.error?(i(),c("span",J,r(t.store.lastNotification.error),1)):t.store.lastNotification.result?(i(),c("span",K,r(t.truncate(String(t.store.lastNotification.result),120)),1)):x("v-if",!0)]),_:1},8,["type"])):x("v-if",!0),n(N,{gutter:[16,16],class:"stats-row"},{default:a(()=>[n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"全部任务",value:t.store.tasks.length},null,8,["value"])]),_:1})]),_:1}),n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"运行中",value:t.store.running.length},null,8,["value"])]),_:1})]),_:1}),n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"等待中",value:t.store.pending.length},null,8,["value"])]),_:1})]),_:1}),n(h,{xs:12,sm:6},{default:a(()=>[n(f,{class:"stat-card",size:"small"},{default:a(()=>[n(m,{title:"已完成",value:t.store.completed.length},null,8,["value"])]),_:1})]),_:1})]),_:1}),t.store.running.length>0?(i(),S(f,{key:1,title:"运行中的任务",class:"panel-card",size:"small"},{default:a(()=>[(i(!0),c(T,null,O(t.store.running,o=>(i(),c("div",{key:o.id,class:"task-item running"},[_("div",M,[n(C,{color:t.store.getStatusColor(o.status)},{default:a(()=>[k(r(o.status.toUpperCase()),1)]),_:2},1032,["color"]),_("span",Q,r(o.description),1),_("span",W,r(o.id.slice(0,16)),1)]),_("div",Z,[_("span",null,"类型: "+r(o.type||"-"),1),_("span",null,"已运行: "+r(t.store.formatDuration(Date.now()-o.startedAt)),1),n(v,{size:"small",danger:"",onClick:e=>t.store.stopTask(o.id)},{default:a(()=>[...l[4]||(l[4]=[k("停止",-1)])]),_:1},8,["onClick"])])]))),128))]),_:1})):x("v-if",!0),n(f,{class:"panel-card"},{default:a(()=>[n(A,{columns:t.columns,"data-source":t.store.tasks,pagination:{pageSize:15,size:"small"},loading:t.store.loading,"row-key":"id",size:"small"},{bodyCell:a(({column:o,record:e})=>[o.key==="status"?(i(),S(C,{key:0,color:t.store.getStatusColor(e.status)},{default:a(()=>[k(r(e.status),1)]),_:2},1032,["color"])):o.key==="description"?(i(),c("span",{key:1,title:e.command},r(e.description),9,q)):o.key==="duration"?(i(),c(T,{key:2},[k(r(t.getDuration(e)),1)],64)):o.key==="createdAt"?(i(),c(T,{key:3},[k(r(t.formatTime(e.createdAt)),1)],64)):o.key==="result"?(i(),c(T,{key:4},[e.error?(i(),c("span",G,r(t.truncate(e.error,60)),1)):e.result?(i(),c("span",H,r(t.truncate(String(e.result),60)),1)):(i(),c("span",X,"-"))],64)):o.key==="action"?(i(),c(T,{key:5},[e.status==="running"?(i(),S(v,{key:0,size:"small",danger:"",onClick:g=>t.store.stopTask(e.id)},{default:a(()=>[...l[5]||(l[5]=[k(" 停止 ",-1)])]),_:1},8,["onClick"])):x("v-if",!0)],64)):x("v-if",!0)]),_:1},8,["data-source","loading"])]),_:1})])}const st=E(L,[["render",Y],["__scopeId","data-v-da5ff6a2"],["__file","/tmp/cc-web-panel-i0C953/repo/packages/web-panel/src/views/Tasks.vue"]]);export{st as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Q as r}from"./index-GG_MXjSL.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-CefMqONH.js";import{a0 as t}from"./index-GG_MXjSL.js";import"./vendor-Bn1JzzAn.js";import"./index-CBwQwtsE.js";import"./icons-DG5UD-6K.js";const s=t(o);export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-DtWQ5otv.js";import{a0 as t}from"./index-GG_MXjSL.js";import"./vendor-Bn1JzzAn.js";import"./responsiveObserve-C064Ubmu.js";import"./useFlexGapSupport-DJsIaU2S.js";import"./styleChecker-Cxz3wPL7.js";import"./index-CBwQwtsE.js";import"./icons-DG5UD-6K.js";const l=t(o);export{l as default};
|