diff --git a/docs/permission-extension.md b/docs/permission-extension.md index 5cbdce53..9fe33e4c 100644 --- a/docs/permission-extension.md +++ b/docs/permission-extension.md @@ -53,11 +53,12 @@ The request-level record is placed under `RequestPermissionRequest._meta.permiss } ``` -| Field | Required | Type | Meaning | -| ------------- | -------: | ---------------- | ----------------------------------------- | -| `version` | yes | integer `1` | Permission presentation schema version. | -| `title` | yes | non-empty string | The standard tool-call operation title. | -| `description` | no | string | Temporary diagnostic SDK decision reason. | +| Field | Required | Type | Meaning | +| ------------- | -------: | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `version` | yes | integer `1` | Permission presentation schema version. | +| `title` | yes | non-empty string | The standard tool-call operation title. | +| `description` | no | string | Temporary diagnostic SDK decision reason. | +| `defaultToNo` | no | `true` | The ask must not be approvable by a stray keystroke; the reject options are listed first and a client that pre-selects an option should focus the decline. | The permission title normally duplicates `toolCall.title`: one operation has one heading across the tool card and approval UI. `ExitPlanMode` is the deliberate exception and uses the action-oriented diff --git a/docs/session-failure-extension.md b/docs/session-failure-extension.md index cc1446dd..7c4b2a27 100644 --- a/docs/session-failure-extension.md +++ b/docs/session-failure-extension.md @@ -113,6 +113,7 @@ Claude SDK conditions map to these groups: | Claude condition | Category | | ---------------------------------------------------------------------------------------- | ---------------------------------- | | `authentication_failed`, `oauth_org_not_allowed`, synthetic login message | `access` | +| `verification_required`, `cloud_credential_error` | `access` (no `login` action) | | `billing_error`, `rate_limit`, `max_output_tokens`, usage/spend limit, budget/turn limit | `limit` | | `invalid_request`, `model_not_found` | `request` | | `overloaded`, `server_error`, unknown provider error, adapter internal error | `service` | diff --git a/package-lock.json b/package-lock.json index ca5d644d..9a1fce26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,20 +10,20 @@ "license": "Apache-2.0", "dependencies": { "@agentclientprotocol/sdk": "1.4.0", - "@anthropic-ai/claude-agent-sdk": "0.3.257", - "zod": "^4.0.0" + "@anthropic-ai/claude-agent-sdk": "0.3.270", + "zod": "4.6.5" }, "bin": { "claude-agent-acp": "dist/index.js" }, "devDependencies": { - "@anthropic-ai/sdk": "0.122.0", + "@anthropic-ai/sdk": "0.125.0", "@eslint/js": "10.0.1", "@tsconfig/node22": "22.0.6", - "@types/node": "26.4.0", - "@typescript-eslint/eslint-plugin": "8.69.0", - "@typescript-eslint/parser": "8.69.0", - "eslint": "10.9.1", + "@types/node": "26.5.1", + "@typescript-eslint/eslint-plugin": "8.70.0", + "@typescript-eslint/parser": "8.70.0", + "eslint": "10.10.0", "eslint-config-prettier": "10.1.8", "globals": "17.12.0", "prettier": "3.9.6", @@ -45,22 +45,22 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.257.tgz", - "integrity": "sha512-Se55zXv48IYLg/WzoXzpbPLcq86suwDSbRUoNb69l4dkovorqS/47Xuy7MUo/gPNwwcPB4a+aqbXbshU33dcdQ==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.270.tgz", + "integrity": "sha512-sSfcm5Nhb+WHeBCxqeHRRQMUKPmFTL+zgv5xcRUVaFMLttfNEbn3IZJE+fLJJmy4h3J8zdc5sXdSa1JxyB8ppQ==", "license": "SEE LICENSE IN README.md", "engines": { "node": ">=18.0.0" }, "optionalDependencies": { - "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.257", - "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.257", - "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.257", - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.257", - "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.257", - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.257", - "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.257", - "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.257" + "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.270", + "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.270", + "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.270", + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.270", + "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.270", + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.270", + "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.270", + "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.270" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", @@ -69,9 +69,9 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.257.tgz", - "integrity": "sha512-ITjFPYB8riu9tbxbrWArokiZ/90w/NDrYbtEvyr3ScilVtu1iupkComxkhvbUxoyT4JRDpKsdw/ZOfwSl/pkpA==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.270.tgz", + "integrity": "sha512-nk7BP+i559rheYz9DIwAfevd4DulQXP0mXPP+MeO2fGuIGFmzhE/c0JRm9YswXv5HdaYJvSzjGIB7dVA01NehA==", "cpu": [ "arm64" ], @@ -82,9 +82,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.257.tgz", - "integrity": "sha512-0s7QoLRnopbMvCqVpgCnvBWg4UNxPUybMZTknkn3HLBMvUjUdHs1QXb77c/yrT1WAPqDTw1Ju+H0esXwWa8/Kg==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.270.tgz", + "integrity": "sha512-89Uql8Oalm52ojdZZeNLU24LKrU+WG9QR7d6YP9ly4aY0YvQUJDaTosbDkijQngUETbPBFdKuVp6fNM8x0Zt3Q==", "cpu": [ "x64" ], @@ -95,12 +95,15 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.257.tgz", - "integrity": "sha512-38tv1s1CaIE6CyEBmJpfKtvwPzrasxPiRT079BEs5aaiLPQ+pmSGF0+Lwy7ot9i6xqr7v5/91TVo5JXHI8Pkpg==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.270.tgz", + "integrity": "sha512-iHPYqwetyeO4tZPzXyKZz0hUh2fLpwu/+biGTxxynikG3XrYknovZ/znGDA3TxjSFurqHf5IIDA+SOjh9OPs0A==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -108,12 +111,15 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.257.tgz", - "integrity": "sha512-t2WHfKjY4Jjgzfk0lbBUt6EVPQe+wXvXvRmYnK7ICfzZ1jS8CrpDajwBQErKFSMiUqGAutZy3vwDwGziW32cpw==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.270.tgz", + "integrity": "sha512-2BlLk2MAohWG2h43RKcjCA4ooMfBxzKf4yyYfOVv1DtYr8zPU876MHCT1VXB2BaemjKA0pdYJJBzH6pncwx6MQ==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -121,12 +127,15 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.257.tgz", - "integrity": "sha512-0FRyIwV4jEJErdDDoYMC0v9lzuFNz5y0lK2340H5fP02eNXsP3U0htKW/bfRP8Ppei+xc4QUZgdCI6rVzkhXGg==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.270.tgz", + "integrity": "sha512-ADaqz2viyAd0GUxdupYLX/K0YJb46xckNpEeWxyLK/9+26b/R5stbaGDyL29fIzyq1ymnNUOaCgEWEemgX0kEA==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -134,12 +143,15 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.257.tgz", - "integrity": "sha512-qSlgAUEpj2JAA+YqMD222iv2W3x8xBDSYwdoaOx20VbaJRjFq8feViI7kcr1C6wVN+ApX4Rxl7YX6gekiBkA2g==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.270.tgz", + "integrity": "sha512-mzH3lnbzrbDGrTf75jLEmkbvkKRLLgmjLaWvf3QuUsgcw+aU69aOY0mW33oOrsuq5zg330uI3B4e68f4LbxNIA==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -147,9 +159,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.257.tgz", - "integrity": "sha512-7iEwy14lSqaAWvNR3KucBusQs5+hG6uoliYWZ2M2FyaCk5PHYymVf9mrRPtWhaYfNwum/YY13acYIIvnAbz0kA==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.270.tgz", + "integrity": "sha512-Pexeu26cLZByhs6VlrawNYAEu+QE2YptvwNkXsmpLRm7Q/C/M0N/BZBmuUcikXrQQ9cuVzSjuuTTpZt64mvtLA==", "cpu": [ "arm64" ], @@ -160,9 +172,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": { - "version": "0.3.257", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.257.tgz", - "integrity": "sha512-NW0zMjHXFBdu2TcjT9Zo5o/1tJaDy6A7v4Gt/vLVJgaipV/RzAbyRGXZzH37hswyiKrSLGaSoYYP1vUfncbkUQ==", + "version": "0.3.270", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.270.tgz", + "integrity": "sha512-9UyfFcUYsyUZqSe/xX9nIJ1Og6i8FxhlQ35BDi79Ik5He87XFxEIGUvJuMcl7Mq2e3panyhekELFE+9H79xKdw==", "cpu": [ "x64" ], @@ -173,9 +185,9 @@ ] }, "node_modules/@anthropic-ai/sdk": { - "version": "0.122.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.122.0.tgz", - "integrity": "sha512-GGPNftt0caaz9MDlmNQGHX8855Ojaduyy5pm9Sm1h7HalCn0cWNb5/bweadJF+4yzbal+QL6ztBa09WAAOzLmQ==", + "version": "0.125.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.125.0.tgz", + "integrity": "sha512-Hq5wYlXupzJ9M1Fzqjqa3hObcuigEXVZJqSYDgeZGM3wF4qrNERM5Z1OOAeoT9rlod8awJ3uYyJjbQXp1ckIGg==", "license": "MIT", "dependencies": { "json-schema-to-ts": "^3.1.1", @@ -202,6 +214,30 @@ "node": ">=6.9.0" } }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -317,9 +353,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", - "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -437,6 +473,30 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", @@ -479,9 +539,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.148.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.148.0.tgz", - "integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==", + "version": "0.149.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.149.0.tgz", + "integrity": "sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA==", "dev": true, "license": "MIT", "peer": true, @@ -490,9 +550,9 @@ } }, "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz", - "integrity": "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.8.tgz", + "integrity": "sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==", "cpu": [ "arm" ], @@ -508,9 +568,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.7.tgz", - "integrity": "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.8.tgz", + "integrity": "sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==", "cpu": [ "arm64" ], @@ -526,9 +586,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.7.tgz", - "integrity": "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.8.tgz", + "integrity": "sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==", "cpu": [ "arm64" ], @@ -544,9 +604,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.7.tgz", - "integrity": "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.8.tgz", + "integrity": "sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==", "cpu": [ "x64" ], @@ -562,9 +622,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.7.tgz", - "integrity": "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.8.tgz", + "integrity": "sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==", "cpu": [ "x64" ], @@ -580,9 +640,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.7.tgz", - "integrity": "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.8.tgz", + "integrity": "sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==", "cpu": [ "arm" ], @@ -598,9 +658,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.7.tgz", - "integrity": "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.8.tgz", + "integrity": "sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==", "cpu": [ "arm64" ], @@ -619,9 +679,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.7.tgz", - "integrity": "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.8.tgz", + "integrity": "sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==", "cpu": [ "arm64" ], @@ -640,9 +700,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.7.tgz", - "integrity": "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.8.tgz", + "integrity": "sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==", "cpu": [ "ppc64" ], @@ -661,9 +721,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.7.tgz", - "integrity": "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.8.tgz", + "integrity": "sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==", "cpu": [ "s390x" ], @@ -682,9 +742,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.7.tgz", - "integrity": "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.8.tgz", + "integrity": "sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==", "cpu": [ "x64" ], @@ -703,9 +763,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.7.tgz", - "integrity": "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.8.tgz", + "integrity": "sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==", "cpu": [ "x64" ], @@ -724,9 +784,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.7.tgz", - "integrity": "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.8.tgz", + "integrity": "sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==", "cpu": [ "arm64" ], @@ -742,9 +802,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.7.tgz", - "integrity": "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.8.tgz", + "integrity": "sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==", "cpu": [ "arm64" ], @@ -760,9 +820,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.7.tgz", - "integrity": "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.8.tgz", + "integrity": "sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==", "cpu": [ "x64" ], @@ -866,27 +926,27 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.4.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz", - "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==", + "version": "26.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.5.1.tgz", + "integrity": "sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~8.3.0" + "undici-types": "~8.9.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz", - "integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.0.tgz", + "integrity": "sha512-/v8HZt6RlyIZxB3ntehELOcUcfxKPVGWXnQdJuHRmzrqgF8nQypcC/oxGW+Ot4VGKDq81XugPKxx0n5PBtf9PA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.69.0", - "@typescript-eslint/type-utils": "8.69.0", - "@typescript-eslint/utils": "8.69.0", - "@typescript-eslint/visitor-keys": "8.69.0", + "@typescript-eslint/scope-manager": "8.70.0", + "@typescript-eslint/type-utils": "8.70.0", + "@typescript-eslint/utils": "8.70.0", + "@typescript-eslint/visitor-keys": "8.70.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -899,22 +959,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.69.0", + "@typescript-eslint/parser": "^8.70.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz", - "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.0.tgz", + "integrity": "sha512-zYvrmj9Yxd63UGaXw+kdt6A0F0s0qveJyuatIM77bYC2DE4pgmg7a50u8LR7PRtXd0x+h+Tl3eXabGm06SWd3Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.69.0", - "@typescript-eslint/types": "8.69.0", - "@typescript-eslint/typescript-estree": "8.69.0", - "@typescript-eslint/visitor-keys": "8.69.0", + "@typescript-eslint/scope-manager": "8.70.0", + "@typescript-eslint/types": "8.70.0", + "@typescript-eslint/typescript-estree": "8.70.0", + "@typescript-eslint/visitor-keys": "8.70.0", "debug": "^4.4.3" }, "engines": { @@ -930,14 +990,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz", - "integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.0.tgz", + "integrity": "sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.69.0", - "@typescript-eslint/types": "^8.69.0", + "@typescript-eslint/tsconfig-utils": "^8.70.0", + "@typescript-eslint/types": "^8.70.0", "debug": "^4.4.3" }, "engines": { @@ -952,14 +1012,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz", - "integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.0.tgz", + "integrity": "sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.69.0", - "@typescript-eslint/visitor-keys": "8.69.0" + "@typescript-eslint/types": "8.70.0", + "@typescript-eslint/visitor-keys": "8.70.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -970,9 +1030,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz", - "integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.0.tgz", + "integrity": "sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==", "dev": true, "license": "MIT", "engines": { @@ -987,15 +1047,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz", - "integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.0.tgz", + "integrity": "sha512-NUMKIhYVaVIVLnRL9CRt+VVcuLgSHUCpXn4/+K8wql+vdInUzvx8BjUO1oJ7cG9shjFJKtF8F8Hh2kCh3/KBVw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.69.0", - "@typescript-eslint/typescript-estree": "8.69.0", - "@typescript-eslint/utils": "8.69.0", + "@typescript-eslint/types": "8.70.0", + "@typescript-eslint/typescript-estree": "8.70.0", + "@typescript-eslint/utils": "8.70.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -1012,9 +1072,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz", - "integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.0.tgz", + "integrity": "sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==", "dev": true, "license": "MIT", "engines": { @@ -1026,16 +1086,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz", - "integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.0.tgz", + "integrity": "sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.69.0", - "@typescript-eslint/tsconfig-utils": "8.69.0", - "@typescript-eslint/types": "8.69.0", - "@typescript-eslint/visitor-keys": "8.69.0", + "@typescript-eslint/project-service": "8.70.0", + "@typescript-eslint/tsconfig-utils": "8.70.0", + "@typescript-eslint/types": "8.70.0", + "@typescript-eslint/visitor-keys": "8.70.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -1054,16 +1114,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz", - "integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.0.tgz", + "integrity": "sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.69.0", - "@typescript-eslint/types": "8.69.0", - "@typescript-eslint/typescript-estree": "8.69.0" + "@typescript-eslint/scope-manager": "8.70.0", + "@typescript-eslint/types": "8.70.0", + "@typescript-eslint/typescript-estree": "8.70.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1078,13 +1138,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.69.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz", - "integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.0.tgz", + "integrity": "sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/types": "8.70.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -1331,6 +1391,20 @@ "node": ">= 0.8" } }, + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1603,9 +1677,9 @@ } }, "node_modules/eslint": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.1.tgz", - "integrity": "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==", + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.10.0.tgz", + "integrity": "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==", "dev": true, "license": "MIT", "workspaces": [ @@ -1617,7 +1691,7 @@ "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.2", + "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -1632,7 +1706,7 @@ "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", @@ -2012,16 +2086,13 @@ } }, "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "flat-cache": "^6.1.23" } }, "node_modules/finalhandler": { @@ -2064,17 +2135,15 @@ } }, "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" } }, "node_modules/flatted": { @@ -2221,6 +2290,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/hasown": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", @@ -2235,15 +2317,22 @@ } }, "node_modules/hono": { - "version": "4.13.5", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.5.tgz", - "integrity": "sha512-O6+/eCYRkzzzy0rPWwKLiGBR1nFuUPZynnwjxN1MBA62NNqbT0wQEzQyK2gSO5yDIDB336sXQleAhOHrzlYyKw==", + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.7.tgz", + "integrity": "sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==", "license": "MIT", "peer": true, "engines": { "node": ">=16.9.0" } }, + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", + "dev": true, + "license": "MIT" + }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -2283,9 +2372,9 @@ } }, "node_modules/ignore": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", - "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz", + "integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==", "dev": true, "license": "MIT", "engines": { @@ -2366,22 +2455,15 @@ "license": "ISC" }, "node_modules/jose": { - "version": "6.2.10", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.10.tgz", - "integrity": "sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==", + "version": "6.2.12", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", + "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/panva" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, "node_modules/json-schema-to-ts": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", @@ -2417,13 +2499,13 @@ "license": "MIT" }, "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@keyv/serialize": "^1.1.1" } }, "node_modules/levn": { @@ -2742,13 +2824,13 @@ } }, "node_modules/magic-string": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.2.3.tgz", - "integrity": "sha512-Bpb0W2TbLKOZ7vJnOUnVRGq3WL2p+ISV29M6hYPL1AFCpyKZpdr5ytiXoTSSxRVhg8YW7f65+6gbG8WG6PCa/g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.3.1.tgz", + "integrity": "sha512-rm91zr2Ou+XueDTohjQQjdQEcYM6zVi8KVUCG8Ec3vHwUEKrhSdCNyfuIywkA6hcCAteIn0ZOtAHA6eGpiX+Pg==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@jridgewell/sourcemap-codec": "^1.6.0" } }, "node_modules/make-error": { @@ -2845,9 +2927,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", "dev": true, "funding": [ { @@ -2926,9 +3008,9 @@ } }, "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -3163,6 +3245,26 @@ "node": ">=6" } }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, "node_modules/qs": { "version": "6.16.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", @@ -3221,14 +3323,14 @@ } }, "node_modules/rolldown": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.7.tgz", - "integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.8.tgz", + "integrity": "sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@oxc-project/types": "=0.148.0", + "@oxc-project/types": "=0.149.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -3238,21 +3340,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.7", - "@rolldown/binding-android-arm64": "1.2.7", - "@rolldown/binding-darwin-arm64": "1.2.7", - "@rolldown/binding-darwin-x64": "1.2.7", - "@rolldown/binding-freebsd-x64": "1.2.7", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.7", - "@rolldown/binding-linux-arm64-gnu": "1.2.7", - "@rolldown/binding-linux-arm64-musl": "1.2.7", - "@rolldown/binding-linux-ppc64-gnu": "1.2.7", - "@rolldown/binding-linux-s390x-gnu": "1.2.7", - "@rolldown/binding-linux-x64-gnu": "1.2.7", - "@rolldown/binding-linux-x64-musl": "1.2.7", - "@rolldown/binding-openharmony-arm64": "1.2.7", - "@rolldown/binding-win32-arm64-msvc": "1.2.7", - "@rolldown/binding-win32-x64-msvc": "1.2.7" + "@rolldown/binding-android-arm-eabi": "1.2.8", + "@rolldown/binding-android-arm64": "1.2.8", + "@rolldown/binding-darwin-arm64": "1.2.8", + "@rolldown/binding-darwin-x64": "1.2.8", + "@rolldown/binding-freebsd-x64": "1.2.8", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.8", + "@rolldown/binding-linux-arm64-gnu": "1.2.8", + "@rolldown/binding-linux-arm64-musl": "1.2.8", + "@rolldown/binding-linux-ppc64-gnu": "1.2.8", + "@rolldown/binding-linux-s390x-gnu": "1.2.8", + "@rolldown/binding-linux-x64-gnu": "1.2.8", + "@rolldown/binding-linux-x64-musl": "1.2.8", + "@rolldown/binding-openharmony-arm64": "1.2.8", + "@rolldown/binding-win32-arm64-msvc": "1.2.8", + "@rolldown/binding-win32-x64-msvc": "1.2.8" } }, "node_modules/router": { @@ -3666,9 +3768,9 @@ } }, "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "dev": true, "license": "MIT" }, @@ -3710,17 +3812,17 @@ } }, "node_modules/vite": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", - "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", + "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "lightningcss": "^1.33.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.26", - "rolldown": "~1.2.4", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.6", "tinyglobby": "^0.2.17" }, "bin": { @@ -3737,7 +3839,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -3944,9 +4046,9 @@ } }, "node_modules/zod": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz", - "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index fadc5d3e..9c78d4e7 100644 --- a/package.json +++ b/package.json @@ -66,17 +66,17 @@ }, "dependencies": { "@agentclientprotocol/sdk": "1.4.0", - "@anthropic-ai/claude-agent-sdk": "0.3.257", - "zod": "^4.0.0" + "@anthropic-ai/claude-agent-sdk": "0.3.270", + "zod": "4.6.5" }, "devDependencies": { - "@anthropic-ai/sdk": "0.122.0", + "@anthropic-ai/sdk": "0.125.0", "@eslint/js": "10.0.1", "@tsconfig/node22": "22.0.6", - "@types/node": "26.4.0", - "@typescript-eslint/eslint-plugin": "8.69.0", - "@typescript-eslint/parser": "8.69.0", - "eslint": "10.9.1", + "@types/node": "26.5.1", + "@typescript-eslint/eslint-plugin": "8.70.0", + "@typescript-eslint/parser": "8.70.0", + "eslint": "10.10.0", "eslint-config-prettier": "10.1.8", "globals": "17.12.0", "prettier": "3.9.6", diff --git a/src/acp-agent.ts b/src/acp-agent.ts index b8003d8b..2799e7db 100644 --- a/src/acp-agent.ts +++ b/src/acp-agent.ts @@ -626,10 +626,14 @@ type Turn = { * issue #866), and the model's task-notification followup summary all * land inside the turn. * - * The CLI does NOT hold its trailing idle for background agents (observed - * on 2.1.206: `idle` follows the result immediately while the subagent - * still runs), so the hold spans multiple idle cycles: user result → - * idle → (subagent works) → task_notification → followup turn → idle. + * Idle cadence depends on the CLI. Through 2.1.269 the trailing idle is + * NOT held for background agents (observed on 2.1.206: `idle` follows + * the result immediately while the subagent still runs), so the hold + * spans multiple idle cycles: user result → idle → (subagent works) → + * task_notification → followup turn → idle. From 2.1.270 the CLI stays + * `running` while background agents live (observed live: user result → + * task_notification → followup turn → ONE idle), so the user result's + * idle debt goes unpaid — swept at the next `running` transition. * The stored outcome (the result's stop reason and usage snapshot) is * what the turn settles with once its spawned subagents have settled — * at the followup's terminal result (the summary has streamed by then), @@ -4183,7 +4187,31 @@ export class ClaudeAcpAgent { break; } case "session_state_changed": { + const previousState = session.lastSessionState; session.lastSessionState = message.state; + if ( + message.state === "running" && + previousState !== "running" && + session.owedTrailingIdles > 0 + ) { + // A transition INTO `running` (the CLI reports state + // changes; a repeated `running` is not a transition and is + // left alone) proves the idle period before it ended: every + // idle the CLI was going to emit for earlier results has + // been emitted. Debt still outstanding here can never be paid. + // CLI 2.1.270+ withholds `idle` while background agents run + // (verified live: user result → task_notification → + // followup result → ONE idle), so a held turn's own result + // leaves one unpaid unit per hold. Left in place, each unit + // would absorb a later un-owed idle — masking an issue-#825 + // detection — or swallow the idle a steered turn settles on + // (the owed-idle branch below runs before the steer lane), + // hanging that prompt. Sweep it. + this.logger.log( + `[claude-agent-acp] Session ${params.sessionId}: dropping ${session.owedTrailingIdles} unpaid trailing-idle debt at the running transition`, + ); + session.owedTrailingIdles = 0; + } if (message.state === "idle") { // A non-cancelled turn normally settled at its terminal // `result` already (issue #773), and that result recorded an @@ -4225,17 +4253,19 @@ export class ClaudeAcpAgent { session.emittedAssistantText = false; } else if (isHeldOpen(session.activeTurn)) { // A turn held open for its background subagents (see - // Turn.deferredSettle). Idles keep their normal cadence - // during the hold — the CLI emits one per processing - // cycle (the turn's own trailer, then one per followup), - // NOT one final "all drained" signal — so each one - // absorbs an outstanding trailer debt, and the turn only - // settles once none of its spawned subagents is left - // (the followup-result settle usually got there first; - // this is the fallback when no followup came). Mid-hold - // idles never fall through: a held turn HAS its result, - // so reading its idle as "turn abandoned without a - // result" (issue #825) would fail a healthy prompt. + // Turn.deferredSettle). Idle cadence during the hold + // depends on the CLI: through 2.1.269 one idle per + // processing cycle (the turn's own trailer, then one per + // followup); from 2.1.270 none until the background + // agents drain, then one. Either way each idle absorbs an + // outstanding trailer debt (the unpayable remainder is + // swept at the next `running` transition above), and the + // turn only settles once none of its spawned subagents is + // left (the followup-result settle usually got there + // first; this is the fallback when no followup came). + // Mid-hold idles never fall through: a held turn HAS its + // result, so reading its idle as "turn abandoned without + // a result" (issue #825) would fail a healthy prompt. if (session.owedTrailingIdles > 0) { session.owedTrailingIdles--; } @@ -4601,10 +4631,18 @@ export class ClaudeAcpAgent { // here would outlive the `auth_required` rejection with no // action to clear it (issue #1072). if (kind === "auth_required") break; + // `no_response` (SDK 0.3.261+): the API sent no response headers + // within the first-byte window, so this retry waits longer for + // them. Say so — "attempt 1 of 1" alone reads like a final + // failure, and the wait is what the user is about to sit through. + const seconds = (ms: number) => `${Math.max(1, Math.round(ms / 1000))}s`; + const noResponse = message.no_response + ? ` No response after ${seconds(message.no_response.waited_ms)}; waiting up to ${seconds(message.no_response.retry_wait_ms)}.` + : ""; const title = message.error_status === null - ? `Reconnecting to Claude, attempt ${message.attempt} of ${message.max_retries}.` - : `Retrying Claude, attempt ${message.attempt} of ${message.max_retries}.`; + ? `Reconnecting to Claude, attempt ${message.attempt} of ${message.max_retries}.${noResponse}` + : `Retrying Claude, attempt ${message.attempt} of ${message.max_retries}.${noResponse}`; await publishSessionFailure(kind, { title, severity: "warning" }); break; } @@ -7006,6 +7044,8 @@ export class ClaudeAcpAgent { title, displayName, description, + defaultToNo, + suppressAlwaysAllowRule, }, ) => { const supportsTerminalOutput = this.clientCapabilities?._meta?.["terminal_output"] === true; @@ -7096,10 +7136,13 @@ export class ClaudeAcpAgent { // explicit ask rule). Re-applying bypass in the host would erase that // provider safety decision. - const durableChangeSet = normalizeDurablePermissionChangeSet( - suggestions, - matchedAskRule !== undefined, - ); + // No persistent "always allow" option when the user's own ask rule forced + // the prompt, or when the CLI says the rule it would write grants more + // than this ask's own action (`suppressAlwaysAllowRule`, SDK 0.3.268+ — + // set on its safety-check asks, e.g. delete-class Bash rulings and + // Artifact publishes). + const noPersistentRule = matchedAskRule !== undefined || suppressAlwaysAllowRule === true; + const durableChangeSet = normalizeDurablePermissionChangeSet(suggestions, noPersistentRule); const presentation = buildClaudePermissionPresentation({ toolName, input: toolInput, @@ -7111,6 +7154,7 @@ export class ClaudeAcpAgent { displayName, description, decisionReason, + defaultToNo, }); if (parentToolUseId) { @@ -7125,7 +7169,8 @@ export class ClaudeAcpAgent { input: toolInput, cwd: session.cwd, durableChangeSet, - allowPersistentOptions: matchedAskRule === undefined, + allowPersistentOptions: !noPersistentRule, + defaultToNo, availableModes: this.sessionModes.availableModeIds(session.modes), contextUsedPercent: session.contextUsedTokens === undefined || session.contextWindowSize <= 0 diff --git a/src/permissions/options.ts b/src/permissions/options.ts index 89588a21..7af91eb5 100644 --- a/src/permissions/options.ts +++ b/src/permissions/options.ts @@ -23,8 +23,12 @@ import { export { PERMISSION_OPTION_ID } from "./options/shared.js"; export function buildClaudePermissionOptions(context: PermissionOptionContext): PermissionOption[] { + // ACP has no "pre-selected option" field, so option order is the only lever + // for the CLI's `defaultToNo` hint ("open on the decline option"): lead with + // the reject options instead of the approvals. + const order = context.defaultToNo === true ? declineFirstOptionOrder : permissionOptionOrder; return buildUnsortedClaudePermissionOptions(context).sort( - (left, right) => permissionOptionOrder(left) - permissionOptionOrder(right), + (left, right) => order(left) - order(right), ); } @@ -71,6 +75,16 @@ function buildUnsortedClaudePermissionOptions( } } +function declineFirstOptionOrder(option: PermissionOption): number { + switch (option.kind) { + case "reject_once": + case "reject_always": + return 0; + default: + return 1 + permissionOptionOrder(option); + } +} + function permissionOptionOrder(option: PermissionOption): number { switch (option.kind) { case "allow_once": diff --git a/src/permissions/options/shared.ts b/src/permissions/options/shared.ts index da489768..b94d3ce3 100644 --- a/src/permissions/options/shared.ts +++ b/src/permissions/options/shared.ts @@ -23,6 +23,9 @@ export interface PermissionOptionContext { cwd: string; durableChangeSet?: DurablePermissionChangeSet; allowPersistentOptions?: boolean; + /** The CLI's `defaultToNo` hint (SDK 0.3.268+): the ask must not be + * approvable by a stray keystroke, so the decline option leads. */ + defaultToNo?: boolean; availableModes?: readonly string[]; contextUsedPercent?: number; } diff --git a/src/permissions/presentation.ts b/src/permissions/presentation.ts index 5fb33d9a..2c273777 100644 --- a/src/permissions/presentation.ts +++ b/src/permissions/presentation.ts @@ -12,6 +12,7 @@ export interface ClaudePermissionPresentationInput { displayName?: string; description?: string; decisionReason?: string; + defaultToNo?: boolean; } function humanText(value: unknown, maxLength: number, singleLine = false): string | undefined { @@ -104,6 +105,10 @@ export function buildClaudePermissionPresentation( version: 1, title, ...(description ? { description } : {}), + // The CLI's own hint, forwarded so a client that can pre-select + // an option keeps the decline focused; the option order already + // leads with the reject options when this is set. + ...(value.defaultToNo === true ? { defaultToNo: true } : {}), }, }, } diff --git a/src/session-failure-extension.ts b/src/session-failure-extension.ts index fc7902d7..3f4609cf 100644 --- a/src/session-failure-extension.ts +++ b/src/session-failure-extension.ts @@ -17,6 +17,7 @@ export function airSessionFailureCapabilityMeta(...additionalCapabilities: strin } export type ClaudeFailureKind = + | "access_denied" | "advisory" | "auth_required" | "bad_request" @@ -93,6 +94,15 @@ const AIR_FAILURE_POLICY: Record< fallbackTitle: string; } > = { + // Account or credential blocks that signing in again cannot fix: the + // organization must complete verification, or the cloud provider's + // credentials must be refreshed outside Claude. No `login` action, and not + // sticky like `auth_required` (nothing clears at `auth_status`). + access_denied: { + category: "access", + actions: ["retry"], + fallbackTitle: "Claude could not access the account or provider credentials.", + }, advisory: { category: "unknown", actions: [], @@ -448,6 +458,15 @@ export function providerFailureCategory( case "billing_error": case "account_on_hold": return "quota_exhausted"; + // 403 `permission_error` with error_code `verification_required` (the + // organization must verify at the console), and a Bedrock/Vertex/Foundry + // credential the CLI could not load (transient: it retries, and asks the + // user to check or refresh the credentials). Both are access failures + // `/login` does not repair, so they get their own lane rather than + // `auth_required`'s login action and sticky auth_status recovery. + case "verification_required": + case "cloud_credential_error": + return "access_denied"; case "rate_limit": return "rate_limited"; case "overloaded": diff --git a/src/tests/acp-agent.test.ts b/src/tests/acp-agent.test.ts index 89638d64..2e67d852 100644 --- a/src/tests/acp-agent.test.ts +++ b/src/tests/acp-agent.test.ts @@ -4118,6 +4118,79 @@ describe("canUseTool in bypassPermissions mode", () => { expect(request?.options.map((option) => option.optionId)).toEqual(["allow-once", "reject"]); }); + + // SDK 0.3.268+ hints on the CLI's safety-check asks (delete-class Bash + // rulings, Artifact publishes, …): the always-allow rule it would write is + // broader than the ask, so no persistent option may be offered; and the ask + // must open on its decline option, so the reject options lead. + it("offers no always-allow option when the CLI suppresses the persistent rule", async () => { + let request: RequestPermissionRequest | undefined; + const mockClient = { + sessionUpdate: async () => {}, + requestPermission: async (params: RequestPermissionRequest) => { + request = params; + return { outcome: { outcome: "selected", optionId: "allow-once" } }; + }, + } as unknown as AcpClient; + const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} }); + agent.sessions["session-1"] = mockSessionState(); + agent.sessions["session-1"]!.emittedToolCalls.add("tool-1"); + + await agent.canUseTool("session-1")("Bash", { command: "rm -rf build" }, { + signal: new AbortController().signal, + suggestions: [ + { + type: "addRules", + rules: [{ toolName: "Bash", ruleContent: "rm:*" }], + behavior: "allow", + destination: "localSettings", + }, + ], + toolUseID: "tool-1", + suppressAlwaysAllowRule: true, + } as any); + + expect(request?.options.map((option) => option.optionId)).toEqual(["allow-once", "reject"]); + expect(request?._meta).toEqual({ permission: { version: 1, title: "Bash" } }); + }); + + it("leads with the reject option and forwards the hint when the CLI defaults to no", async () => { + let request: RequestPermissionRequest | undefined; + const mockClient = { + sessionUpdate: async () => {}, + requestPermission: async (params: RequestPermissionRequest) => { + request = params; + return { outcome: { outcome: "selected", optionId: "reject" } }; + }, + } as unknown as AcpClient; + const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} }); + agent.sessions["session-1"] = mockSessionState(); + agent.sessions["session-1"]!.emittedToolCalls.add("tool-1"); + + const result = await agent.canUseTool("session-1")("Bash", { command: "rm -rf build" }, { + signal: new AbortController().signal, + suggestions: [ + { + type: "addRules", + rules: [{ toolName: "Bash", ruleContent: "rm:*" }], + behavior: "allow", + destination: "localSettings", + }, + ], + toolUseID: "tool-1", + defaultToNo: true, + } as any); + + expect(request?.options.map((option) => option.kind)).toEqual([ + "reject_once", + "allow_once", + "allow_always", + ]); + expect(request?._meta).toEqual({ + permission: { version: 1, title: "Bash", defaultToNo: true }, + }); + expect(result).toMatchObject({ behavior: "deny" }); + }); }); describe("subagent permission attribution (issue #851)", () => { @@ -6547,6 +6620,52 @@ describe("stop reason propagation", () => { ); }); + it("says how long a no-response retry waited and will wait", async () => { + const updates: SessionNotification[] = []; + const agent = new ClaudeAcpAgent( + { + sessionUpdate: async (update: SessionNotification) => updates.push(update), + } as unknown as AcpClient, + { log: () => {}, error: () => {} }, + ); + (agent as any).clientCapabilities = airSessionFailureCapabilities; + injectSession(agent, [ + { + type: "system", + subtype: "api_retry", + attempt: 1, + max_retries: 1, + retry_delay_ms: 0, + error_status: null, + error: "unknown", + // SDK 0.3.261+: the API sent no response headers within the + // first-byte window; the retry waits longer for them. + no_response: { waited_ms: 180_000, retry_wait_ms: 600_000 }, + uuid: randomUUID(), + session_id: "test-session", + }, + createResultMessage({ + subtype: "success", + stop_reason: "end_turn", + is_error: false, + result: "ok", + }), + ]); + + await agent.prompt({ sessionId: "test-session", prompt: [{ type: "text", text: "test" }] }); + const warning = updates + .map((update) => (update.update._meta as any)?.jetbrains?.air?.sessionFailure) + .find(Boolean); + expect(warning).toEqual( + expect.objectContaining({ + category: "connection", + severity: "warning", + title: + "Reconnecting to Claude, attempt 1 of 1. No response after 180s; waiting up to 600s.", + }), + ); + }); + it("clears a connection retry warning internally after the turn succeeds", async () => { const updates: SessionNotification[] = []; const agent = new ClaudeAcpAgent( @@ -6656,6 +6775,8 @@ describe("stop reason propagation", () => { it.each([ ["billing_error", "limit"], ["account_on_hold", "limit"], + ["verification_required", "access"], + ["cloud_credential_error", "access"], ["rate_limit", "limit"], ["overloaded", "service"], ["invalid_request", "request"], @@ -13831,10 +13952,11 @@ describe("deferred settlement for live background subagents (issues #864/#866)", // out-of-turn session/update, but many clients stop consuming at the // prompt response, so the subagents' remaining output would be dropped // and their permission requests would block on an RPC nobody answers. The turn is held open - // across the CLI's idle cycles (observed cadence: user result → idle → - // subagent works → task_notification → followup turn → idle) and settles - // once its subagents are done — at the followup's terminal result, or at - // an idle with none of them left. + // across the CLI's idle cycles (cadence through CLI 2.1.269: user result → + // idle → subagent works → task_notification → followup turn → idle; from + // 2.1.270: no idle until the subagent drains) and settles once its + // subagents are done — at the followup's terminal result, or at an idle + // with none of them left. function createMockAgent() { const mockClient = { @@ -14017,6 +14139,59 @@ describe("deferred settlement for live background subagents (issues #864/#866)", await agent.sessions["test-session"]?.consumer; }); + // CLI 2.1.270+ stays `running` while background agents live (verified + // live: user result → task_notification → followup result → ONE idle), so + // the user result's trailing-idle debt is never paid. It must not linger: + // a stale unit would swallow a later un-owed idle (masking issue #825) or + // the idle a steered turn settles on. The next transition into `running` + // sweeps it. + it("settles under the 2.1.270 cadence and sweeps the unpaid idle debt at the next running", async () => { + const { agent, events } = chunkCapturingAgent(); + + injectGeneratorSession(agent, (input) => { + async function* messageGenerator() { + const iter = input[Symbol.asyncIterator](); + const { value: first } = await iter.next(); + yield userEcho(first); + yield running(); + yield subagentStarted("agent-1"); + yield resultMessage(); + // No idle here: the CLI is still `running` for the live subagent. + yield taskNotification("agent-1"); + yield assistantText("promised summary"); + yield resultMessage({ origin: { kind: "task-notification" } }); + yield idle(); // one idle for both results + const { value: second } = await iter.next(); + yield userEcho(second); + yield running(); + yield assistantText("second answer"); + yield resultMessage(); + yield idle(); + } + return messageGenerator(); + }); + + const session = () => agent.sessions["test-session"]!; + const first = await agent.prompt({ + sessionId: "test-session", + prompt: [{ type: "text", text: "explore" }], + }); + expect(first.stopReason).toBe("end_turn"); + expect(events.indexOf("chunk:promised summary")).toBeGreaterThanOrEqual(0); + // Two results, one idle: one unit of debt is left over. + await waitFor(() => session().owedTrailingIdles === 1); + + const second = await agent.prompt({ + sessionId: "test-session", + prompt: [{ type: "text", text: "again" }], + }); + expect(second.stopReason).toBe("end_turn"); + // The `running` transition swept the stale unit, so the second turn's + // own idle leaves nothing outstanding. + await waitFor(() => session().owedTrailingIdles === 0); + await agent.sessions["test-session"]?.consumer; + }); + it("falls back to settling at an idle when no followup comes", async () => { const agent = createMockAgent(); diff --git a/src/tests/model-presentation.test.ts b/src/tests/model-presentation.test.ts index e6647e70..18465c65 100644 --- a/src/tests/model-presentation.test.ts +++ b/src/tests/model-presentation.test.ts @@ -1,6 +1,3 @@ -import { readFileSync } from "node:fs"; -import { createRequire } from "node:module"; -import { dirname, join } from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { query, type ModelInfo, type Query } from "@anthropic-ai/claude-agent-sdk"; import { buildModelConfigOption, getAvailableModels } from "../session-model.js"; @@ -16,21 +13,6 @@ describe("versioned model display names", () => { beforeEach(() => vi.stubEnv("ANTHROPIC_MODEL", undefined)); afterEach(() => vi.unstubAllEnvs()); - it("requires reviewing the live model contract whenever the SDK is upgraded", () => { - const require = createRequire(import.meta.url); - const sdkPackage = JSON.parse( - readFileSync( - join(dirname(require.resolve("@anthropic-ai/claude-agent-sdk")), "package.json"), - "utf8", - ), - ); - expect( - sdkPackage.version, - "Run RUN_INTEGRATION_TESTS=true npx vitest run src/tests/model-presentation.test.ts " + - "and review the Opus name normalization before updating this version guard.", - ).toBe("0.3.257"); - }); - it("adds standard-family versions and preserves model identity and recommendation", async () => { const models: ModelInfo[] = [ { ...OPUS, value: "default", displayName: "Default (recommended)" }, diff --git a/src/tests/permission-options.test.ts b/src/tests/permission-options.test.ts index c7cdaa02..fc119b0e 100644 --- a/src/tests/permission-options.test.ts +++ b/src/tests/permission-options.test.ts @@ -29,6 +29,26 @@ describe("Claude permission options and response mapping", () => { contextUsedPercent, }); + it("leads with the reject options when the CLI defaults the ask to no", () => { + const changeSet = normalizeDurablePermissionChangeSet([ + { type: "addRules", rules: [rule], behavior: "allow", destination: "localSettings" }, + ]); + const context = { + toolName: "Bash", + input: { command: "npm test" }, + cwd: "/workspace", + durableChangeSet: changeSet, + }; + expect(buildClaudePermissionOptions(context).map((option) => option.kind)).toEqual([ + "allow_once", + "allow_always", + "reject_once", + ]); + expect( + buildClaudePermissionOptions({ ...context, defaultToNo: true }).map((option) => option.kind), + ).toEqual(["reject_once", "allow_once", "allow_always"]); + }); + it("builds the native Bash static-suggestions option from the exact update bundle", () => { const changeSet = normalizeDurablePermissionChangeSet([ { type: "addRules", rules: [rule], behavior: "allow", destination: "session" }, diff --git a/src/tests/permission-presentation.test.ts b/src/tests/permission-presentation.test.ts index f106b39d..083aa090 100644 --- a/src/tests/permission-presentation.test.ts +++ b/src/tests/permission-presentation.test.ts @@ -103,6 +103,26 @@ describe("Claude permission ACP v1 presentation", () => { }); }); + it("forwards the CLI's defaultToNo hint in the permission record", () => { + const presentation = buildClaudePermissionPresentation({ + toolName: "Bash", + input: { command: "rm -rf build" }, + toolUseID: "tool-1", + defaultToNo: true, + }); + expect(presentation._meta).toEqual({ + permission: { version: 1, title: "Bash", defaultToNo: true }, + }); + expect( + buildClaudePermissionPresentation({ + toolName: "Bash", + input: { command: "rm -rf build" }, + toolUseID: "tool-1", + defaultToNo: false, + })._meta, + ).toEqual({ permission: { version: 1, title: "Bash" } }); + }); + it("uses the human command description as the permission title", () => { const input = { command: "npm test", description: "Run the tests" }; const presentation = buildClaudePermissionPresentation({