chainlesschain 0.162.165 → 0.162.167
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-DgGZr3PR.js → AIOps-BZJrchIA.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BAOgBIc_.js → ActionButton-Bhlrylt7.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Ds4GAvNF.js → Analytics-pHtXVQYs.js} +2 -2
- package/src/assets/web-panel/assets/{AppLayout-CoJvCkoF.js → AppLayout-ORpuri4R.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-6EgUaE1T.js → Artifacts-eC77yr1_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BYie_i74.js → Audit-B2dZIiqz.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D5gxOhjd.js → BackgroundAgents-COZiTiwP.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CIsVK2pT.js → Backup-vY_Srl5d.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-ClorP55M.js → BaseInput-Dili5BdM.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CnhTPGGA.js → Chat-EzKBf0XL.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Bl1VXgwp.js → ChatBubbleRenderer-D1CtRAyy.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BRavl7TP.js → Checkbox-Beh6BmuW.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BXg_ErNT.js → Codegen-C3fA6kBU.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CfDPzFPq.js → Col-CefMqONH.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Cgo0httP.js → Community-CBAxFJtB.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DU5JcEQM.js → Compact--flHc-sM.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DCH_TVBl.js → Compliance-CPeNLvA6.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-IGb5O2IH.js → Cowork-Bv5yv4BU.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CPp_Xp9F.js → Cron-C22yMEas.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Cwrqklzw.js → Crosschain-Dsb2bcpu.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D55sBQwM.js → DID-DAxei4w0.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CedXhGmP.js → Dashboard-DEUwuVZ8.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Dm6_v3V4.js → Dropdown-BVp4si2j.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CWjnuE3G.js → EmailListRenderer-CyFkybOG.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DubTh7y-.js → FamilyGuardDashboard-BWmmsbVx.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DlSM4uJv.js → Federation-Cxw27A5d.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BYhg0vtG.js → FormItemContext-Q9XthzL1.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Bkh7qjfK.js → GenericCardRenderer-DS5DIdsW.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DSLWPKvn.js → Git-BOliHfxP.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DIj9O8BB.js → Governance-CD4oxa-W.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dhep3e5Y.js → Inference-CMlcivo8.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cj8vzxB_.js → KnowledgeGraph-BwhERcC4.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Ba4SsPja.js → Logs-BjVcZR5P.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BfRhXdyG.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CGs9IIbf.js → Marketplace-DQLU3E2w.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BTPAoX4K.js → McpTools-CeK0XkpB.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-BJ6ISf2c.js → Memory-DLFkgwaz.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Ca6n3Dcn.js → MobileBridge-Bh6ymXyj.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-lvilHuLt.js → MobileProjects-D950tUIe.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CMo0acBV.js → Mtc-Bx5x9_2m.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-Hz5wBvFX.js → MtcAudit-a1-Fexsq.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BK2aKWE6.js → Multisig-eaw0X8X1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CExpnYMI.js → NLProgramming-BaNsPV4k.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B7IFbuBo.js → Notes-C7pevN2X.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-VrGchtb0.js → NotificationSettings-HDqeoP0r.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CyrNTxkU.js → OrderTableRenderer-DvzVl5T3.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-I0C17GBP.js → Organization-D_xHDlGW.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CXcWvERe.js → Overflow-B5sRnueL.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-FFSCXrZq.js → P2P-C-IRjOPW.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-1PB-p8Zk.js → PdhVaultBrowser-BqgUPlcU.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C1YHejsb.js → Permissions-Bm_T1uWw.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CEMPpgf8.js → PersonalDataHub-DujDllye.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-FoIScdLr.js → Pipeline-DyNPOLIG.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DDfbEzEj.js → Privacy-CYKTW3iK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dso4kB0O.js → ProjectInit-CGf03uZ0.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-WvDoydDc.js → ProjectSettings-DIec4bTI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-NJp0kzkd.js → Projects-BY43-bmi.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BuJXnOLI.js → Providers-RrnUmgPk.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Bb3lMvGG.js → QrScannerModal-BBWfqd4y.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Ddxra3fK.js → QuickAsk-BsICSrFp.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BW-dR9qw.js → Recommend-B8y0b4ys.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Hnm7-Qkm.js → RemoteSession-0QgdB1Oe.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DKz6meHE.js → Reputation-DBJGM0YO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BuAsoNTS.js → Row-DtWQ5otv.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-_do9DMIH.js → RssFeed-2zBxHd5H.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CMlcw7ND.js → Search-BofliSkZ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DhAkfSpM.js → Security-ockRBBEL.js} +3 -3
- package/src/assets/web-panel/assets/{Services-5zKLhy46.js → Services-QyvG7Vd0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DCMZ3wfv.js → Skeleton-DwbOndX3.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DxQgYCC_.js → Skills-cHWa63sZ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CJmE4cSN.js → Sla-BHnTEydQ.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BgpRTPQp.js → SpeechSettings-DE2hrrLb.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DkogtYbB.js → SyncSettings-CZ9vnbJH.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-DWgoAHvM.js +1 -0
- package/src/assets/web-panel/assets/{Templates-DAZIu5nN.js → Templates-DiR3ad4X.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BRJMI-su.js → Tenant-NqcW3frV.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-iYeqRQZ0.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D4z9aSGD.js → TimelineRenderer-C5GOoxFz.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-zgYA4UOI.js → Tokens-82dz0XdU.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DMOgHX4m.js → Trigger-B3JCNrOi.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CEtoNwcT.js → Trust-BehFYsN_.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DFx2pQfO.js → UkeySign-BfOxJjVf.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DLssy-7B.js → VideoEditing-DdITCCPz.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DQHc6gTl.js → Wallet-B0EhkCmD.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DgKcODkn.js → WebAuthn-DJ4i1f3-.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-cPEWfMOf.js → WorkflowEditor-Dr9XTqIT.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Coj7rSO1.js → chat-Dc2nFyOj.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DiyGfr-6.js → colors-Drw9djBR.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DB63aMXh.js → compact-item-BdLXbU52.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CENpsYHg.js → createContext-BpQMZiWY.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CnfpDzMr.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-B9NOmk0K.js → hasIn-CbYwawHf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvQq6gX2.js → index-B1ANzVc6.js} +1 -1
- package/src/assets/web-panel/assets/{index-mTK_ZHhE.js → index-B3uRI8_y.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_rZCxxI.js → index-B5KboakZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAMKhjtT.js → index-B9_u4Qhe.js} +1 -1
- package/src/assets/web-panel/assets/{index-7IMjHwGU.js → index-BAq-4KqY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqLC0iE4.js → index-BBueKSTR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Kp2AETEw.js → index-BIcEW07n.js} +1 -1
- package/src/assets/web-panel/assets/{index-KDCuTzdx.js → index-BWUoc9-s.js} +1 -1
- package/src/assets/web-panel/assets/{index-nio98wGC.js → index-BZxzdAI0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxvNtndl.js → index-BiGDrEt4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B45osqnZ.js → index-Blv7c80V.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpmTl8QC.js → index-BmQlot_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-DANoIqXP.js → index-Bo_KwJTF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg0v-CXZ.js → index-Bu8Vy-mj.js} +1 -1
- package/src/assets/web-panel/assets/{index-U_snupDl.js → index-C1eo1Qkd.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClEy1v1o.js → index-C3Alz2QD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bvj07Ab1.js → index-CBwQwtsE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKNt2vfs.js → index-CJQiSQw7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXRknr9W.js → index-CKmz3Is-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRhEJ8JO.js → index-COoIIMbO.js} +1 -1
- package/src/assets/web-panel/assets/index-CYTEB0tb.js +1 -0
- package/src/assets/web-panel/assets/index-CgsEp5bm.js +1 -0
- package/src/assets/web-panel/assets/{index-CxVfbuj9.js → index-CpmlTfpv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmNCDN5t.js → index-D7Ipfs4F.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0C6zl0y.js → index-DHMeEu-P.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsPDEHOg.js → index-DKQlF7Pw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Yb9EfUnY.js → index-DO7LD_1t.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvTJ-x6b.js → index-DSmZjrFy.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9d8hdgY.js → index-DTeqWdAS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Y_UKQpsV.js → index-DWUN8c01.js} +1 -1
- package/src/assets/web-panel/assets/{index-t6hXF2Cw.js → index-D_lkTnZ0.js} +1 -1
- package/src/assets/web-panel/assets/{index-VDFbduzG.js → index-DyU21xVi.js} +1 -1
- package/src/assets/web-panel/assets/{index-76GMjcbq.js → index-GG_MXjSL.js} +3 -3
- package/src/assets/web-panel/assets/{index-BramLq29.js → index-IG3__pGj.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXzMKVLp.js → index-UX_Mfyfv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwkK9Kl2.js → index-VIyNlXPX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAXouogg.js → index-XYe6kBmi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTuX_MU0.js → index-_vVucYqC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkoqtJzV.js → index-aHrUfrv1.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-GTwJVIOz.js → initDefaultProps-DybC85E4.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BJQLsPx8.js → motion-BNNuyDg7.js} +1 -1
- package/src/assets/web-panel/assets/{move-DVQM0bdG.js → move-Bm8gSjEN.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CMXI1I2y.js → mtc-parser-CuHQvzzr.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CAc8MDw9.js → omit-lv4NO7Ng.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BgqzoyP7.js → pickAttrs-BoSMfjHq.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B9ebCdRy.js → placementArrow-BOMDSvgz.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Dy8D0D3n.js → responsiveObserve-C064Ubmu.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Bcrc8J39.js → slide-CeqhbKoG.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CDW6FOlc.js → statusUtils-CunFoYww.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CWhJrDON.js → styleChecker-Cxz3wPL7.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C82c33XI.js → useFlexGapSupport-DJsIaU2S.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-A6m--mih.js → useFs-DnAygceJ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-m-1laJY5.js → usePersonalDataHub-CrEUY7ta.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CL9oKKRa.js → vnode-Cq3rN2eT.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DrOyaof3.js → zoom-TMzcOx__.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +75 -0
- package/src/commands/session.js +132 -0
- package/src/data/changelog.json +12 -2
- package/src/harness/jsonl-session-store.js +9 -0
- package/src/harness/session-mirror.js +212 -6
- package/src/lib/async-hook-queue.cjs +288 -0
- package/src/lib/async-hook-supervisor.cjs +52 -0
- package/src/lib/background-session-transport.js +24 -2
- package/src/lib/doctor-checkup.js +184 -4
- package/src/lib/governance-coverage.js +179 -0
- package/src/lib/install-command-policy.js +333 -0
- package/src/lib/jsonl-session-store.js +1 -0
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +27 -0
- package/src/lib/lsp/lsp-server-registry.js +14 -0
- package/src/lib/packer/smoke-runner.js +85 -15
- package/src/lib/protocol-replay.js +153 -0
- package/src/lib/runtime-checkup.js +33 -0
- package/src/lib/settings-hook-events.cjs +157 -0
- package/src/lib/settings-hooks.cjs +4 -0
- package/src/lib/shell-approval.js +47 -1
- package/src/repl/add-dir.js +59 -1
- package/src/repl/agent-repl.js +85 -3
- package/src/runtime/agent-core.js +35 -0
- package/src/runtime/headless-runner.js +69 -1
- package/src/runtime/headless-stream.js +22 -0
- package/src/runtime/system-prompt.js +39 -12
- package/src/assets/web-panel/assets/MarkdownRenderer-DUjyuVB3.js +0 -1
- package/src/assets/web-panel/assets/Tasks-D5OrwAl9.js +0 -1
- package/src/assets/web-panel/assets/Terminal-CMXLqQKF.js +0 -3
- package/src/assets/web-panel/assets/devWarning-XvRaIiyt.js +0 -1
- package/src/assets/web-panel/assets/index-CbO1zSXV.js +0 -1
- package/src/assets/web-panel/assets/index-aCu2gbUb.js +0 -1
|
@@ -26,6 +26,11 @@ import {
|
|
|
26
26
|
import { execSync, spawnSync } from "node:child_process";
|
|
27
27
|
import { join, basename } from "node:path";
|
|
28
28
|
import { getHomeDir, getConfigPath } from "./paths.js";
|
|
29
|
+
import {
|
|
30
|
+
languageIdForFile,
|
|
31
|
+
resolveServer,
|
|
32
|
+
describeServer,
|
|
33
|
+
} from "./lsp/lsp-server-registry.js";
|
|
29
34
|
import {
|
|
30
35
|
checkAgenda,
|
|
31
36
|
checkInstructionFiles,
|
|
@@ -33,6 +38,8 @@ import {
|
|
|
33
38
|
checkHooks,
|
|
34
39
|
checkSandbox,
|
|
35
40
|
checkDuplicateSkills,
|
|
41
|
+
checkLspReadiness,
|
|
42
|
+
checkOrphanProcesses,
|
|
36
43
|
DEFAULT_CHECKUP_THRESHOLDS,
|
|
37
44
|
} from "./runtime-checkup.js";
|
|
38
45
|
|
|
@@ -604,16 +611,84 @@ async function worktreeSection(opts, deps) {
|
|
|
604
611
|
|
|
605
612
|
// ── runtime checkup: agenda expiry + verbose instruction files ──────────────
|
|
606
613
|
// Only the gaps the OTHER sections don't already cover. Stale sessions,
|
|
607
|
-
// worktrees
|
|
608
|
-
// transcriptSection / worktreeSection / backgroundSection — surfacing
|
|
609
|
-
// too would double-report
|
|
610
|
-
//
|
|
614
|
+
// worktrees and lost background agents (worker STATUS) are handled by
|
|
615
|
+
// transcriptSection / worktreeSection / backgroundSection — surfacing those
|
|
616
|
+
// here too would double-report. This section covers the agenda schedule store,
|
|
617
|
+
// instruction files (cc.md / AGENTS.md / CLAUDE.md), and — distinct from
|
|
618
|
+
// backgroundSection's worker-status check — leaked agent CHILD subprocesses
|
|
619
|
+
// (a per-turn agentPid still alive after its worker died), probed via a static
|
|
620
|
+
// one-shot PID-liveness check and the shared checkOrphanProcesses evaluator.
|
|
611
621
|
const SEVERITY_TO_LEVEL = {
|
|
612
622
|
error: CHECK_LEVELS.ERR,
|
|
613
623
|
warn: CHECK_LEVELS.WARN,
|
|
614
624
|
info: CHECK_LEVELS.INFO,
|
|
615
625
|
};
|
|
616
626
|
|
|
627
|
+
// Heavy / generated directories a project-language scan must never descend into
|
|
628
|
+
// (they'd dominate the budget and aren't the user's source).
|
|
629
|
+
const LSP_SCAN_SKIP_DIRS = new Set([
|
|
630
|
+
"node_modules",
|
|
631
|
+
"dist",
|
|
632
|
+
"build",
|
|
633
|
+
"out",
|
|
634
|
+
"target",
|
|
635
|
+
"coverage",
|
|
636
|
+
"vendor",
|
|
637
|
+
"venv",
|
|
638
|
+
"__pycache__",
|
|
639
|
+
]);
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Bounded shallow walk of a project root, counting source files per LSP
|
|
643
|
+
* languageId (via `languageIdForFile`). Deliberately capped by total entries
|
|
644
|
+
* visited AND depth so `cc doctor` stays fast on a huge monorepo; heavy build /
|
|
645
|
+
* vendor dirs and dot-dirs are skipped. fs access goes through injected `deps`
|
|
646
|
+
* (readdirSync/statSync) so it's unit-testable. Returns a Map languageId→count.
|
|
647
|
+
*/
|
|
648
|
+
function scanProjectLanguages(
|
|
649
|
+
root,
|
|
650
|
+
deps,
|
|
651
|
+
{ maxEntries = 20000, maxDepth = 8 } = {},
|
|
652
|
+
) {
|
|
653
|
+
const counts = new Map();
|
|
654
|
+
let visited = 0;
|
|
655
|
+
const stack = [{ dir: root, depth: 0 }];
|
|
656
|
+
while (stack.length && visited < maxEntries) {
|
|
657
|
+
const { dir, depth } = stack.pop();
|
|
658
|
+
let names;
|
|
659
|
+
try {
|
|
660
|
+
names = deps.readdirSync(dir);
|
|
661
|
+
} catch {
|
|
662
|
+
continue; // unreadable dir — skip, never crash the doctor
|
|
663
|
+
}
|
|
664
|
+
for (const name of names) {
|
|
665
|
+
if (visited >= maxEntries) break;
|
|
666
|
+
visited += 1;
|
|
667
|
+
const lang = languageIdForFile(name);
|
|
668
|
+
if (lang) {
|
|
669
|
+
counts.set(lang, (counts.get(lang) || 0) + 1);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
// Not a source file — maybe a directory to descend (bounded). Skip heavy
|
|
673
|
+
// build/vendor trees and dot-dirs (rarely hold the user's own source).
|
|
674
|
+
if (
|
|
675
|
+
depth < maxDepth &&
|
|
676
|
+
!LSP_SCAN_SKIP_DIRS.has(name) &&
|
|
677
|
+
!String(name).startsWith(".")
|
|
678
|
+
) {
|
|
679
|
+
let isDir = false;
|
|
680
|
+
try {
|
|
681
|
+
isDir = deps.statSync(join(dir, name)).isDirectory();
|
|
682
|
+
} catch {
|
|
683
|
+
isDir = false;
|
|
684
|
+
}
|
|
685
|
+
if (isDir) stack.push({ dir: join(dir, name), depth: depth + 1 });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return counts;
|
|
690
|
+
}
|
|
691
|
+
|
|
617
692
|
async function runtimeSection(opts, deps) {
|
|
618
693
|
const checks = [];
|
|
619
694
|
const now = deps.now();
|
|
@@ -789,6 +864,111 @@ async function runtimeSection(opts, deps) {
|
|
|
789
864
|
checks.push(failedCheck("sandbox", "sandbox availability", err));
|
|
790
865
|
}
|
|
791
866
|
|
|
867
|
+
// LSP readiness — languages the project actually contains but for which no
|
|
868
|
+
// language server is installed: the silent reason `code_intelligence` /
|
|
869
|
+
// `cc code-intel` degrades to plain text search. A STATIC install-gap check
|
|
870
|
+
// (no server is started); the project scan is bounded so it stays fast.
|
|
871
|
+
try {
|
|
872
|
+
const root = opts.cwd || process.cwd();
|
|
873
|
+
const langCounts = scanProjectLanguages(root, deps);
|
|
874
|
+
if (langCounts.size > 0) {
|
|
875
|
+
const languages = [];
|
|
876
|
+
for (const [languageId, fileCount] of langCounts) {
|
|
877
|
+
const resolved = resolveServer(languageId, root);
|
|
878
|
+
const desc = describeServer(languageId);
|
|
879
|
+
languages.push({
|
|
880
|
+
languageId,
|
|
881
|
+
fileCount,
|
|
882
|
+
available: !!resolved,
|
|
883
|
+
serverId: (resolved && resolved.id) || (desc && desc.id) || null,
|
|
884
|
+
exampleBin: desc && desc.bins ? desc.bins[0] : null,
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
for (const f of checkLspReadiness(languages)) {
|
|
888
|
+
checks.push(
|
|
889
|
+
check(
|
|
890
|
+
f.id,
|
|
891
|
+
`lsp ${f.ref}`,
|
|
892
|
+
SEVERITY_TO_LEVEL[f.severity] || CHECK_LEVELS.INFO,
|
|
893
|
+
`${f.message} — ${f.remediation}`,
|
|
894
|
+
),
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
} catch (err) {
|
|
899
|
+
checks.push(failedCheck("lsp-readiness", "lsp server readiness", err));
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Orphaned agent subprocesses — a background worker died but its per-turn
|
|
903
|
+
// agent CHILD (the LLM/tool subprocess recorded as `agentPid`) is still
|
|
904
|
+
// alive: a leaked process nothing reaped. backgroundSection reports the
|
|
905
|
+
// worker's STATUS; this probes the actual child PID's liveness (static,
|
|
906
|
+
// one-shot, anchored on the process start time to defeat PID reuse) and
|
|
907
|
+
// feeds the shared checkOrphanProcesses evaluator. Only PIDs we recorded are
|
|
908
|
+
// probed → no false positives, no OS-wide process-table scan. Tests inject
|
|
909
|
+
// opts.backgroundProcesses / opts.activeSessionIds (mirrors
|
|
910
|
+
// opts.skillLayerEntries below).
|
|
911
|
+
try {
|
|
912
|
+
let processes = opts.backgroundProcesses;
|
|
913
|
+
let activeSessionIds = opts.activeSessionIds;
|
|
914
|
+
if (!processes) {
|
|
915
|
+
const bgMod = await import("./background-agent-supervisor.js");
|
|
916
|
+
const agents = bgMod.listBackgroundAgents({ all: true }) || [];
|
|
917
|
+
activeSessionIds = agents
|
|
918
|
+
.filter((a) => a.status === "running")
|
|
919
|
+
.map((a) => a.sessionId)
|
|
920
|
+
.filter(Boolean);
|
|
921
|
+
processes = [];
|
|
922
|
+
for (const a of agents) {
|
|
923
|
+
let state;
|
|
924
|
+
try {
|
|
925
|
+
state = bgMod.readBackgroundAgentState(a.id);
|
|
926
|
+
} catch {
|
|
927
|
+
continue; // unreadable/raced state file — skip
|
|
928
|
+
}
|
|
929
|
+
const agentPid = Number(state?.agentPid);
|
|
930
|
+
if (!Number.isInteger(agentPid) || agentPid <= 0) continue;
|
|
931
|
+
if (agentPid === Number(state?.pid)) continue; // that's the worker itself
|
|
932
|
+
// Alive AND still the same process we launched (not a reused PID).
|
|
933
|
+
const anchor = state.agentStartedAt || state.startedAt;
|
|
934
|
+
if (!bgMod.isSameProcess(agentPid, anchor)) continue; // dead → nothing to reap
|
|
935
|
+
const parentAlive = bgMod.isSameProcess(
|
|
936
|
+
Number(state.pid),
|
|
937
|
+
state.startedAt,
|
|
938
|
+
);
|
|
939
|
+
processes.push({
|
|
940
|
+
pid: agentPid,
|
|
941
|
+
alive: true,
|
|
942
|
+
parentAlive,
|
|
943
|
+
sessionId: state.sessionId || null,
|
|
944
|
+
kind: "agent-child",
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
for (const f of checkOrphanProcesses(processes, activeSessionIds || [])) {
|
|
949
|
+
const killCmd =
|
|
950
|
+
process.platform === "win32"
|
|
951
|
+
? `taskkill /PID ${f.ref} /T /F`
|
|
952
|
+
: `kill ${f.ref}`;
|
|
953
|
+
checks.push(
|
|
954
|
+
check(
|
|
955
|
+
f.id,
|
|
956
|
+
`process pid=${f.ref}`,
|
|
957
|
+
SEVERITY_TO_LEVEL[f.severity] || CHECK_LEVELS.WARN,
|
|
958
|
+
`${f.message} — ${f.remediation}`,
|
|
959
|
+
{
|
|
960
|
+
id: `reap-orphan-${f.ref}`,
|
|
961
|
+
safe: false,
|
|
962
|
+
description: `terminate leaked agent subprocess pid=${f.ref}`,
|
|
963
|
+
command: killCmd,
|
|
964
|
+
},
|
|
965
|
+
),
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
} catch (err) {
|
|
969
|
+
checks.push(failedCheck("orphan-process", "orphan agent processes", err));
|
|
970
|
+
}
|
|
971
|
+
|
|
792
972
|
// Duplicate skills — an id defined in more than one layer silently shadows
|
|
793
973
|
// (loadAll keeps only the winner), so a user's custom skill can override, or
|
|
794
974
|
// be overridden by, another without any signal. opts.skillLayerEntries lets a
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governance coverage metrics — the last open item of P1-9 ("覆盖率指标") in
|
|
3
|
+
* docs/CLAUDE_CODE_IDE_INCREMENTAL_GAP_ANALYSIS_2026-07-13.md, and the
|
|
4
|
+
* computation behind two §11.3 acceptance targets:
|
|
5
|
+
*
|
|
6
|
+
* - "高风险 Tool Call Ledger/Trace 覆盖率:100%"
|
|
7
|
+
* every high-risk (irreversible side-effecting) tool call MUST have a
|
|
8
|
+
* side-effect-ledger entry AND a trace span.
|
|
9
|
+
* - "Plugin/MCP/Skill/Hook 来源、版本、权限可追溯率:100%"
|
|
10
|
+
* every externally-sourced tool/skill call MUST carry full provenance
|
|
11
|
+
* (source + version + scope + a recorded permission decision).
|
|
12
|
+
*
|
|
13
|
+
* "High-risk" is NOT re-defined here — it is exactly what [[side-effect-ledger.js]]
|
|
14
|
+
* `classifyToolSideEffect` records (the ONE source), so this metric can't drift
|
|
15
|
+
* from what the ledger actually tracks. Provenance rows are the attribution
|
|
16
|
+
* records [[agent-tool-admission.js]] `buildToolAttribution` produces.
|
|
17
|
+
*
|
|
18
|
+
* PURE + deterministic: no fs / process / clock / RNG. The caller gathers a run's
|
|
19
|
+
* tool calls, the op-ids that got a ledger entry, the op-ids that got a trace
|
|
20
|
+
* span, and the attribution records; this reads back coverage ratios + the exact
|
|
21
|
+
* uncovered items so a gap is actionable, not just a number.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { classifyToolSideEffect } from "./side-effect-ledger.js";
|
|
25
|
+
|
|
26
|
+
/** Coverage ratio in [0,1]; an empty population is vacuously fully covered. */
|
|
27
|
+
function ratio(covered, total) {
|
|
28
|
+
return total === 0 ? 1 : covered / total;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Whether a tool call is high-risk (records an irreversible side effect). */
|
|
32
|
+
export function isHighRiskToolCall(call) {
|
|
33
|
+
return classifyToolSideEffect(call?.tool, call?.args || {}) != null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* High-risk tool-call ledger + trace coverage (§11.3 metric).
|
|
38
|
+
*
|
|
39
|
+
* @param {object} params
|
|
40
|
+
* @param {Array<{tool:string, args?:object, opId?:string}>} params.toolCalls
|
|
41
|
+
* every tool call the run issued (only high-risk ones enter the denominator)
|
|
42
|
+
* @param {Iterable<string>} [params.ledgerOpIds] op-ids that got a ledger entry
|
|
43
|
+
* @param {Iterable<string>} [params.tracedOpIds] op-ids that got a trace span
|
|
44
|
+
* @returns {{highRiskCount:number, ledgerCovered:number, traceCovered:number,
|
|
45
|
+
* ledgerCoverage:number, traceCoverage:number,
|
|
46
|
+
* uncoveredLedger:object[], uncoveredTrace:object[], ok:boolean}}
|
|
47
|
+
*/
|
|
48
|
+
export function computeSideEffectCoverage({
|
|
49
|
+
toolCalls = [],
|
|
50
|
+
ledgerOpIds = [],
|
|
51
|
+
tracedOpIds = [],
|
|
52
|
+
} = {}) {
|
|
53
|
+
const ledgerSet = new Set([...ledgerOpIds].map(String));
|
|
54
|
+
const traceSet = new Set([...tracedOpIds].map(String));
|
|
55
|
+
|
|
56
|
+
const highRisk = [];
|
|
57
|
+
(Array.isArray(toolCalls) ? toolCalls : []).forEach((call, index) => {
|
|
58
|
+
const cls = classifyToolSideEffect(call?.tool, call?.args || {});
|
|
59
|
+
if (!cls) return; // not high-risk — excluded from the denominator
|
|
60
|
+
const opId = call?.opId == null ? null : String(call.opId);
|
|
61
|
+
highRisk.push({
|
|
62
|
+
index,
|
|
63
|
+
tool: String(call?.tool || ""),
|
|
64
|
+
kind: cls.kind,
|
|
65
|
+
opId,
|
|
66
|
+
ledger: opId != null && ledgerSet.has(opId),
|
|
67
|
+
traced: opId != null && traceSet.has(opId),
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const total = highRisk.length;
|
|
72
|
+
const ledgerCovered = highRisk.filter((h) => h.ledger).length;
|
|
73
|
+
const traceCovered = highRisk.filter((h) => h.traced).length;
|
|
74
|
+
const pick = (h) => ({
|
|
75
|
+
index: h.index,
|
|
76
|
+
tool: h.tool,
|
|
77
|
+
kind: h.kind,
|
|
78
|
+
opId: h.opId,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
highRiskCount: total,
|
|
83
|
+
ledgerCovered,
|
|
84
|
+
traceCovered,
|
|
85
|
+
ledgerCoverage: ratio(ledgerCovered, total),
|
|
86
|
+
traceCoverage: ratio(traceCovered, total),
|
|
87
|
+
uncoveredLedger: highRisk.filter((h) => !h.ledger).map(pick),
|
|
88
|
+
uncoveredTrace: highRisk.filter((h) => !h.traced).map(pick),
|
|
89
|
+
ok: total === 0 ? true : ledgerCovered === total && traceCovered === total,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** An attribution is in the provenance denominator if it's externally sourced. */
|
|
94
|
+
function inProvenanceScope(attr) {
|
|
95
|
+
return Boolean(attr?.source) || String(attr?.tier || "") === "extension";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Plugin/MCP/Skill/Hook provenance traceability coverage (§11.3 metric). Only
|
|
100
|
+
* externally-sourced (or extension-tier) calls enter the denominator; a built-in
|
|
101
|
+
* mvp tool with no source is not part of this metric. An in-scope row is
|
|
102
|
+
* traceable only when source + version + scope are all present AND a permission
|
|
103
|
+
* decision was recorded (`admitted` is not null).
|
|
104
|
+
*
|
|
105
|
+
* @param {Array<object>} attributions buildToolAttribution() records
|
|
106
|
+
* @returns {{total:number, traceable:number, coverage:number,
|
|
107
|
+
* untraceable:Array<{index:number, tool:(string|null), missing:string[]}>,
|
|
108
|
+
* ok:boolean}}
|
|
109
|
+
*/
|
|
110
|
+
export function computeProvenanceCoverage(attributions = []) {
|
|
111
|
+
const rows = [];
|
|
112
|
+
(Array.isArray(attributions) ? attributions : []).forEach((attr, index) => {
|
|
113
|
+
if (!inProvenanceScope(attr)) return;
|
|
114
|
+
const missing = [];
|
|
115
|
+
if (!attr?.source) missing.push("source");
|
|
116
|
+
if (!attr?.version) missing.push("version");
|
|
117
|
+
if (!attr?.scope) missing.push("scope");
|
|
118
|
+
if (attr?.admitted == null) missing.push("permission");
|
|
119
|
+
rows.push({
|
|
120
|
+
index,
|
|
121
|
+
tool: attr?.tool ?? null,
|
|
122
|
+
traceable: missing.length === 0,
|
|
123
|
+
missing,
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const total = rows.length;
|
|
128
|
+
const traceable = rows.filter((r) => r.traceable).length;
|
|
129
|
+
return {
|
|
130
|
+
total,
|
|
131
|
+
traceable,
|
|
132
|
+
coverage: ratio(traceable, total),
|
|
133
|
+
untraceable: rows.filter((r) => !r.traceable),
|
|
134
|
+
ok: total === 0 ? true : traceable === total,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Format a ratio in [0,1] as a whole-or-1-decimal percentage string. */
|
|
139
|
+
function pct(r) {
|
|
140
|
+
const v = r * 100;
|
|
141
|
+
return (Number.isInteger(v) ? v.toFixed(0) : v.toFixed(1)) + "%";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Combine both metrics into one report + a fail-closed `ok` (both must be 100%).
|
|
146
|
+
*
|
|
147
|
+
* @param {object} params
|
|
148
|
+
* @param {Array} [params.toolCalls]
|
|
149
|
+
* @param {Iterable<string>} [params.ledgerOpIds]
|
|
150
|
+
* @param {Iterable<string>} [params.tracedOpIds]
|
|
151
|
+
* @param {Array} [params.attributions]
|
|
152
|
+
* @returns {{sideEffect:object, provenance:object, ok:boolean}}
|
|
153
|
+
*/
|
|
154
|
+
export function computeGovernanceCoverage({
|
|
155
|
+
toolCalls = [],
|
|
156
|
+
ledgerOpIds = [],
|
|
157
|
+
tracedOpIds = [],
|
|
158
|
+
attributions = [],
|
|
159
|
+
} = {}) {
|
|
160
|
+
const sideEffect = computeSideEffectCoverage({
|
|
161
|
+
toolCalls,
|
|
162
|
+
ledgerOpIds,
|
|
163
|
+
tracedOpIds,
|
|
164
|
+
});
|
|
165
|
+
const provenance = computeProvenanceCoverage(attributions);
|
|
166
|
+
return { sideEffect, provenance, ok: sideEffect.ok && provenance.ok };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** One-line, token-free summary of a governance coverage report. */
|
|
170
|
+
export function summarizeGovernanceCoverage(report) {
|
|
171
|
+
const se = report?.sideEffect || {};
|
|
172
|
+
const pr = report?.provenance || {};
|
|
173
|
+
return (
|
|
174
|
+
`high-risk ledger ${pct(se.ledgerCoverage ?? 1)} / trace ` +
|
|
175
|
+
`${pct(se.traceCoverage ?? 1)} (${se.highRiskCount ?? 0} calls) · ` +
|
|
176
|
+
`provenance ${pct(pr.coverage ?? 1)} (${pr.total ?? 0} sourced) · ` +
|
|
177
|
+
`${report?.ok ? "OK" : "GAPS"}`
|
|
178
|
+
);
|
|
179
|
+
}
|