chainlesschain 0.162.125 → 0.162.126
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-DcqNhZhA.js → AIOps-BrTOcqIJ.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BigtmPoq.js → ActionButton-na9cocmf.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-1J_X_HF4.js → Analytics-BtDygkpt.js} +2 -2
- package/src/assets/web-panel/assets/{AppLayout-DlcDG_a_.js → AppLayout-D_t5CS18.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-Do-y8_3w.js → Audit-BYMZccCy.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-S2Df-50Y.js → Backup-D2qDfAdL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D5kgWJfk.js → BaseInput-kj456Ju9.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-aUcp3kN1.js → Chat-BY0A0ZLE.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D1VvrOPQ.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DTg1U7Xs.js → Checkbox-DiBhtXsh.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-YO9ZZ4Ky.js → Codegen-B1ER0L0j.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BHonE9fU.js → Col-CjLmza7D.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DA2AlEFh.js → Community-BNId05U7.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DULxLRNg.js → Compact-BuuMj7K1.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BZqfuuZL.js → Compliance-DUuDycaJ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CJe3vyMS.js → Cowork-BKHiF6uL.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CeV8AtRu.js → Cron-C7p-lHnC.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CAg66zS5.js → Crosschain-BvSOx8a6.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Dtup5JZm.js → DID-D1k9jgHv.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DAR_8PNy.js → Dashboard-B9mCCnqY.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-K5bTaCYN.js → Dropdown-ge9UHSXF.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C890uErx.js → EmailListRenderer-TZO7ppXi.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-B-Tj_8yM.js → FamilyGuardDashboard-DkhLJmzx.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C6WZ98ni.js → Federation-JLuA_8zp.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-D-LTfGWd.js → FormItemContext-C4w-rzNg.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-C80DK4W7.js → GenericCardRenderer-Btns4sV9.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Cjvvv3zW.js → Git-BheXMjzC.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C0BND77H.js → Governance-D9rLlatH.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BL9kTtSu.js → Inference-DiklIMcd.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CnVTBmJf.js → KnowledgeGraph-C70EWL03.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CbCbg7K6.js → Logs-Zt_MLI10.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CG5On-fH.js → Marketplace-suQxES99.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-AYYDZZK7.js → McpTools-CclpCDpY.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-tMWbMDQq.js → Memory-B2lHOUwF.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BAOsf4wB.js → MobileBridge-BMXKoDAD.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BT-2komQ.js → MobileProjects-a6mWVdBV.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BFwfC63n.js → Mtc-BFpM4Fkj.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-DYG3CWdH.js → MtcAudit-DDQkxkbS.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-KJwd0yWT.js → Multisig-Crkd_zKQ.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BmL5dNWm.js → NLProgramming-Dpk5An7B.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DmkaVaMc.js → Notes-BrFnOMNz.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-tmVQszDZ.js → NotificationSettings-CM0iApFM.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BtrR7anf.js → OrderTableRenderer-XXjeqkdz.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-pppktQyW.js → Organization-CHFW_38T.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-D3lBoQDA.js → Overflow-C-vl3EjV.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BgE2qGlZ.js → P2P-BT7Slavq.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DRUaULap.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BR8no2Xe.js → Permissions-DkhOAvMz.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-DabbyQEF.js → PersonalDataHub-Dl7dSOvV.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-n4sNpEz8.js → Pipeline-B3nVI4p6.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CGNp4n8M.js → Privacy-Dv1SXx1Q.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CAVA5VsX.js → ProjectInit-DrAhVi5p.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-GCgkfM7A.js → ProjectSettings-h-ggCYN_.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BYK17p52.js → Projects-CM91hYdr.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DpUT5W-d.js → Providers-rfkZel3N.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-ZJxTb7vi.js → QuickAsk-XepZB7h_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CIzFRDk1.js → Recommend-DzQWsh1a.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-lQ_WDNZn.js → Reputation-CDeaal0j.js} +1 -1
- package/src/assets/web-panel/assets/{Row-1MEtrgtF.js → Row-BN4aKhFH.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-SSgcPPl4.js → RssFeed-INP6VYAA.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CcTMOGNY.js → Search-ChPbwatu.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BA1KMaDx.js → Security-C97ZCY8N.js} +3 -3
- package/src/assets/web-panel/assets/{Services-_aj7czZn.js → Services-Cbtl2Ajs.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BWgg_0Zr.js → Skeleton-B13sFxBQ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C2ZIziYM.js → Skills-vI9zSIKX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CYxp4axY.js → Sla-Cr3oBH39.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C7Csp1jV.js → SpeechSettings-BwemqPPV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-svGeswiw.js → SyncSettings-CLA78P-Z.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-ClISj6oK.js → Tasks-DBjQ_DOM.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CmO-Fp7r.js → Templates-BkSLDkBs.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-a3Ac3lxz.js → Tenant-Dn0nSlib.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DyJIRh81.js → Terminal-C8f4boru.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-acXS5N5h.js → TimelineRenderer-DW_rMtJR.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DJW0KqV4.js → Tokens-BdffrKYV.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-0HeTi4r6.js → Trigger-CX4CUg-Q.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-aFym34eo.js → Trust-Cq9Bl7Od.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CYhszHJv.js → UkeySign-BQy18_VY.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BbJxPF9X.js → VideoEditing-h5hzK7Vw.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DDthEwiu.js → Wallet-BLotT3gw.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-DQ6McYPg.js → WebAuthn-8cCANYLE.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-CnF8zRsi.js → WorkflowEditor-Db6NwtAv.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Dzkx2gTP.js → chat-BPk1LbpL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-35T51Oo5.js → colors-BnNal71p.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-TtzNrlu1.js → compact-item-W2VC0tcy.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Y1LkWrYb.js → createContext-DceVsgnZ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning--rwFDBhx.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BOYw1BgS.js → hasIn-BEq6EDcp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtlJWaSP.js → index-5gIBUFBn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLqC2sRT.js → index-APCHxOkM.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7Wt5feN.js → index-B2dMhwZi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqhwG1ox.js → index-B8cPjrEH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxWUEFKy.js → index-BDC5HsxZ.js} +1 -1
- package/src/assets/web-panel/assets/index-BPFuPGKi.js +1 -0
- package/src/assets/web-panel/assets/{index-NM9Oke2k.js → index-BUkDcIwJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWgNn9As.js → index-BWcCyH6-.js} +3 -3
- package/src/assets/web-panel/assets/{index-CVrUs6rf.js → index-BgZikQoh.js} +1 -1
- package/src/assets/web-panel/assets/index-Bwjus13Y.js +1 -0
- package/src/assets/web-panel/assets/{index-D6tG4B25.js → index-BzSzRWsw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjeUZxE5.js → index-C1K9CsGr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkG479D.js → index-CBZVISK6.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw1iOGhM.js → index-CEJN-R2L.js} +1 -1
- package/src/assets/web-panel/assets/{index-G4ClSmJc.js → index-CG5dGC9E.js} +1 -1
- package/src/assets/web-panel/assets/{index-D47robkX.js → index-CMGLpstm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKRlWHUp.js → index-CWrGCndd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhMSOd_2.js → index-CbcvfpCV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dx0hIfC-.js → index-Ceqv4lI2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdyFg4FI.js → index-CsT6frT8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7aKAZzS.js → index-D8PQKsDT.js} +1 -1
- package/src/assets/web-panel/assets/{index-8jffdb6b.js → index-DGncdA-j.js} +1 -1
- package/src/assets/web-panel/assets/{index-XIuZV9by.js → index-DHanQHO0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dhfw-BXs.js → index-DaUBk28E.js} +1 -1
- package/src/assets/web-panel/assets/{index-hyqEKkBT.js → index-Di2J4b4V.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAizH273.js → index-DtuLvWZN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPGNc2tF.js → index-DvS1J8xc.js} +1 -1
- package/src/assets/web-panel/assets/{index-KgXrlfNF.js → index-DxePJdwP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFhlelzN.js → index-Et4XvL49.js} +1 -1
- package/src/assets/web-panel/assets/{index-zF77jnI2.js → index-GlFxgcj4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs82BHAj.js → index-HV119Oui.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dof7lWA_.js → index-InGW87pj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs69SI96.js → index-P1-s8JR7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4BgCBa3.js → index-SdABCNoi.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSpFe6j5.js → index-WTAZbN-c.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7dCBw_M.js → index-_2I-KzOj.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGPEaeB1.js → index-m1sVaWVU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ16GlOs.js → index-s37wwyeN.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2od7Bgx.js → index-tyWABqp9.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DD5y5msp.js → initDefaultProps-DzrCDb3j.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BuoutMia.js → motion-BQERVnE3.js} +1 -1
- package/src/assets/web-panel/assets/{move-DkpjqOXg.js → move-I9ACA5XJ.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BmGJD-v-.js → mtc-parser-Dd2Pw-tr.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DftUE0Sz.js → omit-DwzYRzWV.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DDRb9FIu.js → pickAttrs-BSGULyIL.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DPgtxOOD.js → placementArrow-tSYYjAts.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BQFRzFeZ.js → responsiveObserve-Dy2lqikT.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DQ4lmUSz.js → slide-RaB4Uq0c.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C1TR4ZiQ.js → statusUtils-CBpC_wZg.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B-Suj978.js → styleChecker-BEKwPWt5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Q7bDZ3EI.js → useFlexGapSupport-C4CnYJH1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DHjRLyQH.js → useFs-n24jutw5.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-lQOvCvCr.js → usePersonalDataHub-DMgS8F6G.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Ie0g4-p3.js → vnode-BSp2KYcj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CHP0YEoH.js → zoom-7UfQtTPh.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +41 -2
- package/src/commands/compliance.js +3 -1
- package/src/commands/review.js +47 -17
- package/src/commands/session.js +11 -2
- package/src/gateways/ws/message-dispatcher.js +145 -165
- package/src/gateways/ws/ws-session-gateway.js +39 -5
- package/src/harness/jsonl-session-store.js +39 -12
- package/src/harness/worktree-isolator.js +5 -0
- package/src/lib/agent-core.js +1 -0
- package/src/lib/audit-logger.js +3 -1
- package/src/lib/chat-core.js +5 -2
- package/src/lib/chat-intent-service.js +68 -21
- package/src/lib/config-manager.js +25 -1
- package/src/lib/credential-guard.js +43 -1
- package/src/lib/git-integration.js +5 -0
- package/src/lib/interaction-adapter.js +32 -11
- package/src/lib/jsonl-session-store.js +1 -0
- package/src/lib/llm-config-defaults.js +37 -0
- package/src/lib/mcp-oauth.js +76 -10
- package/src/lib/permission-engine.js +4 -1
- package/src/lib/pipeline-orchestrator.js +20 -2
- package/src/lib/project-instructions.js +13 -0
- package/src/lib/repl-denials.js +137 -0
- package/src/lib/safe-json.js +22 -0
- package/src/lib/sandbox-v2.js +7 -6
- package/src/lib/search-command.js +65 -0
- package/src/lib/settings-hooks.cjs +133 -0
- package/src/lib/settings-loader.cjs +16 -7
- package/src/lib/social-graph.js +3 -1
- package/src/lib/stream-retry.js +27 -0
- package/src/lib/turn-context.js +15 -5
- package/src/repl/agent-repl.js +81 -8
- package/src/runtime/__tests__/message-roles.test.js +36 -3
- package/src/runtime/agent-core.js +175 -50
- package/src/runtime/coding-agent-contract-shared.cjs +9 -2
- package/src/runtime/coding-agent-shell-policy.cjs +23 -2
- package/src/runtime/file-ref-expander.js +51 -7
- package/src/runtime/headless-runner.js +83 -2
- package/src/runtime/headless-stream.js +69 -3
- package/src/runtime/mcp-config.js +42 -1
- package/src/runtime/message-roles.js +14 -1
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Pg7dIsiE.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-D26Bz5gS.js +0 -7
- package/src/assets/web-panel/assets/devWarning-D_lwLZ6O.js +0 -1
- package/src/assets/web-panel/assets/index-CEwuCM44.js +0 -1
- package/src/assets/web-panel/assets/index-DzzgU4IU.js +0 -1
package/src/lib/social-graph.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { EventEmitter } from "events";
|
|
25
|
+
import { safeJsonParse } from "./safe-json.js";
|
|
25
26
|
|
|
26
27
|
/* ── Edge types ────────────────────────────────────────────── */
|
|
27
28
|
|
|
@@ -325,7 +326,8 @@ export function loadFromDb(db) {
|
|
|
325
326
|
)
|
|
326
327
|
.all();
|
|
327
328
|
for (const row of rows) {
|
|
328
|
-
|
|
329
|
+
// A single corrupt metadata cell must not crash the whole graph load.
|
|
330
|
+
const metadata = safeJsonParse(row.metadata, null);
|
|
329
331
|
// Hydrate without re-emitting events (bulk load).
|
|
330
332
|
_hydrateEdge({
|
|
331
333
|
sourceDid: row.source_did,
|
package/src/lib/stream-retry.js
CHANGED
|
@@ -18,6 +18,33 @@ import { isAbortError } from "./abort-utils.js";
|
|
|
18
18
|
export const STREAM_RETRY_MAX = 2;
|
|
19
19
|
export const STREAM_RETRY_BASE_MS = 400;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Hard ceiling on the *configurable* retry budget (Claude-Code 2.1.186:
|
|
23
|
+
* "CLAUDE_CODE_MAX_RETRIES capped at 15") — keeps a stray huge value from
|
|
24
|
+
* turning a dead endpoint into a multi-minute exponential-backoff hang.
|
|
25
|
+
*/
|
|
26
|
+
export const STREAM_RETRY_MAX_CAP = 15;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the streaming-retry budget. Users can raise (or lower) the default
|
|
30
|
+
* via `CC_MAX_RETRIES` (native) or `CLAUDE_CODE_MAX_RETRIES` (Claude-Code
|
|
31
|
+
* parity); the value is clamped to `[0, STREAM_RETRY_MAX_CAP]`. Unset / blank /
|
|
32
|
+
* non-numeric falls back to the default `STREAM_RETRY_MAX`; a negative value
|
|
33
|
+
* clamps to 0 (retries disabled). `CC_MAX_RETRIES` wins when both are set.
|
|
34
|
+
*
|
|
35
|
+
* @param {Record<string,string|undefined>} [env=process.env]
|
|
36
|
+
* @returns {number}
|
|
37
|
+
*/
|
|
38
|
+
export function resolveStreamRetryMax(env = process.env) {
|
|
39
|
+
const raw = env.CC_MAX_RETRIES ?? env.CLAUDE_CODE_MAX_RETRIES;
|
|
40
|
+
if (raw == null || String(raw).trim() === "") return STREAM_RETRY_MAX;
|
|
41
|
+
const n = Number.parseInt(String(raw).trim(), 10);
|
|
42
|
+
if (!Number.isFinite(n)) return STREAM_RETRY_MAX;
|
|
43
|
+
if (n < 0) return 0;
|
|
44
|
+
if (n > STREAM_RETRY_MAX_CAP) return STREAM_RETRY_MAX_CAP;
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
|
|
21
48
|
/**
|
|
22
49
|
* Is this error from a streaming chat request a transient API CONNECTION drop
|
|
23
50
|
* that is safe to retry? True only for genuine network failures (reset /
|
package/src/lib/turn-context.js
CHANGED
|
@@ -30,6 +30,9 @@ function _git(cmd, cwd) {
|
|
|
30
30
|
encoding: "utf-8",
|
|
31
31
|
stdio: ["ignore", "pipe", "ignore"],
|
|
32
32
|
timeout: 1500,
|
|
33
|
+
// `status --porcelain` on a dirty repo with many files can exceed the
|
|
34
|
+
// 1 MB execSync default → ENOBUFS → null → "(clean)" misreport below.
|
|
35
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
33
36
|
})
|
|
34
37
|
.trim();
|
|
35
38
|
} catch (_e) {
|
|
@@ -61,11 +64,18 @@ export function buildTurnContext({
|
|
|
61
64
|
if (branch) {
|
|
62
65
|
const head = _git("rev-parse --short HEAD", cwd);
|
|
63
66
|
const status = _git("status --porcelain", cwd);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
67
|
+
// Distinguish "command failed" (null — timeout / huge output) from "" (truly
|
|
68
|
+
// clean): the old `status && …` reported a repo as "(clean)" whenever status
|
|
69
|
+
// couldn't be determined, which is a wrong signal to the model.
|
|
70
|
+
let stateLabel;
|
|
71
|
+
if (status === null) {
|
|
72
|
+
stateLabel = " (status unknown)";
|
|
73
|
+
} else if (status.length > 0) {
|
|
74
|
+
stateLabel = ` (${status.split("\n").filter(Boolean).length} uncommitted)`;
|
|
75
|
+
} else {
|
|
76
|
+
stateLabel = " (clean)";
|
|
77
|
+
}
|
|
78
|
+
lines.push(`- git: ${branch}@${head || "?"}${stateLabel}`);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
if (sessionId) {
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -29,6 +29,11 @@ import {
|
|
|
29
29
|
analyzeContinuation,
|
|
30
30
|
joinContinuation,
|
|
31
31
|
} from "../lib/repl-multiline.js";
|
|
32
|
+
import {
|
|
33
|
+
classifyDenial,
|
|
34
|
+
recordDenial,
|
|
35
|
+
formatDenials,
|
|
36
|
+
} from "../lib/repl-denials.js";
|
|
32
37
|
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
33
38
|
import {
|
|
34
39
|
createSession,
|
|
@@ -118,6 +123,14 @@ let _settingsHooks = null;
|
|
|
118
123
|
// `!command` auto-triggers an assistant response to its output. undefined =
|
|
119
124
|
// unset → defaults OFF (opt-in) in shouldRespondToBashCommands.
|
|
120
125
|
let _respondToBash;
|
|
126
|
+
// .claude/settings.json `autoMode.classifyAllShell` (Claude-Code 2.1.193): route
|
|
127
|
+
// the built-in verification allowlist through the shell-policy classifier (→
|
|
128
|
+
// ApprovalGate confirm) instead of fast-pathing it. false = unset → off.
|
|
129
|
+
let _classifyAllShell = false;
|
|
130
|
+
// Bounded log of tool calls the agent was BLOCKED from running this session
|
|
131
|
+
// (shell-policy / ApprovalGate / settings rule / hook). Surfaced by
|
|
132
|
+
// `/permissions denials` (Claude-Code 2.1.193 "recent denials"). In-memory only.
|
|
133
|
+
const _recentDenials = [];
|
|
121
134
|
|
|
122
135
|
/**
|
|
123
136
|
* Fire settings.json Notification hooks (observe-only) — the agent needs the
|
|
@@ -180,13 +193,17 @@ async function executeTool(name, args) {
|
|
|
180
193
|
permissionRules: _permissionRules,
|
|
181
194
|
permissionConfirm: _permissionConfirm,
|
|
182
195
|
settingsHooks: _settingsHooks,
|
|
196
|
+
classifyAllShell: _classifyAllShell,
|
|
183
197
|
});
|
|
184
198
|
}
|
|
185
199
|
|
|
186
200
|
/**
|
|
187
201
|
* Agentic loop — wraps agent-core's async generator with REPL display output.
|
|
202
|
+
* Exported so its event-translation contract (checkpoint-mark accuracy for
|
|
203
|
+
* `/rewind`, content/usage extraction, forced-off in-loop compaction) is
|
|
204
|
+
* unit-testable via the `options._coreLoop` injection seam.
|
|
188
205
|
*/
|
|
189
|
-
async function agentLoop(messages, options) {
|
|
206
|
+
export async function agentLoop(messages, options) {
|
|
190
207
|
// Resume-degenerate role merge (Claude Code 2.1.187 parity), gated by the
|
|
191
208
|
// one-shot `mergeRoles` flag so it fires only on the first model call after
|
|
192
209
|
// resuming a session whose prior run produced no assistant response. Collapse
|
|
@@ -212,12 +229,19 @@ async function agentLoop(messages, options) {
|
|
|
212
229
|
`\n ⚠️ ${info.message || `已从 "${info.from}" 切换到 "${info.to}"`}\n`,
|
|
213
230
|
),
|
|
214
231
|
));
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
232
|
+
// `_coreLoop` is an injectable seam (defaults to agent-core's loop) so the
|
|
233
|
+
// wrapper's event translation can be unit-tested without a live model.
|
|
234
|
+
const runCoreLoop = options._coreLoop || coreAgentLoop;
|
|
235
|
+
// The tool-result event carries no args; remember the last tool-executing
|
|
236
|
+
// pair so a recorded denial can show what was attempted (/permissions denials).
|
|
237
|
+
let _lastExec = null;
|
|
238
|
+
for await (const event of runCoreLoop(messages, {
|
|
220
239
|
...options,
|
|
240
|
+
// FORCE in-loop compaction off — the REPL runs its OWN post-turn compaction
|
|
241
|
+
// (with metrics + persisted compact events), so letting agent-core compact
|
|
242
|
+
// too would trim the same history twice. Placed AFTER the spread so a
|
|
243
|
+
// caller's options.autoCompact can never silently re-enable the double pass.
|
|
244
|
+
autoCompact: false,
|
|
221
245
|
onProviderFallback,
|
|
222
246
|
})) {
|
|
223
247
|
if (event.type === "checkpoint") {
|
|
@@ -236,6 +260,7 @@ async function agentLoop(messages, options) {
|
|
|
236
260
|
chalk.gray(` ⎌ checkpoint ${event.id} (before ${event.tool})\n`),
|
|
237
261
|
);
|
|
238
262
|
} else if (event.type === "tool-executing") {
|
|
263
|
+
_lastExec = { tool: event.tool, args: event.args };
|
|
239
264
|
process.stdout.write(
|
|
240
265
|
chalk.gray(
|
|
241
266
|
` [${event.tool}] ${formatToolArgs(event.tool, event.args)}\n`,
|
|
@@ -246,6 +271,24 @@ async function agentLoop(messages, options) {
|
|
|
246
271
|
process.stdout.write(
|
|
247
272
|
chalk.red(` Error: ${event.error || event.result?.error}\n`),
|
|
248
273
|
);
|
|
274
|
+
// Record policy denials (not plain tool failures) into the caller's
|
|
275
|
+
// denial log for review via `/permissions denials` (Claude-Code 2.1.193
|
|
276
|
+
// recent denials). Caller passes the session log (mirrors checkpointMarks)
|
|
277
|
+
// so the wrapper stays unit-testable.
|
|
278
|
+
if (Array.isArray(options.denialLog)) {
|
|
279
|
+
const denial = classifyDenial({
|
|
280
|
+
tool: event.tool,
|
|
281
|
+
result: event.result,
|
|
282
|
+
error: event.error,
|
|
283
|
+
argsSummary:
|
|
284
|
+
_lastExec && _lastExec.tool === event.tool
|
|
285
|
+
? formatToolArgs(event.tool, _lastExec.args)
|
|
286
|
+
: "",
|
|
287
|
+
});
|
|
288
|
+
if (denial) {
|
|
289
|
+
recordDenial(options.denialLog, { ...denial, at: Date.now() });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
249
292
|
// Parity with Desktop AIChatPage's `Switch to Trusted` button:
|
|
250
293
|
// when the deny came from ApprovalGate (not shell-policy), surface
|
|
251
294
|
// the exact CLI command the user can run to relax the per-session
|
|
@@ -503,6 +546,11 @@ export async function startAgentRepl(options = {}) {
|
|
|
503
546
|
_respondToBash = readBooleanSetting("respondToBashCommands", {
|
|
504
547
|
cwd: process.cwd(),
|
|
505
548
|
});
|
|
549
|
+
// Claude-Code 2.1.193 autoMode.classifyAllShell (default OFF when unset).
|
|
550
|
+
_classifyAllShell =
|
|
551
|
+
readBooleanSetting("autoMode.classifyAllShell", {
|
|
552
|
+
cwd: process.cwd(),
|
|
553
|
+
}) === true;
|
|
506
554
|
const total =
|
|
507
555
|
loaded.rules.allow.length +
|
|
508
556
|
loaded.rules.ask.length +
|
|
@@ -538,12 +586,21 @@ export async function startAgentRepl(options = {}) {
|
|
|
538
586
|
// PostToolUse). The interactive _permissionConfirm above doubles as the
|
|
539
587
|
// confirmer for a hook `ask` decision.
|
|
540
588
|
try {
|
|
541
|
-
const { loadHooks } =
|
|
589
|
+
const { loadHooks, projectHookTrustNotice } =
|
|
590
|
+
await import("../lib/settings-hooks.cjs");
|
|
542
591
|
const loaded = loadHooks({ cwd: process.cwd() });
|
|
543
592
|
_settingsHooks =
|
|
544
593
|
loaded.hooks && Object.keys(loaded.hooks).length > 0
|
|
545
594
|
? loaded.hooks
|
|
546
595
|
: null;
|
|
596
|
+
// First-run trust notice for an untrusted/cloned repo's shell-running
|
|
597
|
+
// hooks (Claude-Code 2.1.195 parity). Best-effort, stderr-only.
|
|
598
|
+
try {
|
|
599
|
+
const notice = projectHookTrustNotice({ cwd: process.cwd() });
|
|
600
|
+
if (notice) process.stderr.write(notice + "\n");
|
|
601
|
+
} catch {
|
|
602
|
+
/* trust notice is best-effort */
|
|
603
|
+
}
|
|
547
604
|
} catch (_err) {
|
|
548
605
|
_settingsHooks = null;
|
|
549
606
|
}
|
|
@@ -1482,7 +1539,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1482
1539
|
` ${chalk.cyan("/cost")} Session token spend + estimated $ (per model & category)`,
|
|
1483
1540
|
);
|
|
1484
1541
|
logger.log(
|
|
1485
|
-
` ${chalk.cyan("/permissions")} Allow/ask/deny rules; set/cycle tier (/permissions <tier> · Shift+Tab
|
|
1542
|
+
` ${chalk.cyan("/permissions")} Allow/ask/deny rules; set/cycle tier (/permissions <tier> · Shift+Tab); /permissions denials to review blocked calls`,
|
|
1486
1543
|
);
|
|
1487
1544
|
logger.log(
|
|
1488
1545
|
` ${chalk.cyan("/export")} Save this conversation to a Markdown file (/export [path])`,
|
|
@@ -3034,6 +3091,13 @@ export async function startAgentRepl(options = {}) {
|
|
|
3034
3091
|
// parity): what the agent runs unprompted, asks about, or is blocked from.
|
|
3035
3092
|
if (trimmed === "/permissions" || trimmed.startsWith("/permissions ")) {
|
|
3036
3093
|
const arg = trimmed.slice("/permissions".length).trim();
|
|
3094
|
+
if (arg === "denials" || arg === "denied") {
|
|
3095
|
+
// Review what the agent was BLOCKED from running this session
|
|
3096
|
+
// (Claude-Code 2.1.193 "recent denials").
|
|
3097
|
+
logger.log(formatDenials(_recentDenials));
|
|
3098
|
+
prompt();
|
|
3099
|
+
return;
|
|
3100
|
+
}
|
|
3037
3101
|
if (arg) {
|
|
3038
3102
|
// Set this session's approval tier mid-session (Claude-Code
|
|
3039
3103
|
// permission-mode / Shift+Tab parity; mirrors `cc session policy --set`).
|
|
@@ -3079,6 +3143,13 @@ export async function startAgentRepl(options = {}) {
|
|
|
3079
3143
|
" Set tier mid-session: /permissions <strict|trusted|autopilot>",
|
|
3080
3144
|
),
|
|
3081
3145
|
);
|
|
3146
|
+
if (_recentDenials.length) {
|
|
3147
|
+
logger.log(
|
|
3148
|
+
chalk.gray(
|
|
3149
|
+
` ${_recentDenials.length} tool call(s) denied this session — /permissions denials to review`,
|
|
3150
|
+
),
|
|
3151
|
+
);
|
|
3152
|
+
}
|
|
3082
3153
|
prompt();
|
|
3083
3154
|
return;
|
|
3084
3155
|
}
|
|
@@ -3511,11 +3582,13 @@ export async function startAgentRepl(options = {}) {
|
|
|
3511
3582
|
autoCheckpoint,
|
|
3512
3583
|
checkpointSession: sessionId,
|
|
3513
3584
|
checkpointMarks: _checkpointMarks,
|
|
3585
|
+
denialLog: _recentDenials,
|
|
3514
3586
|
prepareCall,
|
|
3515
3587
|
approvalGate: _approvalGate,
|
|
3516
3588
|
permissionRules: _permissionRules,
|
|
3517
3589
|
permissionConfirm: _permissionConfirm,
|
|
3518
3590
|
settingsHooks: _settingsHooks,
|
|
3591
|
+
classifyAllShell: _classifyAllShell,
|
|
3519
3592
|
// Interactive session: gate run_code through the ApprovalGate (like
|
|
3520
3593
|
// run_shell) so a strict tier prompts before arbitrary code runs.
|
|
3521
3594
|
interactiveApproval: true,
|
|
@@ -51,13 +51,38 @@ describe("mergeConsecutiveMessages", () => {
|
|
|
51
51
|
// A multi-tool turn produces back-to-back `tool` results — folding them
|
|
52
52
|
// would drop tool_call_ids and corrupt the tool-call pairing.
|
|
53
53
|
const msgs = [
|
|
54
|
-
{
|
|
54
|
+
{
|
|
55
|
+
role: "assistant",
|
|
56
|
+
content: "",
|
|
57
|
+
tool_calls: [{ id: "a" }, { id: "b" }],
|
|
58
|
+
},
|
|
55
59
|
{ role: "tool", content: "r1", tool_call_id: "a" },
|
|
56
60
|
{ role: "tool", content: "r2", tool_call_id: "b" },
|
|
57
61
|
];
|
|
58
62
|
expect(mergeConsecutiveMessages(msgs)).toEqual(msgs);
|
|
59
63
|
});
|
|
60
64
|
|
|
65
|
+
it("never merges a structured assistant tool-call turn (tool_calls preserved)", () => {
|
|
66
|
+
// Two consecutive assistants where the SECOND carries tool_calls — folding
|
|
67
|
+
// would drop them (orphaning the result) and the strict API would 400.
|
|
68
|
+
const msgs = [
|
|
69
|
+
{ role: "assistant", content: "let me check" },
|
|
70
|
+
{ role: "assistant", content: "", tool_calls: [{ id: "c1" }] },
|
|
71
|
+
{ role: "tool", content: "result", tool_call_id: "c1" },
|
|
72
|
+
];
|
|
73
|
+
expect(mergeConsecutiveMessages(msgs)).toEqual(msgs);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("never folds two consecutive assistants when the FIRST has tool_calls", () => {
|
|
77
|
+
// e.g. after a compaction dropped the tool results — merging would mutate
|
|
78
|
+
// the structured turn's content and keep its now-unanswered tool_calls.
|
|
79
|
+
const msgs = [
|
|
80
|
+
{ role: "assistant", content: "", tool_calls: [{ id: "a" }] },
|
|
81
|
+
{ role: "assistant", content: "fallback text" },
|
|
82
|
+
];
|
|
83
|
+
expect(mergeConsecutiveMessages(msgs)).toEqual(msgs);
|
|
84
|
+
});
|
|
85
|
+
|
|
61
86
|
it("never merges system messages (leading base + context pair kept distinct)", () => {
|
|
62
87
|
const msgs = [
|
|
63
88
|
{ role: "system", content: "base" },
|
|
@@ -202,14 +227,22 @@ describe("collapseConsecutiveMessagesInPlace", () => {
|
|
|
202
227
|
const messages = [
|
|
203
228
|
{ role: "user", content: "u1" },
|
|
204
229
|
{ role: "user", content: "u2" },
|
|
205
|
-
{
|
|
230
|
+
{
|
|
231
|
+
role: "assistant",
|
|
232
|
+
content: "",
|
|
233
|
+
tool_calls: [{ id: "a" }, { id: "b" }],
|
|
234
|
+
},
|
|
206
235
|
{ role: "tool", content: "r1", tool_call_id: "a" },
|
|
207
236
|
{ role: "tool", content: "r2", tool_call_id: "b" },
|
|
208
237
|
];
|
|
209
238
|
expect(collapseConsecutiveMessagesInPlace(messages)).toBe(true);
|
|
210
239
|
expect(messages).toEqual([
|
|
211
240
|
{ role: "user", content: "u1\n\nu2" },
|
|
212
|
-
{
|
|
241
|
+
{
|
|
242
|
+
role: "assistant",
|
|
243
|
+
content: "",
|
|
244
|
+
tool_calls: [{ id: "a" }, { id: "b" }],
|
|
245
|
+
},
|
|
213
246
|
{ role: "tool", content: "r1", tool_call_id: "a" },
|
|
214
247
|
{ role: "tool", content: "r2", tool_call_id: "b" },
|
|
215
248
|
]);
|