mirror of
https://github.com/cline/cline.git
synced 2026-09-04 20:02:30 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9708da1ff3 | |||
| 4c85eaa7bb | |||
| c564045d81 | |||
| 9a5e1751b2 | |||
| 131e25e1a1 | |||
| a7ff007af9 | |||
| ef27f45080 | |||
| e3c6d51072 | |||
| 48bac25548 | |||
| 37f5f104f3 | |||
| 3577b52404 | |||
| 1843bc8ed0 | |||
| fead00ec57 | |||
| 238107d21c | |||
| 2063a661bd | |||
| ec02d5862e | |||
| 8452084842 |
@@ -8,8 +8,9 @@ HTTP-controlled debugger for the VSCode extension at `src/dev/debug-harness/serv
|
||||
# Build extension first if needed (protos + esbuild):
|
||||
bun run protos && IS_DEV=true bun esbuild.mjs
|
||||
|
||||
# Launch (skip-build if already built):
|
||||
bun src/dev/debug-harness/server.ts --skip-build --auto-launch
|
||||
# Launch (skip-build if already built). Run with node, NOT bun — Playwright's
|
||||
# Electron launch times out under bun:
|
||||
node src/dev/debug-harness/server.ts --skip-build --auto-launch
|
||||
|
||||
# In another terminal:
|
||||
curl localhost:19229/api -d '{"method":"status"}'
|
||||
|
||||
@@ -16,6 +16,7 @@ This file is the secret sauce for working effectively in this codebase. It captu
|
||||
- The whole repo (including `apps/vscode`) uses **bun** for package management and task running. Emit `bun run X` / `bun install` / `bunx <bin>` / `bun file.ts`, never npm/npx. Node remains the *runtime* (VS Code's extension host and the standalone cline-core are Node), so Node-runtime tokens are legitimate and must not be "fixed" to bun — see @.clinerules/bun-and-node.md for the keep-list vs rewrite-list.
|
||||
- Avoid provider-specific string matching / hardcoded provider branches when fixing provider/config plumbing. Prefer provider metadata, shared catalog/defaults, explicit protocol/client capabilities, or centralized normalization utilities that apply by data shape rather than `providerId === "..."`. If a provider exception seems necessary, stop and explain why instead of adding ad-hoc string matching.
|
||||
- This is a VS Code extension—check `package.json` for available scripts before trying to verify builds (e.g., `bun run compile`, not `bun run build`).
|
||||
- When reading a configuration files that users may edit, use `readFileStrippingUtf8Bom`, `readFileSyncStrippingUtf8Bom`, or `stripUtf8Bom` from `@cline/shared/node`. DON'T strip byte order marks of user files handled by tools/passed to models.
|
||||
- When creating PRs, contributors should not create changelog-entry files. Maintainers handle release versioning and changelog curation during the release process.
|
||||
- When adding new feature flags, see this PR as a reference https://github.com/cline/cline/pull/7566
|
||||
- Additional instructions about making requests: @.clinerules/network.md
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# Cline CLI Changelog
|
||||
|
||||
## 3.0.44
|
||||
|
||||
- Improved max output token handling across providers (gateway routing, OpenAI vendor, and reasoning models) (from SDK v0.0.64)
|
||||
- Frontmatter and configuration files that start with a UTF-8 byte order mark (e.g. saved by Windows editors) now parse correctly (from SDK v0.0.64)
|
||||
|
||||
## 3.0.43
|
||||
|
||||
- The CLI now automatically trusts your operating system's certificate store, so it works behind corporate proxies and TLS-inspecting firewalls without manually setting `NODE_EXTRA_CA_CERTS` (fixes "unable to get local issuer certificate" errors, including Windows intermediate CA stores)
|
||||
|
||||
## 3.0.42
|
||||
|
||||
- Fixed Ollama native API routing so context window and timeout settings work again
|
||||
|
||||
@@ -346,9 +346,24 @@ Desktop-integrated approval mode is also supported via env wiring (`CLINE_TOOL_A
|
||||
- `CLINE_LOG_LEVEL` - Runtime log level (`trace|debug|info|warn|error|fatal|silent`, default `info`)
|
||||
- `CLINE_LOG_PATH` - Runtime log file path (default `<CLINE_DATA_DIR>/logs/cline.log`)
|
||||
- `CLINE_LOG_NAME` - Logger name embedded in runtime log records
|
||||
- `CLINE_DEBUG` - Set to `1`/`true` to print wrapper diagnostics (e.g. the CA bundle summary)
|
||||
|
||||
`--key` takes precedence over environment variables.
|
||||
|
||||
## Certificate trust
|
||||
|
||||
The CLI automatically trusts your operating system's certificate store, so it
|
||||
works behind corporate TLS-inspecting proxies and with self-signed/internal
|
||||
endpoints without any setup. On launch the `cline` wrapper harvests the OS trust
|
||||
anchors and writes them to `~/.cline/cli-node-extra-ca-certs.pem`, then points
|
||||
the runtime's `NODE_EXTRA_CA_CERTS` at that bundle. The file is regenerated when
|
||||
it changes and is safe to delete (it is rebuilt on the next run).
|
||||
|
||||
If you set `NODE_EXTRA_CA_CERTS` yourself, your certificates are **merged** into
|
||||
that bundle alongside the system store rather than replacing it. Run with
|
||||
`CLINE_DEBUG=1` to see how many OS and user CAs were loaded and where the bundle
|
||||
was written.
|
||||
|
||||
## Contributing
|
||||
|
||||
See [DEVELOPMENT.md](./DEVELOPMENT.md) for local development setup, monorepo structure, and TUI architecture. See [DISTRIBUTION.md](./DISTRIBUTION.md) for how the CLI is packaged and distributed.
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
// Auto-discovery of OS trust anchors for the Cline CLI.
|
||||
//
|
||||
// Bun does not read the OS trust store, so the 3.x CLI cannot see corporate
|
||||
// MITM / self-signed CAs out of the box. This runs in the Node `bin/cline`
|
||||
// wrapper (not Bun), reads the full OS store via tls.getCACertificates("system")
|
||||
// (Node >= 22, no --use-system-ca flag), and hands the certs to the Bun child
|
||||
// via NODE_EXTRA_CA_CERTS, which both runtimes honor. Mirrors the JetBrains
|
||||
// plugin's configureCertificates(), sourcing from the OS instead of the IDE.
|
||||
//
|
||||
// Dependency-free CommonJS with injectable modules so it is unit-testable and
|
||||
// ships verbatim in the published wrapper package.
|
||||
|
||||
const PEM_MARKER = "-----BEGIN CERTIFICATE-----";
|
||||
const CERT_BLOCK =
|
||||
/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g;
|
||||
|
||||
/**
|
||||
* Returns only the complete certificate blocks from PEM text, or null when
|
||||
* there are none. User files may also hold private keys (combined cert+key
|
||||
* PEMs) or other sections, which must never be copied into the managed
|
||||
* bundle. Files that contain nothing but certificates pass through verbatim
|
||||
* so unchanged bundles keep hash-skipping the rewrite.
|
||||
*/
|
||||
function sanitizePem(text) {
|
||||
const blocks = text.match(CERT_BLOCK) ?? [];
|
||||
if (blocks.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const rest = text.replace(CERT_BLOCK, "");
|
||||
if (/^\s*$/.test(rest)) {
|
||||
return text;
|
||||
}
|
||||
return `${blocks.join("\n")}\n`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns OS-trusted certificates as PEM strings, or [] when unavailable.
|
||||
* tls.getCACertificates("system") requires Node >= 22.
|
||||
*/
|
||||
function harvestSystemCerts(tlsModule) {
|
||||
try {
|
||||
const tls = tlsModule || require("node:tls");
|
||||
if (typeof tls.getCACertificates !== "function") {
|
||||
return [];
|
||||
}
|
||||
const certs = tls.getCACertificates("system");
|
||||
if (!Array.isArray(certs)) {
|
||||
return [];
|
||||
}
|
||||
return certs.filter(
|
||||
(cert) => typeof cert === "string" && cert.includes(PEM_MARKER),
|
||||
);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file's certificate blocks as PEM text, or null when missing,
|
||||
* unreadable, or holding no complete certificate block.
|
||||
*/
|
||||
function readUserBundle(fsModule, userPath) {
|
||||
if (!userPath) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const fs = fsModule || require("node:fs");
|
||||
const stat = fs.statSync(userPath, { throwIfNoEntry: false });
|
||||
if (!stat || !stat.isFile()) {
|
||||
return null;
|
||||
}
|
||||
// Binary DER would not have loaded in the runtime either; require PEM.
|
||||
return sanitizePem(fs.readFileSync(userPath, "utf8"));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the user's NODE_EXTRA_CA_CERTS value into PEM strings. Node treats the
|
||||
* value as a single file, but some users set an OS-path-delimited list; the
|
||||
* whole value is tried as one file first, then split.
|
||||
* The managed bundle is excluded so reading it back never re-appends its certs.
|
||||
*/
|
||||
function readUserCerts(fsModule, pathModule, value, managedPath) {
|
||||
if (!value) {
|
||||
return [];
|
||||
}
|
||||
const fs = fsModule || require("node:fs");
|
||||
const path = pathModule || require("node:path");
|
||||
const candidates = [];
|
||||
const whole = readUserBundle(fs, value);
|
||||
if (whole) {
|
||||
candidates.push({ filePath: value, pem: whole });
|
||||
} else if (value.includes(path.delimiter)) {
|
||||
for (const segment of value.split(path.delimiter)) {
|
||||
const trimmed = segment.trim();
|
||||
if (!trimmed) {
|
||||
continue;
|
||||
}
|
||||
const pem = readUserBundle(fs, trimmed);
|
||||
if (pem) {
|
||||
candidates.push({ filePath: trimmed, pem });
|
||||
}
|
||||
}
|
||||
}
|
||||
const pems = [];
|
||||
for (const candidate of candidates) {
|
||||
const isManaged =
|
||||
managedPath &&
|
||||
path.resolve(candidate.filePath) === path.resolve(managedPath);
|
||||
if (!isManaged) {
|
||||
pems.push(candidate.pem);
|
||||
}
|
||||
}
|
||||
return pems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates the user PEMs (if any) and the system certificates into one
|
||||
* bundle. A separating newline is inserted between parts so adjacent END/BEGIN
|
||||
* markers cannot fuse into one invalid line.
|
||||
*/
|
||||
function buildBundle({ systemCerts, userPems }) {
|
||||
const parts = [...(userPems ?? []), ...systemCerts];
|
||||
return parts
|
||||
.map((part) => (part.endsWith("\n") ? part : `${part}\n`))
|
||||
.join("");
|
||||
}
|
||||
|
||||
/** Counts individual PEM certificates across the given bundle strings. */
|
||||
function countCerts(pems) {
|
||||
let count = 0;
|
||||
for (const pem of pems) {
|
||||
count += pem.split(PEM_MARKER).length - 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
function readFileIfExists(fs, filePath) {
|
||||
try {
|
||||
return fs.readFileSync(filePath, "utf8");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveClineDir(env, os, path) {
|
||||
return env.CLINE_DIR?.trim() || path.join(os.homedir(), ".cline");
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the api-unavailable warning should print. Stamped per Node version
|
||||
* in the cline dir so the nudge shows once rather than on every command; a
|
||||
* version change (upgrade that still falls short, or downgrade) re-arms it.
|
||||
* When the stamp cannot be read or written, warn — bookkeeping failures must
|
||||
* never suppress a real diagnostic.
|
||||
*/
|
||||
function shouldWarnApiUnavailable(env, deps = {}) {
|
||||
const fs = deps.fs || require("node:fs");
|
||||
const os = deps.os || require("node:os");
|
||||
const path = deps.path || require("node:path");
|
||||
const version = deps.nodeVersion || process.versions.node;
|
||||
const dir = resolveClineDir(env, os, path);
|
||||
const stamp = path.join(dir, `.ca-api-warned-${version}`);
|
||||
try {
|
||||
if (fs.existsSync(stamp)) {
|
||||
return false;
|
||||
}
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.writeFileSync(stamp, "", { mode: 0o600 });
|
||||
return true;
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Atomically writes [content] to [target]; returns true on success. */
|
||||
function writeBundle(fs, dir, target, content) {
|
||||
const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
|
||||
try {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
// Owner read/write: the bundle holds public CA material, not secrets,
|
||||
// but there is no reason to make it world-writable.
|
||||
fs.writeFileSync(tmp, content, { mode: 0o600 });
|
||||
try {
|
||||
fs.renameSync(tmp, target);
|
||||
} catch {
|
||||
// Windows can reject rename over a file a concurrent child holds open.
|
||||
fs.rmSync(target, { force: true });
|
||||
fs.renameSync(tmp, target);
|
||||
}
|
||||
return true;
|
||||
} catch {
|
||||
// Never leave a partial temp file behind (e.g. ENOSPC mid-write).
|
||||
try {
|
||||
fs.rmSync(tmp, { force: true });
|
||||
} catch {
|
||||
// Ignore: best-effort cleanup.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Harvests OS trust anchors, merges them with any user NODE_EXTRA_CA_CERTS, and
|
||||
* points env.NODE_EXTRA_CA_CERTS at a single managed PEM bundle. Mutates `env`
|
||||
* in place. Returns an outcome the caller can log; `action` is one of
|
||||
* "unchanged" | "written" | "write-failed-reused" | "write-failed" |
|
||||
* "no-system-certs" | "api-unavailable".
|
||||
*/
|
||||
function configureNodeExtraCaCerts(env, deps = {}) {
|
||||
const fs = deps.fs || require("node:fs");
|
||||
const os = deps.os || require("node:os");
|
||||
const path = deps.path || require("node:path");
|
||||
const tls = deps.tls || require("node:tls");
|
||||
|
||||
// tls.getCACertificates("system") needs Node >= 22.15; on older Nodes the
|
||||
// harvest cannot run at all, which the caller should surface to the user.
|
||||
if (typeof tls.getCACertificates !== "function") {
|
||||
return {
|
||||
action: "api-unavailable",
|
||||
path: null,
|
||||
systemCertCount: 0,
|
||||
userCertCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const systemCerts = harvestSystemCerts(tls);
|
||||
if (systemCerts.length === 0) {
|
||||
// Nothing to add: leave any user-provided NODE_EXTRA_CA_CERTS untouched
|
||||
// and let the runtime fall back to its bundled CAs.
|
||||
return {
|
||||
action: "no-system-certs",
|
||||
path: null,
|
||||
systemCertCount: 0,
|
||||
userCertCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const managedDir = resolveClineDir(env, os, path);
|
||||
const managedPath = path.join(managedDir, "cli-node-extra-ca-certs.pem");
|
||||
const userValue = (env.NODE_EXTRA_CA_CERTS || "").trim() || null;
|
||||
const userPems = readUserCerts(fs, path, userValue, managedPath);
|
||||
const bundle = buildBundle({ systemCerts, userPems });
|
||||
const base = {
|
||||
path: managedPath,
|
||||
systemCertCount: systemCerts.length,
|
||||
userCertCount: countCerts(userPems),
|
||||
};
|
||||
|
||||
// Skip the rewrite when the bundle is already current. Avoids per-launch I/O
|
||||
// and the concurrent-rename race in the steady state.
|
||||
if (readFileIfExists(fs, managedPath) === bundle) {
|
||||
env.NODE_EXTRA_CA_CERTS = managedPath;
|
||||
return { ...base, action: "unchanged" };
|
||||
}
|
||||
|
||||
if (writeBundle(fs, managedDir, managedPath, bundle)) {
|
||||
env.NODE_EXTRA_CA_CERTS = managedPath;
|
||||
return { ...base, action: "written" };
|
||||
}
|
||||
|
||||
// Write failed: fall back to a previously-written bundle if one exists.
|
||||
if (readFileIfExists(fs, managedPath)) {
|
||||
env.NODE_EXTRA_CA_CERTS = managedPath;
|
||||
return { ...base, action: "write-failed-reused" };
|
||||
}
|
||||
return { ...base, path: null, action: "write-failed" };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
harvestSystemCerts,
|
||||
sanitizePem,
|
||||
readUserBundle,
|
||||
readUserCerts,
|
||||
buildBundle,
|
||||
countCerts,
|
||||
configureNodeExtraCaCerts,
|
||||
shouldWarnApiUnavailable,
|
||||
};
|
||||
@@ -23,6 +23,48 @@ const childEnv = {
|
||||
CLINE_WRAPPER_PATH: scriptPath,
|
||||
};
|
||||
|
||||
// Auto-discover OS trust anchors and pass them to the Bun child via
|
||||
// NODE_EXTRA_CA_CERTS. The Bun runtime does not read the OS store on its own,
|
||||
// so corporate/self-signed CAs would otherwise fail. This wrapper runs on
|
||||
// Node, which can read the full store here.
|
||||
try {
|
||||
const caCerts = require("./ca-certs.cjs");
|
||||
const outcome = caCerts.configureNodeExtraCaCerts(childEnv);
|
||||
const debug =
|
||||
process.env.CLINE_DEBUG === "1" || process.env.CLINE_DEBUG === "true";
|
||||
// Not debug-gated: on old Nodes the harvest silently doing nothing is
|
||||
// indistinguishable from a broken corporate proxy. Stamped per Node
|
||||
// version so the nudge shows once, not on every command.
|
||||
if (
|
||||
outcome &&
|
||||
outcome.action === "api-unavailable" &&
|
||||
!childEnv.NODE_EXTRA_CA_CERTS &&
|
||||
caCerts.shouldWarnApiUnavailable(childEnv)
|
||||
) {
|
||||
console.warn(
|
||||
`[cline] Node ${process.versions.node} cannot read the OS trust store (needs >= 22.15); ` +
|
||||
"corporate or self-signed CAs may fail TLS. Upgrade Node or set NODE_EXTRA_CA_CERTS.",
|
||||
);
|
||||
}
|
||||
if (debug && outcome) {
|
||||
if (outcome.action === "no-system-certs") {
|
||||
console.warn(
|
||||
"[cline] No OS trust anchors found; relying on the runtime's bundled CAs.",
|
||||
);
|
||||
} else if (outcome.action === "write-failed") {
|
||||
console.warn(
|
||||
"[cline] Could not write the managed CA bundle; relying on the runtime's bundled CAs.",
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
`[cline] Trust: ${outcome.systemCertCount} OS + ${outcome.userCertCount} user CAs (${outcome.action}) -> ${outcome.path}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Best effort: fall back to the runtime's default trust on any failure.
|
||||
}
|
||||
|
||||
function run(target) {
|
||||
const result = childProcess.spawnSync(target, process.argv.slice(2), {
|
||||
stdio: "inherit",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@cline/cli",
|
||||
"displayName": "cline",
|
||||
"version": "3.0.42",
|
||||
"version": "3.0.44",
|
||||
"description": "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more",
|
||||
"type": "module",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { delimiter, join } from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
// The helper ships as CommonJS in the published wrapper package, so it is
|
||||
// loaded via require rather than an ESM import.
|
||||
const caCerts = require("../../bin/ca-certs.cjs") as {
|
||||
harvestSystemCerts: (tls?: unknown) => string[];
|
||||
readUserBundle: (fs: unknown, p: string | null) => string | null;
|
||||
readUserCerts: (
|
||||
fs: unknown,
|
||||
path: unknown,
|
||||
value: string | null,
|
||||
managedPath: string | null,
|
||||
) => string[];
|
||||
buildBundle: (input: {
|
||||
systemCerts: string[];
|
||||
userPems?: string[];
|
||||
}) => string;
|
||||
countCerts: (pems: string[]) => number;
|
||||
configureNodeExtraCaCerts: (
|
||||
env: Record<string, string>,
|
||||
deps?: { tls?: unknown; fs?: unknown },
|
||||
) => {
|
||||
action: string;
|
||||
path: string | null;
|
||||
systemCertCount: number;
|
||||
userCertCount: number;
|
||||
};
|
||||
shouldWarnApiUnavailable: (
|
||||
env: Record<string, string>,
|
||||
deps?: { fs?: unknown; nodeVersion?: string },
|
||||
) => boolean;
|
||||
};
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const certSystem =
|
||||
"-----BEGIN CERTIFICATE-----\nSYSTEM\n-----END CERTIFICATE-----\n";
|
||||
const certUser = "-----BEGIN CERTIFICATE-----\nUSER\n-----END CERTIFICATE-----";
|
||||
|
||||
function fakeTls(certs: unknown) {
|
||||
return { getCACertificates: () => certs };
|
||||
}
|
||||
|
||||
describe("ca-certs", () => {
|
||||
let dir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
dir = mkdtempSync(join(tmpdir(), "cline-ca-"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe("harvestSystemCerts", () => {
|
||||
it("returns only PEM strings from the system store", () => {
|
||||
expect(
|
||||
caCerts.harvestSystemCerts(fakeTls([certSystem, "not-a-cert", 42])),
|
||||
).toEqual([certSystem]);
|
||||
});
|
||||
|
||||
it("returns [] when getCACertificates is unavailable", () => {
|
||||
expect(caCerts.harvestSystemCerts({})).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns [] when getCACertificates throws", () => {
|
||||
expect(
|
||||
caCerts.harvestSystemCerts({
|
||||
getCACertificates: () => {
|
||||
throw new Error("nope");
|
||||
},
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("readUserBundle", () => {
|
||||
it("returns PEM contents for a PEM file", () => {
|
||||
const p = join(dir, "user.pem");
|
||||
writeFileSync(p, certUser);
|
||||
expect(caCerts.readUserBundle(fs, p)).toBe(certUser);
|
||||
});
|
||||
|
||||
it("returns null for a non-PEM (DER) file", () => {
|
||||
const p = join(dir, "user.der");
|
||||
writeFileSync(p, Buffer.from([0x30, 0x82, 0x01, 0x02]));
|
||||
expect(caCerts.readUserBundle(fs, p)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for a missing file and for null path", () => {
|
||||
expect(caCerts.readUserBundle(fs, join(dir, "nope.pem"))).toBeNull();
|
||||
expect(caCerts.readUserBundle(fs, null)).toBeNull();
|
||||
});
|
||||
|
||||
it("strips non-certificate sections such as private keys", () => {
|
||||
// Combined cert+key files (nginx/haproxy style) are common; the key
|
||||
// must never reach the managed bundle.
|
||||
const p = join(dir, "combined.pem");
|
||||
writeFileSync(
|
||||
p,
|
||||
`${certUser}\n-----BEGIN PRIVATE KEY-----\nSECRET\n-----END PRIVATE KEY-----\n`,
|
||||
);
|
||||
const out = caCerts.readUserBundle(fs, p);
|
||||
expect(out).toContain("USER");
|
||||
expect(out).not.toContain("PRIVATE KEY");
|
||||
expect(out).not.toContain("SECRET");
|
||||
});
|
||||
|
||||
it("keeps certificates-only files verbatim", () => {
|
||||
// Byte-identical passthrough keeps the unchanged-skip hash stable.
|
||||
const p = join(dir, "clean.pem");
|
||||
writeFileSync(p, `${certUser}\n${certSystem}`);
|
||||
expect(caCerts.readUserBundle(fs, p)).toBe(`${certUser}\n${certSystem}`);
|
||||
});
|
||||
|
||||
it("returns null for a BEGIN marker without a complete block", () => {
|
||||
const p = join(dir, "truncated.pem");
|
||||
writeFileSync(p, "-----BEGIN CERTIFICATE-----\ntruncated");
|
||||
expect(caCerts.readUserBundle(fs, p)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("readUserCerts", () => {
|
||||
it("reads a single PEM file path", () => {
|
||||
const p = join(dir, "corp.pem");
|
||||
writeFileSync(p, certUser);
|
||||
expect(caCerts.readUserCerts(fs, path, p, null)).toEqual([certUser]);
|
||||
});
|
||||
|
||||
it("splits a legacy OS-path-delimited value and reads each PEM", () => {
|
||||
// Legacy footgun: NODE_EXTRA_CA_CERTS="a.pem;b.pem".
|
||||
const a = join(dir, "a.pem");
|
||||
const b = join(dir, "b.pem");
|
||||
writeFileSync(a, certUser);
|
||||
writeFileSync(b, certSystem);
|
||||
expect(
|
||||
caCerts.readUserCerts(fs, path, [a, b].join(delimiter), null),
|
||||
).toEqual([certUser, certSystem]);
|
||||
});
|
||||
|
||||
it("skips missing segments in a delimited value", () => {
|
||||
const a = join(dir, "a.pem");
|
||||
writeFileSync(a, certUser);
|
||||
const value = [a, join(dir, "missing.pem")].join(delimiter);
|
||||
expect(caCerts.readUserCerts(fs, path, value, null)).toEqual([certUser]);
|
||||
});
|
||||
|
||||
it("excludes the managed bundle from user certs", () => {
|
||||
const managed = join(dir, "cli-node-extra-ca-certs.pem");
|
||||
writeFileSync(managed, certUser);
|
||||
expect(caCerts.readUserCerts(fs, path, managed, managed)).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns [] for empty value", () => {
|
||||
expect(caCerts.readUserCerts(fs, path, null, null)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildBundle", () => {
|
||||
it("merges user PEMs before system certs", () => {
|
||||
expect(
|
||||
caCerts.buildBundle({
|
||||
systemCerts: [certSystem],
|
||||
userPems: [certUser],
|
||||
}),
|
||||
).toBe(`${certUser}\n${certSystem}`);
|
||||
});
|
||||
|
||||
it("inserts a separating newline so END/BEGIN markers do not fuse", () => {
|
||||
// certUser has no trailing newline, so this proves the boundary fix.
|
||||
const merged = caCerts.buildBundle({
|
||||
systemCerts: [certSystem],
|
||||
userPems: [certUser],
|
||||
});
|
||||
expect(merged).not.toContain(
|
||||
"-----END CERTIFICATE----------BEGIN CERTIFICATE-----",
|
||||
);
|
||||
});
|
||||
|
||||
it("handles no user PEMs", () => {
|
||||
expect(caCerts.buildBundle({ systemCerts: [certSystem] })).toBe(
|
||||
certSystem,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("configureNodeExtraCaCerts", () => {
|
||||
it("writes a managed bundle and points the env var at it", () => {
|
||||
const env: Record<string, string> = { CLINE_DIR: dir };
|
||||
const out = caCerts.configureNodeExtraCaCerts(env, {
|
||||
tls: fakeTls([certSystem]),
|
||||
});
|
||||
expect(out.action).toBe("written");
|
||||
expect(out.path).toBe(join(dir, "cli-node-extra-ca-certs.pem"));
|
||||
expect(env.NODE_EXTRA_CA_CERTS).toBe(out.path);
|
||||
expect(readFileSync(out.path as string, "utf8")).toContain("SYSTEM");
|
||||
});
|
||||
|
||||
it("merges a user-supplied NODE_EXTRA_CA_CERTS with system certs", () => {
|
||||
const userPath = join(dir, "corp.pem");
|
||||
writeFileSync(userPath, certUser);
|
||||
const env: Record<string, string> = {
|
||||
CLINE_DIR: dir,
|
||||
NODE_EXTRA_CA_CERTS: userPath,
|
||||
};
|
||||
const out = caCerts.configureNodeExtraCaCerts(env, {
|
||||
tls: fakeTls([certSystem]),
|
||||
});
|
||||
expect(out.userCertCount).toBe(1);
|
||||
const written = readFileSync(env.NODE_EXTRA_CA_CERTS, "utf8");
|
||||
expect(written).toContain("USER");
|
||||
expect(written).toContain("SYSTEM");
|
||||
});
|
||||
|
||||
it("reports unchanged and skips rewrite on the second run", () => {
|
||||
const env: Record<string, string> = { CLINE_DIR: dir };
|
||||
expect(
|
||||
caCerts.configureNodeExtraCaCerts(env, { tls: fakeTls([certSystem]) })
|
||||
.action,
|
||||
).toBe("written");
|
||||
expect(
|
||||
caCerts.configureNodeExtraCaCerts(env, { tls: fakeTls([certSystem]) })
|
||||
.action,
|
||||
).toBe("unchanged");
|
||||
});
|
||||
|
||||
it("does not re-append when the user already points at the managed bundle", () => {
|
||||
const env: Record<string, string> = { CLINE_DIR: dir };
|
||||
const first = caCerts.configureNodeExtraCaCerts(env, {
|
||||
tls: fakeTls([certSystem]),
|
||||
}).path as string;
|
||||
const env2: Record<string, string> = {
|
||||
CLINE_DIR: dir,
|
||||
NODE_EXTRA_CA_CERTS: first,
|
||||
};
|
||||
caCerts.configureNodeExtraCaCerts(env2, { tls: fakeTls([certSystem]) });
|
||||
const written = readFileSync(env2.NODE_EXTRA_CA_CERTS, "utf8");
|
||||
expect(written.match(/SYSTEM/g)?.length).toBe(1);
|
||||
});
|
||||
|
||||
it("no-ops when no system certs are available", () => {
|
||||
const env: Record<string, string> = {
|
||||
CLINE_DIR: dir,
|
||||
NODE_EXTRA_CA_CERTS: "/user/corp.pem",
|
||||
};
|
||||
const out = caCerts.configureNodeExtraCaCerts(env, { tls: fakeTls([]) });
|
||||
expect(out.action).toBe("no-system-certs");
|
||||
expect(out.path).toBeNull();
|
||||
expect(env.NODE_EXTRA_CA_CERTS).toBe("/user/corp.pem");
|
||||
});
|
||||
|
||||
it("reports api-unavailable on Nodes without getCACertificates", () => {
|
||||
const env: Record<string, string> = {
|
||||
CLINE_DIR: dir,
|
||||
NODE_EXTRA_CA_CERTS: "/user/corp.pem",
|
||||
};
|
||||
const out = caCerts.configureNodeExtraCaCerts(env, { tls: {} });
|
||||
expect(out.action).toBe("api-unavailable");
|
||||
expect(out.path).toBeNull();
|
||||
expect(env.NODE_EXTRA_CA_CERTS).toBe("/user/corp.pem");
|
||||
});
|
||||
|
||||
it("reports write-failed when the bundle cannot be written", () => {
|
||||
const realFs = require("node:fs");
|
||||
const failingFs = {
|
||||
...realFs,
|
||||
mkdirSync: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
writeFileSync: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
};
|
||||
const env: Record<string, string> = { CLINE_DIR: dir };
|
||||
const out = caCerts.configureNodeExtraCaCerts(env, {
|
||||
tls: fakeTls([certSystem]),
|
||||
fs: failingFs,
|
||||
});
|
||||
expect(out.action).toBe("write-failed");
|
||||
expect(out.path).toBeNull();
|
||||
expect(env.NODE_EXTRA_CA_CERTS).toBeUndefined();
|
||||
});
|
||||
|
||||
it("reuses a stale bundle when the rewrite fails", () => {
|
||||
// First run writes the bundle normally.
|
||||
const env: Record<string, string> = { CLINE_DIR: dir };
|
||||
const managedPath = caCerts.configureNodeExtraCaCerts(env, {
|
||||
tls: fakeTls([certSystem]),
|
||||
}).path as string;
|
||||
|
||||
// Second run: writes fail, but the stale bundle is still readable.
|
||||
const realFs = require("node:fs");
|
||||
const failingFs = {
|
||||
...realFs,
|
||||
mkdirSync: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
writeFileSync: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
};
|
||||
const env2: Record<string, string> = { CLINE_DIR: dir };
|
||||
const out = caCerts.configureNodeExtraCaCerts(env2, {
|
||||
// A different system cert forces a rewrite attempt (not "unchanged").
|
||||
tls: fakeTls([certUser]),
|
||||
fs: failingFs,
|
||||
});
|
||||
|
||||
expect(out.action).toBe("write-failed-reused");
|
||||
expect(env2.NODE_EXTRA_CA_CERTS).toBe(managedPath);
|
||||
});
|
||||
});
|
||||
|
||||
describe("countCerts", () => {
|
||||
it("counts individual certificates, not files", () => {
|
||||
// One file holding two certs must report 2, not 1.
|
||||
const twoInOne = `${certUser}\n${certSystem}`;
|
||||
expect(caCerts.countCerts([twoInOne])).toBe(2);
|
||||
expect(caCerts.countCerts([certUser, certSystem])).toBe(2);
|
||||
expect(caCerts.countCerts([])).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldWarnApiUnavailable", () => {
|
||||
it("warns once per Node version, then stays quiet", () => {
|
||||
const env = { CLINE_DIR: dir };
|
||||
const deps = { nodeVersion: "22.1.0" };
|
||||
expect(caCerts.shouldWarnApiUnavailable(env, deps)).toBe(true);
|
||||
expect(caCerts.shouldWarnApiUnavailable(env, deps)).toBe(false);
|
||||
});
|
||||
|
||||
it("re-arms when the Node version changes", () => {
|
||||
const env = { CLINE_DIR: dir };
|
||||
expect(
|
||||
caCerts.shouldWarnApiUnavailable(env, { nodeVersion: "22.1.0" }),
|
||||
).toBe(true);
|
||||
expect(
|
||||
caCerts.shouldWarnApiUnavailable(env, { nodeVersion: "22.14.0" }),
|
||||
).toBe(true);
|
||||
expect(
|
||||
caCerts.shouldWarnApiUnavailable(env, { nodeVersion: "22.1.0" }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("still warns when the stamp cannot be written", () => {
|
||||
const realFs = require("node:fs");
|
||||
const failingFs = {
|
||||
...realFs,
|
||||
mkdirSync: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
writeFileSync: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
};
|
||||
const env = { CLINE_DIR: dir };
|
||||
const deps = { fs: failingFs, nodeVersion: "22.1.0" };
|
||||
// Bookkeeping failure must never suppress the diagnostic.
|
||||
expect(caCerts.shouldWarnApiUnavailable(env, deps)).toBe(true);
|
||||
expect(caCerts.shouldWarnApiUnavailable(env, deps)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
||||
import { existsSync, readdirSync } from "node:fs";
|
||||
import { homedir } from "node:os";
|
||||
import { basename, extname, join } from "node:path";
|
||||
import {
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type SkillConfig,
|
||||
type WorkflowConfig,
|
||||
} from "@cline/core";
|
||||
import { readFileSyncStrippingUtf8Bom } from "@cline/shared/node";
|
||||
import { Command } from "commander";
|
||||
import { getToolCatalog } from "../runtime/tools";
|
||||
import { loadInteractiveConfigData } from "../tui/interactive-config";
|
||||
@@ -209,7 +210,7 @@ async function runAgentsConfigCommand(
|
||||
continue;
|
||||
}
|
||||
const filePath = join(directory, entry.name);
|
||||
const raw = readFileSync(filePath, "utf8");
|
||||
const raw = readFileSyncStrippingUtf8Bom(filePath);
|
||||
const frontmatterMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
||||
const frontmatter = frontmatterMatch?.[1] ?? "";
|
||||
const nameMatch = frontmatter.match(/^\s*name:\s*(.+?)\s*$/m);
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { version as cliVersion } from "../../package.json";
|
||||
import { getCliBuildInfo } from "../utils/common";
|
||||
|
||||
const {
|
||||
@@ -174,6 +175,40 @@ describe("runDoctorCommand", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("reports CLI and running hub Core versions", async () => {
|
||||
const cwd = "/workspace";
|
||||
mockReadHubDiscovery.mockResolvedValue({
|
||||
url: "ws://127.0.0.1:25463/hub",
|
||||
port: 25463,
|
||||
pid: 50174,
|
||||
coreVersion: "0.0.63",
|
||||
});
|
||||
mockProbeHubServer.mockResolvedValue({
|
||||
url: "ws://127.0.0.1:25463/hub",
|
||||
port: 25463,
|
||||
pid: 50174,
|
||||
coreVersion: "0.0.64",
|
||||
});
|
||||
mockSpawnSync.mockReturnValue({ status: 1, stdout: "" });
|
||||
|
||||
const output: string[] = [];
|
||||
const code = await runDoctorCommand(
|
||||
{ cwd, json: true },
|
||||
{
|
||||
writeln: (text) => {
|
||||
output.push(text ?? "");
|
||||
},
|
||||
writeErr: () => {},
|
||||
},
|
||||
);
|
||||
|
||||
expect(code).toBe(0);
|
||||
expect(JSON.parse(output[0] || "")).toMatchObject({
|
||||
cliVersion,
|
||||
coreVersion: "0.0.64",
|
||||
});
|
||||
});
|
||||
|
||||
it("doctor --fix clears wedged hub startup artifacts when no server is actually running", async () => {
|
||||
const cwd = mkdtempSync(path.join(os.tmpdir(), "doctor-hub-fix-"));
|
||||
tempDirs.push(cwd);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { formatUptime, resolveClineBuildEnv } from "@cline/shared";
|
||||
import { Command } from "commander";
|
||||
import open from "open";
|
||||
import { version as cliVersion } from "../../package.json";
|
||||
import { isProcessRunning } from "../connectors/common";
|
||||
import {
|
||||
type ActiveConnectorRecord,
|
||||
@@ -49,6 +50,8 @@ type SpawnedProcessRecord = {
|
||||
|
||||
type DoctorStatus = {
|
||||
cwd: string;
|
||||
cliVersion: string;
|
||||
coreVersion?: string;
|
||||
hubUrl?: string;
|
||||
hubHealthy: boolean;
|
||||
hubPid?: number;
|
||||
@@ -337,6 +340,8 @@ async function collectDoctorStatus(cwd: string): Promise<DoctorStatus> {
|
||||
];
|
||||
return {
|
||||
cwd,
|
||||
cliVersion,
|
||||
coreVersion: health?.coreVersion ?? discovery?.coreVersion,
|
||||
hubUrl: current?.url,
|
||||
hubHealthy: !!health?.url,
|
||||
hubPid: current?.pid,
|
||||
@@ -419,6 +424,8 @@ export async function runDoctorCommand(
|
||||
io.writeln(JSON.stringify(before));
|
||||
return 0;
|
||||
}
|
||||
writeln(`cli version ${c.dim}${before.cliVersion}${c.reset}`);
|
||||
writeln(`core version ${c.dim}${before.coreVersion ?? "n/a"}${c.reset}`);
|
||||
writeln(`hub url ${c.dim}${before.hubUrl ?? "none"}${c.reset}`);
|
||||
writeln(
|
||||
`hub healthy ${c.dim}${before.hubHealthy ? "yes" : "no"}${before.hubPid ? ` (pid=${before.hubPid})` : ""}${c.reset}`,
|
||||
|
||||
@@ -34,6 +34,7 @@ vi.mock("@cline/core", () => ({
|
||||
stopLocalHubServerGracefully: mockStopLocalHubServerGracefully,
|
||||
}));
|
||||
|
||||
import { version as cliVersion } from "../../package.json";
|
||||
import { createHubCommand } from "./hub";
|
||||
|
||||
const originalBuildEnv = process.env.CLINE_BUILD_ENV;
|
||||
@@ -63,6 +64,7 @@ describe("createHubCommand", () => {
|
||||
port: 25463,
|
||||
pid: 50174,
|
||||
startedAt: "2026-01-01T00:00:00.000Z",
|
||||
coreVersion: "0.0.62",
|
||||
});
|
||||
|
||||
const output: string[] = [];
|
||||
@@ -88,6 +90,8 @@ describe("createHubCommand", () => {
|
||||
pid: 50174,
|
||||
startedAt: "2026-01-01T00:00:00.000Z",
|
||||
uptime: "1m 5s",
|
||||
cliVersion,
|
||||
coreVersion: "0.0.62",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from "@cline/core";
|
||||
import { formatUptime, resolveClineBuildEnv } from "@cline/shared";
|
||||
import { Command } from "commander";
|
||||
import { version as cliVersion } from "../../package.json";
|
||||
|
||||
interface HubCommandIo {
|
||||
writeln: (text?: string) => void;
|
||||
@@ -134,6 +135,8 @@ export function createHubCommand(
|
||||
pid: health?.pid,
|
||||
startedAt: health?.startedAt,
|
||||
uptime,
|
||||
cliVersion,
|
||||
coreVersion: health?.coreVersion ?? discovery?.coreVersion,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -228,6 +228,22 @@ export async function getOrCreateSessionId<
|
||||
sessionId,
|
||||
metadata: {
|
||||
transport: input.transport,
|
||||
// Delivery descriptor for this connector thread. Lets the
|
||||
// agent-facing schedule_task tool (deliverTo: "connector") post a
|
||||
// scheduled run's result back into this thread, reusing the same
|
||||
// per-adapter delivery path as user-typed /schedule.
|
||||
delivery: {
|
||||
adapter: input.transport,
|
||||
threadId: input.thread.id,
|
||||
bindingKey: input.thread.id,
|
||||
...(input.thread.channelId
|
||||
? { channelId: input.thread.channelId }
|
||||
: {}),
|
||||
...(threadState.participantKey
|
||||
? { participantKey: threadState.participantKey }
|
||||
: {}),
|
||||
...(input.hookBotUserName ? { userName: input.hookBotUserName } : {}),
|
||||
},
|
||||
...input.sessionMetadata,
|
||||
...(remoteConfigMetadata ?? {}),
|
||||
...(threadState.participantKey
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
type UserInstructionConfigService,
|
||||
type WorkflowConfig,
|
||||
} from "@cline/core";
|
||||
import { readFileSyncStrippingUtf8Bom } from "@cline/shared/node";
|
||||
import { getToolCatalog } from "../runtime/tools";
|
||||
import {
|
||||
type InteractiveSlashCommand,
|
||||
@@ -195,7 +196,7 @@ function loadAgentConfigItems(workspaceRoot: string): InteractiveConfigItem[] {
|
||||
continue;
|
||||
}
|
||||
const filePath = join(directory, entry.name);
|
||||
const raw = readFileSync(filePath, "utf8");
|
||||
const raw = readFileSyncStrippingUtf8Bom(filePath);
|
||||
const frontmatterMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
||||
const frontmatter = frontmatterMatch?.[1] ?? "";
|
||||
const nameMatch = frontmatter.match(/^\s*name:\s*(.+?)\s*$/m);
|
||||
|
||||
@@ -352,6 +352,7 @@ function HistoryListContent({
|
||||
fg={isSel ? palette.textOnSelection : undefined}
|
||||
flexGrow={1}
|
||||
>
|
||||
{row.source === "schedule" ? "⏰ " : ""}
|
||||
{title}
|
||||
</text>
|
||||
{showCost && cost != null && cost > 0 && (
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
resolvePluginConfigSearchPaths,
|
||||
resolveAgentConfigSearchPaths as resolveSharedAgentConfigSearchPaths,
|
||||
} from "@cline/core";
|
||||
import { readFileSyncStrippingUtf8Bom } from "@cline/shared/node";
|
||||
import { readMcpServersResponse } from "./mcp";
|
||||
import type { JsonRecord } from "./types";
|
||||
|
||||
@@ -114,7 +115,7 @@ export async function listUserInstructionConfigs(
|
||||
const ext = extname(entry.name).toLowerCase();
|
||||
if (ext !== ".yml" && ext !== ".yaml") continue;
|
||||
const filePath = join(directory, entry.name);
|
||||
const raw = readFileSync(filePath, "utf8");
|
||||
const raw = readFileSyncStrippingUtf8Bom(filePath);
|
||||
const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
||||
const fm = fmMatch?.[1] ?? "";
|
||||
const nameMatch = fm.match(/^\s*name:\s*(.+?)\s*$/m);
|
||||
|
||||
@@ -4,11 +4,26 @@ import {
|
||||
consumeWorkspaceMetadata,
|
||||
handleChatSessionCommand,
|
||||
prewarmWorkspaceMetadata,
|
||||
rewriteDesktopTeamPrompt,
|
||||
shouldUpdateSessionConnection,
|
||||
WORKSPACE_METADATA_PREWARM_TTL_MS,
|
||||
} from "./chat-session";
|
||||
import type { SidecarContext } from "./types";
|
||||
|
||||
describe("rewriteDesktopTeamPrompt", () => {
|
||||
it("rewrites /team for the core runtime", () => {
|
||||
expect(rewriteDesktopTeamPrompt("/team inspect the app", new Set())).toBe(
|
||||
'<user_command slash="team">spawn a team of agents for the following task: inspect the app</user_command>',
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects /team when the Teams tool is disabled", () => {
|
||||
expect(() =>
|
||||
rewriteDesktopTeamPrompt("/team inspect the app", new Set(["teams"])),
|
||||
).toThrow("Agent teams are disabled");
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildSessionConnectionUpdate", () => {
|
||||
it("does not clear reasoning settings when config omits reasoning fields", () => {
|
||||
const update = buildSessionConnectionUpdate({
|
||||
|
||||
@@ -6,12 +6,13 @@ import {
|
||||
buildWorkspaceMetadata,
|
||||
type ClineCore,
|
||||
type CoreSessionConfig,
|
||||
readGlobalSettings,
|
||||
type SessionPendingPrompt,
|
||||
SessionSource,
|
||||
splitCoreSessionConfig,
|
||||
} from "@cline/core";
|
||||
import type { Message } from "@cline/llms";
|
||||
import { buildClineSystemPrompt } from "@cline/shared";
|
||||
import { buildClineSystemPrompt, formatUserCommandBlock } from "@cline/shared";
|
||||
import { emitChunk, nowMs, sendEvent } from "./context";
|
||||
import { readSessionManifest, sharedSessionDataDir } from "./paths";
|
||||
import type {
|
||||
@@ -37,6 +38,31 @@ const workspaceMetadataPromises = new Map<
|
||||
WorkspaceMetadataCacheEntry
|
||||
>();
|
||||
|
||||
export function rewriteDesktopTeamPrompt(
|
||||
prompt: string,
|
||||
disabledTools: ReadonlySet<string> = new Set(
|
||||
readGlobalSettings().disabledTools ?? [],
|
||||
),
|
||||
): string {
|
||||
const match = /^\/team\b([\s\S]*)$/i.exec(prompt.trim());
|
||||
if (!match) return prompt;
|
||||
const task = match[1]?.trim();
|
||||
if (!task) {
|
||||
throw new Error(
|
||||
"Usage: /team <task description>. Starts a team of agents for the given task.",
|
||||
);
|
||||
}
|
||||
if (disabledTools.has("teams")) {
|
||||
throw new Error(
|
||||
"Agent teams are disabled. Enable the Teams tool in Customizations → Tools.",
|
||||
);
|
||||
}
|
||||
return formatUserCommandBlock(
|
||||
`spawn a team of agents for the following task: ${task}`,
|
||||
"team",
|
||||
);
|
||||
}
|
||||
|
||||
function getWorkspaceMetadataPromise(
|
||||
cwd: string,
|
||||
load: WorkspaceMetadataLoader,
|
||||
@@ -217,16 +243,6 @@ function buildCoreSessionConfig(config: JsonRecord): JsonRecord {
|
||||
systemPrompt: config.systemPrompt ?? config.system_prompt ?? "",
|
||||
maxIterations: config.maxIterations ?? config.max_iterations,
|
||||
enableTools: config.enableTools ?? config.enable_tools ?? true,
|
||||
enableSpawnAgent:
|
||||
config.enableSpawn ??
|
||||
config.enableSpawnAgent ??
|
||||
config.enable_spawn ??
|
||||
false,
|
||||
enableAgentTeams:
|
||||
config.enableTeams ??
|
||||
config.enableAgentTeams ??
|
||||
config.enable_teams ??
|
||||
false,
|
||||
...(thinking !== undefined ? { thinking } : {}),
|
||||
...(reasoningEffort ? { reasoningEffort } : {}),
|
||||
...(thinkingBudgetTokens !== undefined ? { thinkingBudgetTokens } : {}),
|
||||
@@ -518,6 +534,7 @@ async function handleSend(
|
||||
if (!sessionId) throw new Error("sessionId is required");
|
||||
const prompt = request.prompt?.trim();
|
||||
if (!prompt) throw new Error("prompt is required");
|
||||
const runtimePrompt = rewriteDesktopTeamPrompt(prompt);
|
||||
const manager = getSessionManager(ctx);
|
||||
const session = ctx.liveSessions.get(sessionId);
|
||||
if (request.config) {
|
||||
@@ -551,7 +568,7 @@ async function handleSend(
|
||||
// turn finishes and emit pending_prompts / pending_prompt_submitted events.
|
||||
await manager.send({
|
||||
sessionId,
|
||||
prompt,
|
||||
prompt: runtimePrompt,
|
||||
delivery: "queue",
|
||||
userImages: request.attachments?.userImages,
|
||||
});
|
||||
@@ -575,7 +592,7 @@ async function handleSend(
|
||||
);
|
||||
const result = await manager.send({
|
||||
sessionId,
|
||||
prompt,
|
||||
prompt: runtimePrompt,
|
||||
delivery,
|
||||
userImages: request.attachments?.userImages,
|
||||
});
|
||||
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
updateMcpSettingsFileSync,
|
||||
} from "@cline/core";
|
||||
import { getClineEnvironmentConfig } from "@cline/shared";
|
||||
import { readFileSyncStrippingUtf8Bom } from "@cline/shared/node";
|
||||
import {
|
||||
connectorChannelsPayload,
|
||||
startConnectorChannel,
|
||||
@@ -558,7 +559,7 @@ async function listUserInstructionConfigs(
|
||||
const ext = extname(entry.name).toLowerCase();
|
||||
if (ext !== ".yml" && ext !== ".yaml") continue;
|
||||
const filePath = join(directory, entry.name);
|
||||
const raw = readFileSync(filePath, "utf8");
|
||||
const raw = readFileSyncStrippingUtf8Bom(filePath);
|
||||
const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
||||
const fm = fmMatch?.[1] ?? "";
|
||||
const nameMatch = fm.match(/^\s*name:\s*(.+?)\s*$/m);
|
||||
@@ -637,6 +638,8 @@ async function listUserInstructionConfigs(
|
||||
|
||||
const disabledTools = new Set(readGlobalSettings().disabledTools ?? []);
|
||||
const builtinToolCatalog = getCoreBuiltinToolCatalog({
|
||||
enableSpawnAgent: true,
|
||||
enableAgentTeams: true,
|
||||
disabledToolIds: disabledTools,
|
||||
});
|
||||
|
||||
|
||||
@@ -706,7 +706,7 @@ export function ChatInputBar({
|
||||
value={editingQueuedPromptValue}
|
||||
/>
|
||||
) : (
|
||||
<div className="line-clamp-2 whitespace-pre-wrap break-words text-xs text-foreground">
|
||||
<div className="line-clamp-2 whitespace-pre-wrap wrap-break-word text-xs text-foreground">
|
||||
{item.prompt}
|
||||
</div>
|
||||
)}
|
||||
@@ -1097,7 +1097,7 @@ export function ChatInputBar({
|
||||
>
|
||||
<SelectTrigger
|
||||
aria-label="Thinking level"
|
||||
className="h-7 min-w-[5.75rem] gap-1.5 border-0 bg-muted px-2 text-[11px] shadow-none data-[size=sm]:h-7 max-[560px]:col-span-2 max-[560px]:col-start-1 max-[560px]:row-start-2"
|
||||
className="h-7 min-w-23 gap-1.5 border-0 bg-muted px-2 text-[11px] shadow-none data-[size=sm]:h-7 max-[560px]:col-span-2 max-[560px]:col-start-1 max-[560px]:row-start-2"
|
||||
size="sm"
|
||||
title={
|
||||
modelSupportsReasoning === false
|
||||
|
||||
@@ -124,8 +124,6 @@ export function normalizeRuntimeConfig(
|
||||
cwd: normalizedCwd || normalizedWorkspaceRoot,
|
||||
thinking,
|
||||
reasoningEffort: thinking === false ? undefined : config.reasoningEffort,
|
||||
enableSpawn: false,
|
||||
enableTeams: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -56,4 +56,16 @@ describe("parseYamlFrontmatter", () => {
|
||||
expect(result.data).to.deep.equal({ count: 42, enabled: true, tags: ["a", "b"] })
|
||||
expect(result.body.trim()).to.equal("Content")
|
||||
})
|
||||
|
||||
// Regression test for https://github.com/cline/cline/issues/12151
|
||||
// A leading UTF-8 BOM (e.g. saved by Windows Notepad's "UTF-8 with BOM" encoding) must not
|
||||
// prevent frontmatter from being recognized.
|
||||
it("parses frontmatter correctly when the content has a leading UTF-8 BOM", () => {
|
||||
const input = `\uFEFF---\nname: my-skill\ndescription: A test skill\n---\n# my-skill\nThis is a test skill.`
|
||||
const result = parseYamlFrontmatter(input)
|
||||
expect(result.hadFrontmatter).to.equal(true)
|
||||
expect(result.parseError).to.equal(undefined)
|
||||
expect(result.data).to.deep.equal({ name: "my-skill", description: "A test skill" })
|
||||
expect(result.body.trim()).to.equal("# my-skill\nThis is a test skill.")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -139,6 +139,34 @@ Instructions here`)
|
||||
expect(skills[0].source).to.equal("global")
|
||||
})
|
||||
|
||||
// Regression test for https://github.com/cline/cline/issues/12151:
|
||||
// SKILL.md files saved with a UTF-8 BOM (e.g. by Windows Notepad's "UTF-8 with BOM"
|
||||
// encoding) were silently skipped because the frontmatter regex required "---" at the
|
||||
// very start of the file and never accounted for the leading \uFEFF byte sequence.
|
||||
it("should discover skills whose SKILL.md starts with a UTF-8 BOM", async () => {
|
||||
const skillDir = path.join(GLOBAL_SKILLS_DIR, "my-skill")
|
||||
const skillMdPath = path.join(skillDir, "SKILL.md")
|
||||
|
||||
fileExistsStub.withArgs(GLOBAL_SKILLS_DIR).resolves(true)
|
||||
fileExistsStub.withArgs(skillMdPath).resolves(true)
|
||||
isDirectoryStub.withArgs(GLOBAL_SKILLS_DIR).resolves(true)
|
||||
readdirStub.withArgs(GLOBAL_SKILLS_DIR).resolves(["my-skill"])
|
||||
statStub.withArgs(skillDir).resolves({ isDirectory: () => true })
|
||||
readFileStub.withArgs(skillMdPath, "utf-8").resolves(`\uFEFF---
|
||||
name: my-skill
|
||||
description: A test skill
|
||||
---
|
||||
# my-skill
|
||||
This is a test skill.`)
|
||||
|
||||
const skills = await discoverSkills(TEST_CWD)
|
||||
|
||||
expect(skills).to.have.lengthOf(1)
|
||||
expect(skills[0].name).to.equal("my-skill")
|
||||
expect(skills[0].description).to.equal("A test skill")
|
||||
expect(skills[0].source).to.equal("global")
|
||||
})
|
||||
|
||||
it("should discover skills from project .clinerules/skills directory", async () => {
|
||||
const projectSkillsDir = path.join(TEST_CWD, ".clinerules", "skills")
|
||||
const skillDir = path.join(projectSkillsDir, "explaining-code")
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { stripUtf8Bom } from "@cline/shared"
|
||||
import * as yaml from "js-yaml"
|
||||
|
||||
export type FrontmatterParseResult = {
|
||||
@@ -35,11 +36,16 @@ export type FrontmatterParseResult = {
|
||||
* - If no frontmatter exists, returns data={} and body=original markdown.
|
||||
*/
|
||||
export function parseYamlFrontmatter(markdown: string): FrontmatterParseResult {
|
||||
// Strip a leading UTF-8 BOM (e.g. added by Windows Notepad's "UTF-8 with BOM" encoding),
|
||||
// which Node's `utf-8` decoding does not strip on its own. Without this the frontmatter
|
||||
// regex below never matches a file that starts with "\uFEFF---" (see cline/cline#12151).
|
||||
const normalizedMarkdown = stripUtf8Bom(markdown)
|
||||
|
||||
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/
|
||||
const match = markdown.match(frontmatterRegex)
|
||||
const match = normalizedMarkdown.match(frontmatterRegex)
|
||||
|
||||
if (!match) {
|
||||
return { data: {}, body: markdown, hadFrontmatter: false }
|
||||
return { data: {}, body: normalizedMarkdown, hadFrontmatter: false }
|
||||
}
|
||||
|
||||
const [, yamlContent, body] = match
|
||||
@@ -48,6 +54,6 @@ export function parseYamlFrontmatter(markdown: string): FrontmatterParseResult {
|
||||
return { data, body, hadFrontmatter: true }
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
return { data: {}, body: markdown, hadFrontmatter: true, parseError: message }
|
||||
return { data: {}, body: normalizedMarkdown, hadFrontmatter: true, parseError: message }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,14 +236,11 @@ export async function updateSettings(controller: Controller, request: UpdateSett
|
||||
|
||||
// Update default terminal profile
|
||||
if (request.defaultTerminalProfile !== undefined) {
|
||||
const previousProfile = controller.stateManager.getGlobalSettingsKey("defaultTerminalProfile")
|
||||
controller.stateManager.setGlobalState("defaultTerminalProfile", request.defaultTerminalProfile)
|
||||
// Update the live terminal manager so new terminals use the new profile.
|
||||
// Existing terminals are left open — they're keyed by effective shell
|
||||
// and reused when compatible, or skipped when not.
|
||||
controller.terminalManager?.setDefaultTerminalProfile(request.defaultTerminalProfile)
|
||||
// Rebuild the session so the run_commands tool description names the new shell.
|
||||
controller.handleTerminalProfileChanged(previousProfile, request.defaultTerminalProfile)
|
||||
}
|
||||
|
||||
if (request.backgroundEditEnabled !== undefined) {
|
||||
|
||||
@@ -189,14 +189,11 @@ export async function updateSettingsCli(controller: Controller, request: UpdateS
|
||||
|
||||
// Update default terminal profile
|
||||
if (defaultTerminalProfile !== undefined && defaultTerminalProfile !== "") {
|
||||
const previousProfile = controller.stateManager.getGlobalSettingsKey("defaultTerminalProfile")
|
||||
controller.stateManager.setGlobalState("defaultTerminalProfile", defaultTerminalProfile)
|
||||
// Update the live terminal manager so new terminals use the new profile.
|
||||
// Existing terminals are left open — they're keyed by effective shell
|
||||
// and reused when compatible, or skipped when not.
|
||||
controller.terminalManager?.setDefaultTerminalProfile(defaultTerminalProfile)
|
||||
// Rebuild the session so the run_commands tool description names the new shell.
|
||||
controller.handleTerminalProfileChanged(previousProfile, defaultTerminalProfile)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@ Designed to be driven from an agentic loop via `curl` commands.
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Terminal 1: Start the debug harness server
|
||||
bun src/dev/debug-harness/server.ts --auto-launch --skip-build
|
||||
# Terminal 1: Start the debug harness server.
|
||||
# Run with node, NOT bun — Playwright's Electron launch times out under bun.
|
||||
node src/dev/debug-harness/server.ts --auto-launch --skip-build
|
||||
|
||||
# Terminal 2: Interact via curl
|
||||
curl localhost:19229/api -d '{"method":"status"}'
|
||||
@@ -27,7 +28,7 @@ curl localhost:19229/api -d '{"method":"ui.screenshot"}'
|
||||
## Server Options
|
||||
|
||||
```
|
||||
bun src/dev/debug-harness/server.ts [options]
|
||||
node src/dev/debug-harness/server.ts [options]
|
||||
|
||||
Options:
|
||||
--skip-build Skip building extension/webview (use existing dist/)
|
||||
@@ -42,7 +43,7 @@ Options:
|
||||
```bash
|
||||
# This builds protos, extension (unminified+sourcemaps), webview (unminified+sourcemaps),
|
||||
# downloads VSCode, launches it, and connects CDP to the extension host.
|
||||
bun src/dev/debug-harness/server.ts --auto-launch
|
||||
node src/dev/debug-harness/server.ts --auto-launch
|
||||
```
|
||||
|
||||
## Data Isolation
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bun
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Debug Harness Server
|
||||
@@ -10,7 +10,12 @@
|
||||
* - UI automation (click, type, screenshot) via Playwright
|
||||
*
|
||||
* Usage:
|
||||
* bun src/dev/debug-harness/server.ts [options]
|
||||
* node src/dev/debug-harness/server.ts [options]
|
||||
*
|
||||
* Run with node, not bun: Playwright's _electron.launch() never finishes
|
||||
* attaching to the debugee under bun (the Electron process starts, but the
|
||||
* launch times out), while the same launch works under node. Node >= 22.6
|
||||
* runs this file directly via type stripping.
|
||||
*
|
||||
* Options:
|
||||
* --skip-build Skip building extension/webview
|
||||
@@ -39,7 +44,6 @@ import path from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { downloadAndUnzipVSCode, SilentReporter } from "@vscode/test-electron"
|
||||
import { _electron, type CDPSession, type ElectronApplication, type Frame, type Page } from "playwright"
|
||||
import WebSocket from "ws"
|
||||
|
||||
const __script_dir = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
@@ -201,19 +205,21 @@ class CdpClient {
|
||||
|
||||
async connect(wsUrl: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// The runtime's built-in WebSocket (browser-style events), so the
|
||||
// harness has no dependency on the `ws` package.
|
||||
const ws = new WebSocket(wsUrl)
|
||||
ws.on("open", () => {
|
||||
ws.addEventListener("open", () => {
|
||||
this.ws = ws
|
||||
resolve()
|
||||
})
|
||||
ws.on("error", (e: Error) => {
|
||||
if (!this.ws) reject(e)
|
||||
ws.addEventListener("error", () => {
|
||||
if (!this.ws) reject(new Error(`WebSocket connection failed: ${wsUrl}`))
|
||||
})
|
||||
ws.on("close", () => {
|
||||
ws.addEventListener("close", () => {
|
||||
this.ws = null
|
||||
})
|
||||
ws.on("message", (raw: WebSocket.Data) => {
|
||||
const msg = JSON.parse(raw.toString())
|
||||
ws.addEventListener("message", (event: MessageEvent) => {
|
||||
const msg = JSON.parse(typeof event.data === "string" ? event.data : Buffer.from(event.data).toString())
|
||||
if (msg.id !== undefined) {
|
||||
const p = this.pending.get(msg.id)
|
||||
if (p) {
|
||||
|
||||
@@ -46,7 +46,6 @@ import { ShowMessageRequest, ShowMessageType } from "@/shared/proto/host/window"
|
||||
import { Logger } from "@/shared/services/Logger"
|
||||
import { isClineManagedProvider } from "@/shared/utils/cline"
|
||||
import { arePathsEqual, getDesktopDir } from "@/utils/path"
|
||||
import { getShellForProfile } from "@/utils/shell"
|
||||
import { ClineAccountService } from "./account-service"
|
||||
import { AuthService, LogoutReason } from "./auth-service"
|
||||
import { buildStartSessionInput, createHistoryItemFromSession } from "./cline-session-factory"
|
||||
@@ -360,11 +359,9 @@ export class Controller {
|
||||
onSendStart: () => {
|
||||
this.beginProviderFailureTelemetryTurn()
|
||||
},
|
||||
// this.mode and this.terminalExecutionMode are assigned later in this
|
||||
// constructor; the closures only run at send time, long after
|
||||
// construction completes.
|
||||
// this.mode is assigned later in this constructor; the closure only
|
||||
// runs at send time, long after construction completes.
|
||||
consumeModeSwitchNotice: (sessionId) => this.mode.consumeModeSwitchNotice(sessionId),
|
||||
consumeShellChangeNotice: (sessionId) => this.terminalExecutionMode.consumeShellChangeNotice(sessionId),
|
||||
onSendComplete: async () => {
|
||||
// Normal flows close their diff sessions inline; anything left here is orphaned.
|
||||
void this.diffEdits.discardAllPreviews("turn complete")
|
||||
@@ -485,7 +482,6 @@ export class Controller {
|
||||
buildStartSessionInput,
|
||||
postStateToWebview: () => this.postStateToWebview(),
|
||||
rebuilds: this.sessionRebuilds,
|
||||
resolveShellForProfile: getShellForProfile,
|
||||
})
|
||||
this.providerChanges = new SdkProviderChangeCoordinator({
|
||||
stateManager: this.stateManager,
|
||||
@@ -652,10 +648,6 @@ export class Controller {
|
||||
this.terminalExecutionMode.handleTerminalExecutionModeChanged(previous, next)
|
||||
}
|
||||
|
||||
handleTerminalProfileChanged(previous: string | undefined, next: string): void {
|
||||
this.terminalExecutionMode.handleTerminalProfileChanged(previous, next)
|
||||
}
|
||||
|
||||
private handleSessionBecameIdle(): void {
|
||||
if (this.mode?.hasPendingModeChange()) {
|
||||
// The mode rebuild reads the latest provider and tool configuration, so
|
||||
|
||||
@@ -454,13 +454,35 @@ describe("SdkDiffEditCoordinator", () => {
|
||||
expect(callOrder).toEqual(["close", "apply"])
|
||||
})
|
||||
|
||||
it("applies patches without preview sessions directly", async () => {
|
||||
it("shows a brief preview around auto-approved patches", async () => {
|
||||
await writeFile("patched.ts", "line one\nline two\n")
|
||||
const patch = ["*** Begin Patch", "*** Update File: patched.ts", "@@", "-line one", "+line ONE", "*** End Patch"].join(
|
||||
"\n",
|
||||
)
|
||||
|
||||
const result = await coordinator.executeApplyPatchTool({ input: patch }, tempDir, makeContext("tc9"))
|
||||
|
||||
expect(result).toBe("fallback apply_patch result")
|
||||
expect(fallbackApplyPatch).toHaveBeenCalledOnce()
|
||||
expect(previews).toHaveLength(1)
|
||||
expect(previews[0].opened).toMatchObject({
|
||||
absolutePath: path.join(tempDir, "patched.ts"),
|
||||
leftContent: "line one\nline two\n",
|
||||
rightContent: "line ONE\nline two\n",
|
||||
})
|
||||
expect(previews[0].closed).toBe(1)
|
||||
})
|
||||
|
||||
it("applies auto-approved patches without a preview when background edit is enabled", async () => {
|
||||
backgroundEdit = true
|
||||
const result = await coordinator.executeApplyPatchTool(
|
||||
{ input: "*** Begin Patch\n*** End Patch" },
|
||||
tempDir,
|
||||
makeContext("tc9"),
|
||||
)
|
||||
|
||||
expect(result).toBe("fallback apply_patch result")
|
||||
expect(fallbackApplyPatch).toHaveBeenCalledOnce()
|
||||
expect(previews).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -122,12 +122,32 @@ export class SdkDiffEditCoordinator {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `apply_patch` tool executor override: close the preview, then delegate the
|
||||
* whole patch application to the SDK's default executor.
|
||||
* The `apply_patch` tool executor override: manually-approved patches close their
|
||||
* approval preview before applying; auto-approved patches show a brief preview
|
||||
* around execution, matching the `editor` tool behavior.
|
||||
*/
|
||||
async executeApplyPatchTool(input: ApplyPatchInput, cwd: string, context: AgentToolContext): Promise<string> {
|
||||
await this.discardPreview(context.toolCallId ?? "")
|
||||
return this.fallbackApplyPatchExecutor(input, cwd, context)
|
||||
const toolCallId = context.toolCallId ?? ""
|
||||
const hadPreApprovalPreview = this.sessions.has(toolCallId)
|
||||
try {
|
||||
if (hadPreApprovalPreview) {
|
||||
await this.discardPreview(toolCallId)
|
||||
} else if (!this.options.isBackgroundEditEnabled()) {
|
||||
try {
|
||||
await this.openPatchPreview(toolCallId, input)
|
||||
} catch (error) {
|
||||
Logger.warn(`[SdkDiffEditCoordinator] Failed to show auto-approve patch preview: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
const result = await this.fallbackApplyPatchExecutor(input, cwd, context)
|
||||
if (!hadPreApprovalPreview && this.sessions.get(toolCallId)?.preview) {
|
||||
await lingerDelay(this.autoApprovePreviewLingerMs, context.signal)
|
||||
}
|
||||
return result
|
||||
} finally {
|
||||
await this.discardPreview(toolCallId)
|
||||
}
|
||||
}
|
||||
|
||||
/** Closes one preview (reject / abort / edit applied). Never throws; unknown ids are a no-op. */
|
||||
|
||||
@@ -611,61 +611,6 @@ describe("SdkSessionLifecycle", () => {
|
||||
|
||||
expect(send).toHaveBeenCalledWith(expect.objectContaining({ prompt: "hello" }))
|
||||
})
|
||||
|
||||
it("stamps a pending shell-change notice onto the outbound prompt", async () => {
|
||||
const send = vi.fn().mockResolvedValue(undefined)
|
||||
const sdkHost = makeSdkHost({ send })
|
||||
mockCreateSessionHost.mockResolvedValueOnce(sdkHost)
|
||||
let pending: { from: string; to: string } | null = { from: "powershell", to: "cmd.exe" }
|
||||
const consumeShellChangeNotice = vi.fn(() => {
|
||||
const notice = pending
|
||||
pending = null
|
||||
return notice
|
||||
})
|
||||
const lifecycle = makeLifecycle({ consumeShellChangeNotice })
|
||||
// biome-ignore lint/suspicious/noExplicitAny: focused fake for lifecycle unit test
|
||||
await lifecycle.startNewSession({} as any)
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: focused fake for lifecycle unit test
|
||||
lifecycle.fireAndForgetSend(sdkHost as any, "session-123", "list the files")
|
||||
await vi.waitFor(() => expect(send).toHaveBeenCalledTimes(1))
|
||||
expect(send).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
prompt: "<environment_notice>The user changed the terminal shell from PowerShell to cmd.exe before sending this message. Commands now run through cmd.exe; write all subsequent commands in cmd.exe syntax.</environment_notice>\nlist the files",
|
||||
}),
|
||||
)
|
||||
|
||||
// Consumed by the first send; the next message is clean.
|
||||
// biome-ignore lint/suspicious/noExplicitAny: focused fake for lifecycle unit test
|
||||
lifecycle.fireAndForgetSend(sdkHost as any, "session-123", "now build")
|
||||
await vi.waitFor(() => expect(send).toHaveBeenCalledTimes(2))
|
||||
expect(send).toHaveBeenLastCalledWith(expect.objectContaining({ prompt: "now build" }))
|
||||
})
|
||||
|
||||
it("stamps pending mode and shell notices together, mode first", async () => {
|
||||
const send = vi.fn().mockResolvedValue(undefined)
|
||||
const sdkHost = makeSdkHost({ send })
|
||||
mockCreateSessionHost.mockResolvedValueOnce(sdkHost)
|
||||
const lifecycle = makeLifecycle({
|
||||
consumeModeSwitchNotice: vi.fn(() => ({ from: "plan" as const, to: "act" as const })),
|
||||
consumeShellChangeNotice: vi.fn(() => ({ from: "powershell", to: "cmd.exe" })),
|
||||
})
|
||||
// biome-ignore lint/suspicious/noExplicitAny: focused fake for lifecycle unit test
|
||||
await lifecycle.startNewSession({} as any)
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: focused fake for lifecycle unit test
|
||||
lifecycle.fireAndForgetSend(sdkHost as any, "session-123", "do it")
|
||||
await vi.waitFor(() => expect(send).toHaveBeenCalled())
|
||||
|
||||
expect(send).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
prompt:
|
||||
"<mode_notice>The user switched from plan mode to act mode before sending this message.</mode_notice>\n" +
|
||||
"<environment_notice>The user changed the terminal shell from PowerShell to cmd.exe before sending this message. Commands now run through cmd.exe; write all subsequent commands in cmd.exe syntax.</environment_notice>\n" +
|
||||
"do it",
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
function makeLifecycle(overrides: Partial<ConstructorParameters<typeof SdkSessionLifecycle>[0]> = {}) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
RestoreResult,
|
||||
StartSessionResult,
|
||||
} from "@cline/core"
|
||||
import { formatModeSwitchNotice, formatShellChangeNotice, type ModeSwitchNotice, type ShellChangeNotice } from "@cline/shared"
|
||||
import { formatModeSwitchNotice, type ModeSwitchNotice } from "@cline/shared"
|
||||
import { StateManager } from "@/core/storage/StateManager"
|
||||
import type { VscodeTerminalManager } from "@/hosts/vscode/terminal/VscodeTerminalManager"
|
||||
import { McpHub } from "@/services/mcp/McpHub"
|
||||
@@ -49,13 +49,6 @@ export interface SdkSessionLifecycleOptions {
|
||||
* message. Consumed exactly once; null when no switch is pending.
|
||||
*/
|
||||
consumeModeSwitchNotice?: (sessionId: string) => ModeSwitchNotice | null
|
||||
/**
|
||||
* Returns (and clears) a pending terminal-shell change recorded by
|
||||
* SdkTerminalExecutionModeCoordinator for this session, stamped as an
|
||||
* <environment_notice> the same way. Independent of the mode notice; when
|
||||
* both are pending, both are stamped onto the same message.
|
||||
*/
|
||||
consumeShellChangeNotice?: (sessionId: string) => ShellChangeNotice | null
|
||||
onDidBecomeIdle?: () => void
|
||||
}
|
||||
|
||||
@@ -371,22 +364,14 @@ export class SdkSessionLifecycle {
|
||||
Logger.debug(`[SdkController] Ignoring ${label} of superseded send for session: ${sessionId}`)
|
||||
return true
|
||||
}
|
||||
// Mark preceding user-initiated setting changes on this message so the
|
||||
// model sees exactly when the rules changed: a plan/act switch (mirrors
|
||||
// the CLI's run-interactive stamping) and/or a terminal-shell change.
|
||||
// Each notice is tracked and consumed independently, so either, both, or
|
||||
// neither may be present. The notices survive prepareTurnInput's
|
||||
// normalizeUserInput sanitize and are hidden from display surfaces by
|
||||
// stripRuntimeNotices.
|
||||
const modeNotice = this.options.consumeModeSwitchNotice?.(sessionId)
|
||||
const shellNotice = this.options.consumeShellChangeNotice?.(sessionId)
|
||||
const noticedPrompt = [
|
||||
modeNotice ? formatModeSwitchNotice(modeNotice.from, modeNotice.to) : undefined,
|
||||
shellNotice ? formatShellChangeNotice(shellNotice.from, shellNotice.to) : undefined,
|
||||
prompt,
|
||||
]
|
||||
.filter((part): part is string => part !== undefined)
|
||||
.join("\n")
|
||||
// Mark a preceding user-initiated mode switch on this message so the model
|
||||
// sees exactly when the rules changed, instead of only inferring it from
|
||||
// the user_input mode attribute flipping (mirrors the CLI's
|
||||
// run-interactive stamping). The notice survives prepareTurnInput's
|
||||
// normalizeUserInput sanitize and is hidden from display surfaces by
|
||||
// stripModeNotices.
|
||||
const notice = this.options.consumeModeSwitchNotice?.(sessionId)
|
||||
const noticedPrompt = notice ? `${formatModeSwitchNotice(notice.from, notice.to)}\n${prompt}` : prompt
|
||||
this.options.onSendStart?.(sessionId)
|
||||
sdkHost
|
||||
.send({
|
||||
|
||||
@@ -13,13 +13,6 @@ vi.mock("@/shared/services/Logger", () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
/** Profile-to-shell mapping used by the injected resolveShellForProfile. */
|
||||
const SHELL_BY_PROFILE: Record<string, string> = {
|
||||
default: "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
||||
powershell: "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
||||
cmd: "C:\\Windows\\System32\\cmd.exe",
|
||||
}
|
||||
|
||||
describe("SdkTerminalExecutionModeCoordinator", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
@@ -42,86 +35,6 @@ describe("SdkTerminalExecutionModeCoordinator", () => {
|
||||
expect(options.sessions.replaceActiveSession).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("does nothing when the terminal profile did not change", () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator, options } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalProfileChanged("powershell", "powershell")
|
||||
|
||||
expect(options.rebuilds.request).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("treats undefined and 'default' as the same profile", () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator, options } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalProfileChanged(undefined, "default")
|
||||
|
||||
expect(options.rebuilds.request).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("requests a rebuild when the terminal profile changes", async () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator, options } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalProfileChanged("default", "cmd")
|
||||
|
||||
expect(options.rebuilds.request).toHaveBeenCalledWith("terminalExecutionMode", expect.any(Function))
|
||||
})
|
||||
|
||||
it("records a shell notice for the active session when the profile changes shell", () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalProfileChanged("default", "cmd")
|
||||
|
||||
expect(coordinator.consumeShellChangeNotice("some-other-task")).toBeNull()
|
||||
expect(coordinator.consumeShellChangeNotice("old-session")).toEqual({
|
||||
from: SHELL_BY_PROFILE.default,
|
||||
to: SHELL_BY_PROFILE.cmd,
|
||||
})
|
||||
expect(coordinator.consumeShellChangeNotice("old-session")).toBeNull()
|
||||
})
|
||||
|
||||
it("records no shell notice when the new profile resolves to the same shell", () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator, options } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalProfileChanged("default", "powershell")
|
||||
|
||||
expect(coordinator.consumeShellChangeNotice("old-session")).toBeNull()
|
||||
// The tool description still names the (unchanged) shell correctly; the
|
||||
// rebuild is cheap and keeps profile bookkeeping in one place.
|
||||
expect(options.rebuilds.request).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("cancels the shell notice when the user switches back before sending", () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalProfileChanged("default", "cmd")
|
||||
coordinator.handleTerminalProfileChanged("cmd", "default")
|
||||
|
||||
expect(coordinator.consumeShellChangeNotice("old-session")).toBeNull()
|
||||
})
|
||||
|
||||
it("records no shell notice without an active session", () => {
|
||||
const { coordinator } = makeCoordinator()
|
||||
|
||||
coordinator.handleTerminalProfileChanged("default", "cmd")
|
||||
|
||||
expect(coordinator.consumeShellChangeNotice("old-session")).toBeNull()
|
||||
})
|
||||
|
||||
it("records no shell notice for execution mode changes", () => {
|
||||
const activeSession = makeActiveSession()
|
||||
const { coordinator } = makeCoordinator({ activeSession })
|
||||
|
||||
coordinator.handleTerminalExecutionModeChanged("backgroundExec", "vscodeTerminal")
|
||||
|
||||
expect(coordinator.consumeShellChangeNotice("old-session")).toBeNull()
|
||||
})
|
||||
|
||||
it("schedules restart while the active session is running", () => {
|
||||
const activeSession = makeActiveSession({ isRunning: true })
|
||||
const { coordinator, options } = makeCoordinator({ activeSession })
|
||||
@@ -231,7 +144,6 @@ function makeCoordinator(input: Partial<MakeCoordinatorInput> = {}) {
|
||||
loadInitialMessages: vi.fn().mockResolvedValue([{ role: "user", content: "hello" }]),
|
||||
buildStartSessionInput: vi.fn(() => ({ prompt: "start" })),
|
||||
postStateToWebview: vi.fn().mockResolvedValue(undefined),
|
||||
resolveShellForProfile: vi.fn((profileId: string) => SHELL_BY_PROFILE[profileId] ?? SHELL_BY_PROFILE.default),
|
||||
rebuilds: {
|
||||
request: vi.fn((_reason: string, rebuild: () => Promise<void>) => {
|
||||
if (!initialRebuildScheduled && !activeSession?.isRunning) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { createShellChangeNoticeTracker, type ShellChangeNotice, type ShellChangeNoticeTracker } from "@cline/shared"
|
||||
import type { ClineMessage } from "@shared/ExtensionMessage"
|
||||
import type { Mode } from "@shared/storage/types"
|
||||
import type { StateManager } from "@/core/storage/StateManager"
|
||||
@@ -25,90 +24,17 @@ export interface SdkTerminalExecutionModeCoordinatorOptions {
|
||||
buildStartSessionInput: (config: SessionConfig, input: { cwd: string; mode: Mode }) => StartInput
|
||||
postStateToWebview: () => Promise<void>
|
||||
rebuilds: Pick<SdkSessionRebuildScheduler, "request">
|
||||
/**
|
||||
* Maps a terminal profile ID to the shell it runs (getShellForProfile).
|
||||
* Injected so shell-notice decisions are testable without VS Code config.
|
||||
*/
|
||||
resolveShellForProfile: (profileId: string) => string
|
||||
}
|
||||
|
||||
export class SdkTerminalExecutionModeCoordinator {
|
||||
/**
|
||||
* Pending shell change, stamped as an <environment_notice> onto the next
|
||||
* outbound message by SdkSessionLifecycle.fireAndForgetSend. Tracked over
|
||||
* resolved shells rather than profile IDs so profile changes that keep the
|
||||
* same shell (e.g. "default" -> "powershell" where default is PowerShell)
|
||||
* record nothing, and a round trip back to the shell the model last used
|
||||
* cancels out. Session-scoped like SdkModeCoordinator's mode notice: the
|
||||
* setting is global, so the notice stays pending for the recorded session
|
||||
* even if the user visits another task before sending.
|
||||
*/
|
||||
private shellChangeNoticeTracker: ShellChangeNoticeTracker = createShellChangeNoticeTracker()
|
||||
private shellChangeNoticeSessionId: string | null = null
|
||||
|
||||
constructor(private readonly options: SdkTerminalExecutionModeCoordinatorOptions) {}
|
||||
|
||||
handleTerminalExecutionModeChanged(previous: VscodeTerminalExecutionMode, next: VscodeTerminalExecutionMode): void {
|
||||
if (previous === next) {
|
||||
return
|
||||
}
|
||||
// No shell notice: both modes resolve the shell from the same profile
|
||||
// setting, so the shell does not change with the execution mode.
|
||||
this.requestRebuild(`Terminal execution mode changed: ${previous} -> ${next}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* The terminal profile selects the shell, and the run_commands tool
|
||||
* description names that shell, so a profile change requires the same
|
||||
* session rebuild as an execution mode change — plus a conversation
|
||||
* notice, since the transcript's earlier commands still model the old
|
||||
* shell's syntax.
|
||||
*/
|
||||
handleTerminalProfileChanged(previous: string | undefined, next: string): void {
|
||||
if ((previous || "default") === (next || "default")) {
|
||||
return
|
||||
}
|
||||
this.recordShellChangeNotice(previous || "default", next || "default")
|
||||
this.requestRebuild(`Terminal profile changed: ${previous ?? "default"} -> ${next}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns (and clears) the pending shell-change notice when the outbound
|
||||
* message targets the session the change was recorded for; otherwise
|
||||
* leaves it pending.
|
||||
*/
|
||||
consumeShellChangeNotice(sessionId: string): ShellChangeNotice | null {
|
||||
if (this.shellChangeNoticeSessionId !== sessionId) {
|
||||
return null
|
||||
}
|
||||
const notice = this.shellChangeNoticeTracker.consume()
|
||||
if (notice) {
|
||||
this.shellChangeNoticeSessionId = null
|
||||
}
|
||||
return notice
|
||||
}
|
||||
|
||||
private recordShellChangeNotice(previousProfileId: string, nextProfileId: string): void {
|
||||
const activeSession = this.options.sessions.getActiveSession()
|
||||
if (!activeSession) {
|
||||
// No transcript to correct: a future session starts with the right
|
||||
// tool description and no momentum in the old shell.
|
||||
return
|
||||
}
|
||||
if (this.shellChangeNoticeSessionId !== activeSession.sessionId) {
|
||||
// A stale notice for another session is superseded rather than merged:
|
||||
// round-trip cancellation only makes sense within one transcript.
|
||||
this.shellChangeNoticeTracker = createShellChangeNoticeTracker()
|
||||
}
|
||||
this.shellChangeNoticeSessionId = activeSession.sessionId
|
||||
this.shellChangeNoticeTracker.record(
|
||||
this.options.resolveShellForProfile(previousProfileId),
|
||||
this.options.resolveShellForProfile(nextProfileId),
|
||||
)
|
||||
}
|
||||
|
||||
private requestRebuild(reason: string): void {
|
||||
Logger.log(`[SdkController] ${reason}`)
|
||||
Logger.log(`[SdkController] Terminal execution mode changed: ${previous} -> ${next}`)
|
||||
|
||||
const activeSession = this.options.sessions.getActiveSession()
|
||||
if (!activeSession) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { normalizeUserInput, stripRuntimeNotices } from "@cline/shared"
|
||||
import { normalizeUserInput, stripModeNotices } from "@cline/shared"
|
||||
import { ACT_MODE_CONTINUATION_PROMPT } from "./sdk-mode-coordinator"
|
||||
|
||||
export type SdkUserMessage = {
|
||||
@@ -46,7 +46,7 @@ export function isSyntheticUserPrompt(text: string): boolean {
|
||||
// <mode_notice> element to the canned continuation, so strip those too or
|
||||
// the synthetic prompt would start counting as a visible user message and
|
||||
// shift every later edit/regenerate ordinal by one.
|
||||
const normalized = stripRuntimeNotices(normalizeUserInput(text))
|
||||
const normalized = stripModeNotices(normalizeUserInput(text))
|
||||
return normalized.startsWith("[TASK RESUMPTION]") || normalized === ACT_MODE_CONTINUATION_PROMPT
|
||||
}
|
||||
|
||||
|
||||
@@ -289,33 +289,18 @@ export async function executeForeground(
|
||||
// Tool factory
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resolves the shell the user's terminal profile setting selects right now.
|
||||
* Both execution modes run this shell: foreground terminals are created from
|
||||
* the same profile (VscodeTerminalManager.setDefaultTerminalProfile), and the
|
||||
* background executor spawns it directly.
|
||||
*/
|
||||
function resolveConfiguredShell(): string {
|
||||
// The setting is typed string, but guard empty values the same way the
|
||||
// settings handlers do (they skip persisting "" but older stores may hold one).
|
||||
const profileId = StateManager.get().getGlobalSettingsKey("defaultTerminalProfile") || "default"
|
||||
return getShellForProfile(profileId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the custom `run_commands` tool for the VSCode extension.
|
||||
*
|
||||
* This tool suppresses and replaces the SDK's built-in `run_commands` tool.
|
||||
* The terminal execution mode and shell are captured when the session's tool
|
||||
* set is built. Switching modes or terminal profiles rebuilds the active SDK
|
||||
* session so the tool timeout, execution mode, and the shell named in the
|
||||
* tool description stay aligned with what actually runs.
|
||||
* The terminal execution mode is captured when the session's tool set is built.
|
||||
* Switching modes rebuilds the active SDK session so the tool timeout and
|
||||
* execution mode stay aligned.
|
||||
*/
|
||||
export function createVscodeRunCommandsTool(options: VscodeRunCommandsToolOptions): AgentTool {
|
||||
return createShellTool(createVscodeShellExecutor(options), {
|
||||
cwd: options.cwd,
|
||||
bashTimeoutMs: options.bashTimeoutMs,
|
||||
shell: resolveConfiguredShell(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -334,11 +319,10 @@ function createVscodeShellExecutor(options: VscodeRunCommandsToolOptions): Shell
|
||||
Logger.log(`[VscodeRunCommands] Executing command in ${executionMode} mode`)
|
||||
|
||||
if (executionMode === "backgroundExec") {
|
||||
// Background path — use SDK's createShellExecutor.
|
||||
// Re-resolve the shell per invocation: a profile change rebuilds the
|
||||
// session, but that rebuild is deferred while a task is running, so
|
||||
// commands issued in the meantime must still use the new profile.
|
||||
const shell = resolveConfiguredShell()
|
||||
// Background path — use SDK's createShellExecutor
|
||||
// Resolve shell from the user's terminal profile setting
|
||||
const profileId = (StateManager.get().getGlobalSettingsKey("defaultTerminalProfile") as string) || "default"
|
||||
const shell = getShellForProfile(profileId)
|
||||
|
||||
// Recreate the executor if the shell has changed
|
||||
if (!bgExecutor || bgExecutorShell !== shell) {
|
||||
|
||||
@@ -61,8 +61,10 @@
|
||||
* JetBrains exports trusted certificates from the OS and writes them to a
|
||||
* temporary file, then configures node TLS by setting NODE_EXTRA_CA_CERTS.
|
||||
*
|
||||
* CLI users should set the NODE_EXTRA_CA_CERTS environment variable if
|
||||
* necessary, because node does not automatically use the OS' trusted certs.
|
||||
* The CLI's npm wrapper (bin/cline) does the same automatically: it harvests
|
||||
* the OS trust store and points the child's NODE_EXTRA_CA_CERTS at a managed
|
||||
* bundle, because the Bun runtime does not read the OS store on its own. A
|
||||
* user-set NODE_EXTRA_CA_CERTS is merged in rather than replaced.
|
||||
*
|
||||
* ## Limitations in JetBrains & CLI
|
||||
*
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, it, mock } from "bun:test"
|
||||
import { expect } from "chai"
|
||||
import * as actualFs from "fs"
|
||||
import * as actualOs from "os"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
@@ -16,16 +15,6 @@ const osMock = () => ({ ...osMockNamespace, default: osMockNamespace })
|
||||
mock.module("os", osMock)
|
||||
mock.module("node:os", osMock)
|
||||
|
||||
// getShell() probes the filesystem for PowerShell 7 when no Windows terminal
|
||||
// profile is configured. Route existsSync through a mutable delegate so tests
|
||||
// control which PowerShell installs "exist" regardless of the host machine.
|
||||
let existsSyncImpl: typeof actualFs.existsSync = actualFs.existsSync
|
||||
const existsSyncDelegate = ((path: unknown) => existsSyncImpl(path as string)) as typeof actualFs.existsSync
|
||||
const fsMockNamespace = { ...actualFs, existsSync: existsSyncDelegate }
|
||||
const fsMock = () => ({ ...fsMockNamespace, default: fsMockNamespace })
|
||||
mock.module("fs", fsMock)
|
||||
mock.module("node:fs", fsMock)
|
||||
|
||||
import { getShell } from "@utils/shell"
|
||||
|
||||
describe("Shell Detection Tests", () => {
|
||||
@@ -33,7 +22,6 @@ describe("Shell Detection Tests", () => {
|
||||
let originalEnv: NodeJS.ProcessEnv
|
||||
let originalGetConfig: typeof vscode.workspace.getConfiguration
|
||||
let originalUserInfo: typeof actualOs.userInfo
|
||||
let originalExistsSync: typeof actualFs.existsSync
|
||||
|
||||
// Helper to mock VS Code configuration
|
||||
function mockVsCodeConfig(platformKey: string, defaultProfileName: string | null, profiles: Record<string, any>) {
|
||||
@@ -57,7 +45,6 @@ describe("Shell Detection Tests", () => {
|
||||
originalEnv = { ...process.env }
|
||||
originalGetConfig = vscode.workspace.getConfiguration
|
||||
originalUserInfo = userInfoImpl
|
||||
originalExistsSync = existsSyncImpl
|
||||
|
||||
// Clear environment variables for a clean test
|
||||
delete process.env.SHELL
|
||||
@@ -65,9 +52,6 @@ describe("Shell Detection Tests", () => {
|
||||
|
||||
// Default userInfo() mock
|
||||
userInfoImpl = (() => ({ shell: null })) as any
|
||||
// Default: PowerShell 7 is not installed, so the Windows default
|
||||
// resolves to legacy Windows PowerShell.
|
||||
existsSyncImpl = (() => false) as any
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -76,7 +60,6 @@ describe("Shell Detection Tests", () => {
|
||||
process.env = originalEnv
|
||||
vscode.workspace.getConfiguration = originalGetConfig
|
||||
userInfoImpl = originalUserInfo
|
||||
existsSyncImpl = originalExistsSync
|
||||
})
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -134,36 +117,18 @@ describe("Shell Detection Tests", () => {
|
||||
expect(getShell()).to.equal("C:\\Windows\\System32\\cmd.exe")
|
||||
})
|
||||
|
||||
it("defaults to PowerShell 7 when no profile is configured and pwsh is installed", () => {
|
||||
it("respects userInfo() if no VS Code config is available", () => {
|
||||
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
|
||||
process.env.ProgramW6432 = "C:\\Program Files"
|
||||
existsSyncImpl = (() => true) as any
|
||||
userInfoImpl = () => ({ shell: "C:\\Custom\\PowerShell.exe" }) as any
|
||||
|
||||
expect(getShell()).to.equal("C:\\Program Files\\PowerShell\\7\\pwsh.exe")
|
||||
expect(getShell()).to.equal("C:\\Custom\\PowerShell.exe")
|
||||
})
|
||||
|
||||
it("defaults to Store-installed pwsh when that is the only pwsh present", () => {
|
||||
it("respects an odd COMSPEC if no userInfo shell is available", () => {
|
||||
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
|
||||
process.env.LOCALAPPDATA = "C:\\Users\\Test\\AppData\\Local"
|
||||
const storePwsh = "C:\\Users\\Test\\AppData\\Local\\Microsoft\\WindowsApps\\pwsh.exe"
|
||||
existsSyncImpl = ((path: string) => path === storePwsh) as any
|
||||
|
||||
expect(getShell()).to.equal(storePwsh)
|
||||
})
|
||||
|
||||
it("defaults to legacy Windows PowerShell when no profile is configured and pwsh is absent", () => {
|
||||
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
|
||||
existsSyncImpl = (() => false) as any
|
||||
|
||||
expect(getShell()).to.equal("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe")
|
||||
})
|
||||
|
||||
it("ignores userInfo() and COMSPEC — VS Code's default terminal ignores them too", () => {
|
||||
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
|
||||
userInfoImpl = () => ({ shell: "C:\\Custom\\OtherShell.exe" }) as any
|
||||
process.env.COMSPEC = "D:\\CustomCmd\\cmd.exe"
|
||||
|
||||
expect(getShell()).to.equal("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe")
|
||||
expect(getShell()).to.equal("D:\\CustomCmd\\cmd.exe")
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as childProcess from "child_process"
|
||||
import { Logger } from "@/shared/services/Logger"
|
||||
import { getWindowsPwshInstallPaths, WINDOWS_POWERSHELL_LEGACY_PATH } from "./shell"
|
||||
import { WINDOWS_POWERSHELL_7_PATH, WINDOWS_POWERSHELL_LEGACY_PATH } from "./shell"
|
||||
|
||||
const POWERSHELL_PROBE_TIMEOUT_MS = 1200
|
||||
|
||||
@@ -16,7 +16,14 @@ export function getFallbackWindowsPowerShellPath(): string {
|
||||
}
|
||||
|
||||
export function getWindowsPowerShellCandidates(): string[] {
|
||||
const envAbsoluteCandidates = [...getWindowsPwshInstallPaths(), WINDOWS_POWERSHELL_LEGACY_PATH]
|
||||
const programFiles = process.env.ProgramW6432 || process.env.ProgramFiles || "C:\\Program Files"
|
||||
|
||||
const envAbsoluteCandidates = [
|
||||
`${programFiles}\\PowerShell\\7\\pwsh.exe`,
|
||||
`${programFiles}\\PowerShell\\6\\pwsh.exe`,
|
||||
WINDOWS_POWERSHELL_7_PATH,
|
||||
WINDOWS_POWERSHELL_LEGACY_PATH,
|
||||
]
|
||||
|
||||
const commandNameFallbacks = ["pwsh.exe", "pwsh", "powershell.exe", "powershell"]
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { existsSync } from "fs"
|
||||
import { userInfo } from "os"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
@@ -172,6 +171,11 @@ function getShellFromUserInfo(): string | null {
|
||||
function getShellFromEnv(): string | null {
|
||||
const { env } = process
|
||||
|
||||
if (process.platform === "win32") {
|
||||
// On Windows, COMSPEC typically holds cmd.exe
|
||||
return env.COMSPEC || "C:\\Windows\\System32\\cmd.exe"
|
||||
}
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
// On macOS/Linux, SHELL is commonly the environment variable
|
||||
return env.SHELL || "/bin/zsh"
|
||||
@@ -300,35 +304,6 @@ export function getShellForProfile(profileId: string): string {
|
||||
// 5) Publicly Exposed Shell Getter
|
||||
// -----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Absolute paths where a modern PowerShell (pwsh) may be installed, most
|
||||
* preferred first: MSI/ZIP installs under Program Files (either architecture),
|
||||
* then the Microsoft Store install under LOCALAPPDATA. This is the single
|
||||
* candidate list shared with the async prober in utils/powershell.ts.
|
||||
*/
|
||||
export function getWindowsPwshInstallPaths(): string[] {
|
||||
const programFiles = process.env.ProgramW6432 || process.env.ProgramFiles || "C:\\Program Files"
|
||||
const localAppData = process.env.LOCALAPPDATA
|
||||
return [
|
||||
`${programFiles}\\PowerShell\\7\\pwsh.exe`,
|
||||
`${programFiles}\\PowerShell\\6\\pwsh.exe`,
|
||||
SHELL_PATHS.POWERSHELL_7,
|
||||
...(localAppData ? [`${localAppData}\\Microsoft\\WindowsApps\\pwsh.exe`] : []),
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* The shell VS Code launches on Windows when the user has not configured a
|
||||
* default terminal profile: its built-in default is PowerShell (pwsh when
|
||||
* installed, Windows PowerShell otherwise) — never cmd.exe. Mirroring that
|
||||
* here keeps the "default" profile meaning the same shell whether commands
|
||||
* run in a visible VS Code terminal or a background child process.
|
||||
*/
|
||||
function getWindowsDefaultShell(): string {
|
||||
const pwsh = getWindowsPwshInstallPaths().find((candidate) => existsSync(candidate))
|
||||
return pwsh ?? SHELL_PATHS.POWERSHELL_LEGACY
|
||||
}
|
||||
|
||||
export function getShell(): string {
|
||||
// 1. Check VS Code config first.
|
||||
if (process.platform === "win32") {
|
||||
@@ -337,12 +312,7 @@ export function getShell(): string {
|
||||
if (windowsShell) {
|
||||
return windowsShell
|
||||
}
|
||||
// No profile configured — match the shell VS Code's default terminal
|
||||
// would launch. userInfo()/COMSPEC are not consulted: VS Code's own
|
||||
// terminal ignores them too, and they would resolve to cmd.exe.
|
||||
return getWindowsDefaultShell()
|
||||
}
|
||||
if (process.platform === "darwin") {
|
||||
} else if (process.platform === "darwin") {
|
||||
// macOS from VS Code
|
||||
const macShell = getMacShellFromVSCode()
|
||||
if (macShell) {
|
||||
@@ -368,6 +338,12 @@ export function getShell(): string {
|
||||
return envShell
|
||||
}
|
||||
|
||||
// 4. Fall back to a POSIX shell - This is the behavior of our old shell detection method.
|
||||
// 4. Finally, fall back to a default
|
||||
if (process.platform === "win32") {
|
||||
// On Windows, if we got here, we have no config, no COMSPEC, and one very messed up operating system.
|
||||
// Use CMD as a last resort
|
||||
return SHELL_PATHS.CMD
|
||||
}
|
||||
// On macOS/Linux, fallback to a POSIX shell - This is the behavior of our old shell detection method.
|
||||
return SHELL_PATHS.FALLBACK
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ const ApiOptions = ({
|
||||
<AIhubmixProvider currentMode={currentMode} isPopup={isPopup} showModelOptions={showModelOptions} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && (selectedProvider.includes("openai") || isCustomProvider) && (
|
||||
{apiConfiguration && (selectedProvider === "openai" || isCustomProvider) && (
|
||||
<OpenAICompatibleProvider
|
||||
currentMode={currentMode}
|
||||
isPopup={isPopup}
|
||||
|
||||
@@ -97,6 +97,25 @@ describe("ApiOptions Component", () => {
|
||||
expect(modelIdInput).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it.each([
|
||||
["openai-native", "OpenAI API Key"],
|
||||
["openai-codex", "Sign in to OpenAI Codex"],
|
||||
])("renders only the dedicated form for %s", (provider, dedicatedFormText) => {
|
||||
mockExtensionState({
|
||||
planModeApiProvider: provider as any,
|
||||
actModeApiProvider: provider as any,
|
||||
})
|
||||
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions currentMode="plan" showModelOptions={false} />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
|
||||
expect(screen.getByText(dedicatedFormText)).toBeInTheDocument()
|
||||
expect(screen.queryByText("Custom Headers")).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders the OpenAI-compatible form for custom/unknown catalog providers", () => {
|
||||
vi.mocked(useProviderListings).mockReturnValue({
|
||||
providers: [
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import type { AuthState, UserOrganizationsResponse } from "@shared/proto/cline/account"
|
||||
import { act, render, screen } from "@testing-library/react"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
import { ClineAuthProvider, useClineAuth } from "./ClineAuthContext"
|
||||
|
||||
type AuthStatusCallbacks = {
|
||||
onResponse: (response: AuthState) => void
|
||||
}
|
||||
|
||||
const grpcMocks = vi.hoisted(() => ({
|
||||
getUserOrganizations: vi.fn(),
|
||||
subscribeToAuthStatusUpdate: vi.fn(),
|
||||
authStatusCallbacks: undefined as AuthStatusCallbacks | undefined,
|
||||
}))
|
||||
|
||||
vi.mock("@/services/grpc-client", () => ({
|
||||
AccountServiceClient: {
|
||||
getUserOrganizations: grpcMocks.getUserOrganizations,
|
||||
subscribeToAuthStatusUpdate: grpcMocks.subscribeToAuthStatusUpdate,
|
||||
},
|
||||
}))
|
||||
|
||||
function createDeferred<T>() {
|
||||
let resolve: (value: T) => void = () => {}
|
||||
const promise = new Promise<T>((promiseResolve) => {
|
||||
resolve = promiseResolve
|
||||
})
|
||||
return { promise, resolve }
|
||||
}
|
||||
|
||||
function AuthStateProbe() {
|
||||
const { clineUser, organizations } = useClineAuth()
|
||||
return (
|
||||
<>
|
||||
<div data-testid="user-state">{clineUser?.uid ?? "signed-out"}</div>
|
||||
<div data-testid="organizations-state">
|
||||
{organizations?.map((organization) => organization.organizationId).join(",") ?? "none"}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
describe("ClineAuthProvider", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
grpcMocks.authStatusCallbacks = undefined
|
||||
grpcMocks.subscribeToAuthStatusUpdate.mockImplementation((_request, callbacks: AuthStatusCallbacks) => {
|
||||
grpcMocks.authStatusCallbacks = callbacks
|
||||
return vi.fn()
|
||||
})
|
||||
})
|
||||
|
||||
it("does not restore organizations when an in-flight request resolves after sign-out", async () => {
|
||||
const organizationsRequest = createDeferred<UserOrganizationsResponse>()
|
||||
grpcMocks.getUserOrganizations.mockReturnValue(organizationsRequest.promise)
|
||||
|
||||
render(
|
||||
<ClineAuthProvider>
|
||||
<AuthStateProbe />
|
||||
</ClineAuthProvider>,
|
||||
)
|
||||
|
||||
act(() => {
|
||||
grpcMocks.authStatusCallbacks?.onResponse({ user: { uid: "user-1" } })
|
||||
})
|
||||
expect(grpcMocks.getUserOrganizations).toHaveBeenCalledTimes(1)
|
||||
|
||||
act(() => {
|
||||
grpcMocks.authStatusCallbacks?.onResponse({})
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
organizationsRequest.resolve({
|
||||
organizations: [
|
||||
{ organizationId: "stale-org", active: true, memberId: "member-1", name: "Stale Org", roles: [] },
|
||||
],
|
||||
})
|
||||
await organizationsRequest.promise
|
||||
})
|
||||
|
||||
expect(screen.getByTestId("user-state")).toHaveTextContent("signed-out")
|
||||
expect(screen.getByTestId("organizations-state")).toHaveTextContent("none")
|
||||
})
|
||||
})
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { UserOrganization } from "@shared/proto/cline/account"
|
||||
import type { AuthState, UserOrganization } from "@shared/proto/cline/account"
|
||||
import { EmptyRequest } from "@shared/proto/cline/common"
|
||||
import deepEqual from "fast-deep-equal"
|
||||
import type React from "react"
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react"
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { AccountServiceClient } from "@/services/grpc-client"
|
||||
|
||||
// Define User type (you may need to adjust this based on your actual User type)
|
||||
@@ -25,10 +25,15 @@ export const ClineAuthContext = createContext<ClineAuthContextType | undefined>(
|
||||
export const ClineAuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [user, setUser] = useState<ClineUser | null>(null)
|
||||
const [userOrganizations, setUserOrganizations] = useState<UserOrganization[] | null>(null)
|
||||
const organizationsRequestIdRef = useRef(0)
|
||||
|
||||
const getUserOrganizations = useCallback(async () => {
|
||||
const requestId = ++organizationsRequestIdRef.current
|
||||
try {
|
||||
const response = await AccountServiceClient.getUserOrganizations(EmptyRequest.create())
|
||||
if (requestId !== organizationsRequestIdRef.current) {
|
||||
return
|
||||
}
|
||||
setUserOrganizations((old) => {
|
||||
if (!deepEqual(response.organizations, old)) {
|
||||
return response.organizations
|
||||
@@ -52,22 +57,23 @@ export const ClineAuthProvider: React.FC<{ children: React.ReactNode }> = ({ chi
|
||||
// Handle auth status update events
|
||||
useEffect(() => {
|
||||
const cancelSubscription = AccountServiceClient.subscribeToAuthStatusUpdate(EmptyRequest.create(), {
|
||||
onResponse: async (response: any) => {
|
||||
setUser((oldUser) => {
|
||||
if (!response?.user?.uid) {
|
||||
return null
|
||||
}
|
||||
onResponse: (response: AuthState) => {
|
||||
const responseUser = response.user
|
||||
if (!responseUser?.uid) {
|
||||
organizationsRequestIdRef.current++
|
||||
setUser(null)
|
||||
setUserOrganizations(null)
|
||||
return
|
||||
}
|
||||
|
||||
if (response?.user && oldUser?.uid !== response.user.uid) {
|
||||
// Once we have a new user, fetch organizations that
|
||||
// allow us to display the active account in account view UI
|
||||
// and fetch the correct credit balance to display on mount
|
||||
getUserOrganizations()
|
||||
return response.user
|
||||
}
|
||||
// Refresh organizations on every auth status update, not just user
|
||||
// changes. Switching organizations doesn't change the uid, so gating
|
||||
// this on uid changes leaves stale `active` flags — which reset the
|
||||
// account view's org dropdown on remount. The deepEqual guard in
|
||||
// getUserOrganizations prevents no-op re-renders.
|
||||
getUserOrganizations()
|
||||
|
||||
return oldUser
|
||||
})
|
||||
setUser((oldUser) => (oldUser?.uid !== responseUser.uid ? responseUser : oldUser))
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
console.error("Error in auth callback subscription:", error)
|
||||
@@ -79,6 +85,7 @@ export const ClineAuthProvider: React.FC<{ children: React.ReactNode }> = ({ chi
|
||||
|
||||
// Cleanup function to cancel subscription when component unmounts
|
||||
return () => {
|
||||
organizationsRequestIdRef.current++
|
||||
cancelSubscription()
|
||||
}
|
||||
}, [getUserOrganizations])
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"apps/cli": {
|
||||
"name": "@cline/cli",
|
||||
"version": "3.0.41",
|
||||
"version": "3.0.43",
|
||||
"bin": {
|
||||
"cline": "src/index.ts",
|
||||
},
|
||||
@@ -632,7 +632,7 @@
|
||||
},
|
||||
"sdk/packages/agents": {
|
||||
"name": "@cline/agents",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"dependencies": {
|
||||
"@cline/llms": "workspace:*",
|
||||
"@cline/shared": "workspace:*",
|
||||
@@ -641,7 +641,7 @@
|
||||
},
|
||||
"sdk/packages/core": {
|
||||
"name": "@cline/core",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"dependencies": {
|
||||
"@cline/agents": "workspace:*",
|
||||
"@cline/llms": "workspace:*",
|
||||
@@ -679,7 +679,7 @@
|
||||
},
|
||||
"sdk/packages/llms": {
|
||||
"name": "@cline/llms",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"dependencies": {
|
||||
"@ai-sdk/amazon-bedrock": "^4.0.89",
|
||||
"@ai-sdk/anthropic": "^3.0.68",
|
||||
@@ -714,14 +714,14 @@
|
||||
},
|
||||
"sdk/packages/sdk": {
|
||||
"name": "@cline/sdk",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"dependencies": {
|
||||
"@cline/core": "workspace:*",
|
||||
},
|
||||
},
|
||||
"sdk/packages/shared": {
|
||||
"name": "@cline/shared",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"dependencies": {
|
||||
"aws4fetch": "^1.0.20",
|
||||
"jsonrepair": "^3.13.2",
|
||||
@@ -768,27 +768,27 @@
|
||||
|
||||
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.16.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-1ad+Sc/0sCtZGHthxxvgEUo5Wsbw16I+aF+YwdiLnPwkZG8KAGUEAPK6LM6Pf69lCyJPt1Aomk1d+8oE3C4ZEw=="],
|
||||
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.131", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.95", "@ai-sdk/openai": "3.0.82", "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-UrbM28zGFJV6xTn7wpv/uCsp/wMKb79MCuZC3Ff1a59PGjLr+iMN+Nlul7cWV04pjE5u5kLP5SybtGZtDP2EkQ=="],
|
||||
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.132", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.96", "@ai-sdk/openai": "3.0.83", "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ngtWAA4BHhtRrC0Vx1by9+KwcYtXbKcKjEoKbKhqJxNes8w6JNtdp5nQfK3ZE9Wbcdq8i6a8s08xXFm3pHe3iA=="],
|
||||
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.95", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Q7NhioTX6m0hKni14Ip9EO6WedbIYcldQ/PsGB7gVAveRNog39FfX31f+9HYoEUrfm9L7QxIcB5aAzJV/hmNRg=="],
|
||||
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.96", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-6VQzaXQdm5FkX6NWOyKzV5GB11C8IqkgsKZE91lg/bdwyvnQJLDwal2qkE0+fC8CCGeW5d+VV8Mw/+H+OcDC1A=="],
|
||||
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.145", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cqSQ+I0Bjj2W9g1oFyE1O1mSowsWXb+U1wK9vtg5kRQqB95iWVIKbtdr14gGf46cueJSiBlKfPTT24gDDVuFmw=="],
|
||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.146", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-QK922LzOfGeHdZ9QGvghDizQx/tPOolTQSHvMlnUPeaTW5qpiIqpfbLwYiyxEt5YOGLLM/0t232Dut+95udo/Q=="],
|
||||
|
||||
"@ai-sdk/google": ["@ai-sdk/google@3.0.90", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-nn2bSLFZDV5Xhl2oh+C3ckpBUM849zrHLoLe6B9DVu2DcgtIvxKYO0pKLO/vB9XQVKON5XORp7uV7P+60L5XUQ=="],
|
||||
"@ai-sdk/google": ["@ai-sdk/google@3.0.91", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-d/ho+sDjArFjreE2002t9jE4LXX3wde97dN2HCLCX1l41gaJV3wf/c/19axjUNfIf/4uUq+nJmhBO0lW/dg3yw=="],
|
||||
|
||||
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.158", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.95", "@ai-sdk/google": "3.0.90", "@ai-sdk/openai-compatible": "2.0.58", "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Z7KPZ2+M7DFnXPEDgElwazDQxDxYqd9HQdFLuCMSpc0No/1Dr0TKRT+Q5pJwstHJfIQeAMApFvalzGOfTe/ShQ=="],
|
||||
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.159", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.96", "@ai-sdk/google": "3.0.91", "@ai-sdk/openai-compatible": "2.0.59", "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-AvHvV3Nw+LaLjTBveP96hBbKFXHoQBMeQa1fd9SV1UnXCvmCfl7cQempb+pZnho12rbTFHwgdX419nFTMNmATw=="],
|
||||
|
||||
"@ai-sdk/mistral": ["@ai-sdk/mistral@3.0.47", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-A/ov/CTrQ0rDztrvgYo9ql4u6tlyfTrwMN4u76zqLM0JqUWy82T82Y8HzP4fCQOs7gZggrruHaNbWnqnE9IwKA=="],
|
||||
"@ai-sdk/mistral": ["@ai-sdk/mistral@3.0.48", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-SOZMjV48dyAn1rsiZSN7emeO0KYKnr9/SqMFPpJYUddPcnLSjac9GGWVKn+LnSzD7Woh3lYbYbJWdbJOQ2U2sQ=="],
|
||||
|
||||
"@ai-sdk/openai": ["@ai-sdk/openai@3.0.82", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Gn1YliuNMneXoBmuLX1kH/e5SR/VnU9FXLvJ8WyiV61Noo+wPdE4nuzxRGt3lfV6rla1wyCb1syV4jU0A310ew=="],
|
||||
"@ai-sdk/openai": ["@ai-sdk/openai@3.0.83", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-gYsQPmBQYgWc8+sFdmO4lSbNJoBdt9wgx1wZ1YOi0wX8X0d/K3FYOnNS0/TGymiDk8kh+wKj6PLC6UyA8bwVFA=="],
|
||||
|
||||
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.58", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-0SXA0xVt18F4ki7ttVshqaM0oLXSB475ACOU0/2RK3OZS3UYqrmKF+DJwYBYUZmqCq2nZ2vkNZEXpWP2wfGsrQ=="],
|
||||
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.59", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-CFsUizO+jL+jSlN13rW2nQE9EbWx+8PSFBdB3TtD0UGYOxtefCVa5hsrNo5NUOJJGX5f4xHiXE1i2m5nQ80QPg=="],
|
||||
|
||||
"@ai-sdk/provider": ["@ai-sdk/provider@3.0.13", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-ZPtVYt5QIJzOta1kdUiDuCx4HhFkvNPv/rvmZ2b1iXwybYjJsCnNYR4PAw4kW7rgVfDARvHXcU64efWuqNp6bw=="],
|
||||
"@ai-sdk/provider": ["@ai-sdk/provider@3.0.14", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-5X1k57JBJ4H7H1QjX7CnJYAB1I19r/trVZTMcSms7/kLNZ8RaU4Nt2agcwZzv82Hfx6Q7/TOLU7agAKeFfc8cA=="],
|
||||
|
||||
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.37", "", { "dependencies": { "@ai-sdk/provider": "3.0.13", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-VG4tpVXCuzm21U9xjg05BCMZnjZOazC72+MxBkLAa7hCKsnqNt542GYWUUqwmHSczJwgbSXN8UvaNgSerUaKdw=="],
|
||||
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.38", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-/HHGmtKllqjg1OLc023v9w9kK3laW7Z6TzfZukYQWCsGBbzB9p60zTvvpXFVcs44NZBVXL3viOa1HRKUbeee8g=="],
|
||||
|
||||
"@ai-sdk/react": ["@ai-sdk/react@3.0.223", "", { "dependencies": { "@ai-sdk/provider-utils": "4.0.37", "ai": "6.0.221", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" } }, "sha512-b7Ri+wLOR9pZkKlEKii3ZuXi79Rh3rC5rYUEFDpXUOJLazztIE4MPM4dQRXCojYgOuPa61gVO2BFjuRVLGsOfw=="],
|
||||
"@ai-sdk/react": ["@ai-sdk/react@3.0.224", "", { "dependencies": { "@ai-sdk/provider-utils": "4.0.38", "ai": "6.0.222", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" } }, "sha512-bfCVv6uTNS+gwMLLpsJQUBZqedCphqNiFkMVjL4kzunlgpC0uFyyYRYd99884NuYZJAF9AKKROK9t+/v1N9tow=="],
|
||||
|
||||
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
||||
|
||||
@@ -796,23 +796,23 @@
|
||||
|
||||
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.205", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.205", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.205", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.205", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.205", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.205", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.205", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.205", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.205" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-ft6iBw9kXudsusiXNpeybIPBJ07Z3tqp1ROSg5cEJqgA+9i+JJj2sRfQth+QD+lyenbbAU8yPieLxIimvfBhtw=="],
|
||||
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.206", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.206", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.206", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.206", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.206", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.206", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.206", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.206", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.206" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-KljDh9Pg4YCYpoXS8dnWoVSsOHtU4yLCW268K2iOruSxFXE8/Tay6DPvmJzYuqjP5YLNYfj05ZGykwZSUn6GXA=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.205", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lrfJ4eVtzfPkCpbSkBOGSMQCBbvmW6nbPzgHE4IwMN3scZlpuFMUFqh2aaJa/X2SAcWD9H2S0t2WWvSRgM7BjA=="],
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.206", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FL2+NKcMMN47vcnCW2Fkt3AOgeRRlQxrisbPNaxrxqPJFzhUKs17x5j0XzLefd0xRbDAr74hd0PK/tnp6PHM6w=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.205", "", { "os": "darwin", "cpu": "x64" }, "sha512-G6ETPmL5mNzJ2DFsWxG3jmsmrXgZX1N2ZCJvxaGUUpjTsKZJ4Tup1cWYvcd/m7o5fYZmx9REmgzTwsAIc1fdPQ=="],
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.206", "", { "os": "darwin", "cpu": "x64" }, "sha512-mRW8PPMfQN15EunLwpdmcVzk3XuM4DXQUM8DOzaeA1Hr1yxYPaVVBLr9hkdBKOqr8XTl3ueoTR6RZAy6a/n7OA=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.205", "", { "os": "linux", "cpu": "arm64" }, "sha512-CXzySK3PV3EizCRPXnxPqeaAtgrBFDnMFOVpMe36oC3U16yDb1b1tAJGqZi/7uFrVvAiaXvnSFxhUWnDDSaO+A=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.206", "", { "os": "linux", "cpu": "arm64" }, "sha512-Id6H8l6EsGb7849EAZDOB4Ic+FQpbzt4D5HGOwp59CTW3o/1c4etjQA/Kl1K+DSEWn3FGo6D5UMVgc/rwhBj8g=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.205", "", { "os": "linux", "cpu": "arm64" }, "sha512-91fgdG4aTnQ29sKOcUqgH4+tKCW2ut6PWGRSYmXNDbROasJm1rAlPdzC5brdu/e4c0CDSNV6TWyE5JCjaS/jlQ=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.206", "", { "os": "linux", "cpu": "arm64" }, "sha512-aMZe1Kl+kYv5QlA15W9Ae25MAzBsA9FA40f5TOtJebA+M/xliF0r2LLb2NdyBviiZCDllcE31l0zgYE0rQqFQw=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.205", "", { "os": "linux", "cpu": "x64" }, "sha512-siS+1iNqBSlGFZZvJY6+mhzZ/6/ec/TbX9GMuwmTF0E6fxGhIIp797jJxR1q8r6FAq7d39mEoRNhC0Ffo60uNQ=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.206", "", { "os": "linux", "cpu": "x64" }, "sha512-egZhOC1RlEVhZyq6Oa1b04AF7hh4hO+8oCsJCZ3gOifJQuHih1oW3lZ8fOUxU85jlT2ytAnt5kRp4uQr6PJgbg=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.205", "", { "os": "linux", "cpu": "x64" }, "sha512-vvsb7GlnA8CTSVvvTkrXjcSeRKqxSM7p/tU3Od9ICAZeWHglptekEyzLEApzLuLbI5ewfFF/F0q3NwOBbo18dg=="],
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.206", "", { "os": "linux", "cpu": "x64" }, "sha512-xQBOBhlcmTNc7YeYT5qLZOikpSq3WHlsJ/t6i7kJqUWrcXlOPaAoSMdKp5xO/V0CjAdzdJoWB88I55UAh8mclQ=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.205", "", { "os": "win32", "cpu": "arm64" }, "sha512-SpP5zF68weFez/6pKrGzq/UVAJDMDNphWqmkLfOpWTDBL5xy6XlIZw5Bl4EXoVnfi2VLFkwuffNeFe+9SdX7kw=="],
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.206", "", { "os": "win32", "cpu": "arm64" }, "sha512-oRQk23bFXSz4QRhOxqnnvlLWq/KiF2PtSBYXrMg1AQrCOHJd2k66aOAS7AJ4ZSzejiyV4N6sS6UThfmF6ipHBQ=="],
|
||||
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.205", "", { "os": "win32", "cpu": "x64" }, "sha512-kg2kkXyeSoFLruO3Ic2IruLxzBR0xCUtmlJHdWi3SYW7JhAKNJg4fcrdJsWcardmEw23Y2UDGDJbRyxqSVx6wg=="],
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.206", "", { "os": "win32", "cpu": "x64" }, "sha512-BdjKmDojZjc5RjN+8Q6K7Yqf1WYhel6I3DkMXc9zdxS/xIuN42sx7zgQpdMGY73pm7ROPLqo3LieOeMhVH161w=="],
|
||||
|
||||
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.37.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-tHjX2YbkUBwEgg0JZU3EFSSAQPoK4qQR/NFYa8Vtzd5UAyXzZksCw2In69Rml4R/TyHPBfRYaLK35XiOe33pjw=="],
|
||||
|
||||
@@ -838,7 +838,7 @@
|
||||
|
||||
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.63", "", { "dependencies": { "@aws-sdk/core": "^3.975.1", "@aws-sdk/nested-clients": "^3.997.31", "@aws-sdk/types": "^3.974.0", "@smithy/core": "^3.29.2", "@smithy/types": "^4.16.0", "tslib": "^2.6.2" } }, "sha512-8qZLFhM69eKcS37m459ctPR05Qimycm/74OPVioe6wNZabMT54GYhwBju0+J656RkMasNSawWQu+c8CmBe3TUQ=="],
|
||||
|
||||
"@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.1083.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.1", "@aws-sdk/credential-provider-cognito-identity": "^3.972.56", "@aws-sdk/credential-provider-env": "^3.972.57", "@aws-sdk/credential-provider-http": "^3.972.59", "@aws-sdk/credential-provider-ini": "^3.973.1", "@aws-sdk/credential-provider-login": "^3.972.63", "@aws-sdk/credential-provider-node": "^3.972.66", "@aws-sdk/credential-provider-process": "^3.972.57", "@aws-sdk/credential-provider-sso": "^3.973.1", "@aws-sdk/credential-provider-web-identity": "^3.972.63", "@aws-sdk/nested-clients": "^3.997.31", "@aws-sdk/types": "^3.974.0", "@smithy/core": "^3.29.2", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.0", "tslib": "^2.6.2" } }, "sha512-i2q3Jgt365lZp7BSDqDSf283WvISrXob1zsql093LK3G2svYRHRvcNv995SsKtAzRENwHem2TC2vWeghrgBkxg=="],
|
||||
"@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.1084.0", "", { "dependencies": { "@aws-sdk/core": "^3.975.1", "@aws-sdk/credential-provider-cognito-identity": "^3.972.56", "@aws-sdk/credential-provider-env": "^3.972.57", "@aws-sdk/credential-provider-http": "^3.972.59", "@aws-sdk/credential-provider-ini": "^3.973.1", "@aws-sdk/credential-provider-login": "^3.972.63", "@aws-sdk/credential-provider-node": "^3.972.66", "@aws-sdk/credential-provider-process": "^3.972.57", "@aws-sdk/credential-provider-sso": "^3.973.1", "@aws-sdk/credential-provider-web-identity": "^3.972.63", "@aws-sdk/nested-clients": "^3.997.31", "@aws-sdk/types": "^3.974.0", "@smithy/core": "^3.29.2", "@smithy/credential-provider-imds": "^4.4.7", "@smithy/types": "^4.16.0", "tslib": "^2.6.2" } }, "sha512-6MT9xigrduBftpOEq2HKzGqp2Up0Jwe8dK5W3GyBpePywzgMK6029XEYXkCC5wRYwXwhSPzpjnjRlWUA7K/KNQ=="],
|
||||
|
||||
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.31", "", { "dependencies": { "@aws-sdk/core": "^3.975.1", "@aws-sdk/signature-v4-multi-region": "^3.996.39", "@aws-sdk/types": "^3.974.0", "@smithy/core": "^3.29.2", "@smithy/fetch-http-handler": "^5.6.4", "@smithy/node-http-handler": "^4.9.4", "@smithy/types": "^4.16.0", "tslib": "^2.6.2" } }, "sha512-BDHTpwcsZHEBNEJzOg/B1BkFYJxAXY50dau/NyVWs3d51F0WgIUGSWZot/Os+N3KpDhXeaXnz37mWffAvduREw=="],
|
||||
|
||||
@@ -1680,7 +1680,7 @@
|
||||
|
||||
"@openai/codex-win32-x64": ["@openai/codex@0.130.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-FzMznm7fr5/nbjZgOujZ9Y9AbdGm7ji1FOoWiY3U+srqauvZaTgn6o6aCheSL7kuymu7nTLOO/cAyWV6NuesqQ=="],
|
||||
|
||||
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.17.15", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-gWRQOEggHTELJ9+BtelxnuAczk9qutCXVZenPgRPaT8oVxePf52jfWbqfhyFjnrN8Vlp8tCCTdkEpFW5pZAuEA=="],
|
||||
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.17.18", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-c/C9PhY8PrbcxDY+JIYtOZsrmMD0KzoVvxq+RGUrZ6LQp57SuVBbT4lfwA2G8Se5RNC1N5JtYjiuaXeECnF2SQ=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
||||
|
||||
@@ -1740,7 +1740,7 @@
|
||||
|
||||
"@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.9.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.9.0", "@opentelemetry/core": "2.9.0", "@opentelemetry/sdk-trace-base": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-ec9a7ps37huy5itYk0MalaZdSLlM6AXWp/FhtEjgMpp5leEGojBDvAl/UWttQnkMZOvFHKzRESn8TD3yKTF5nQ=="],
|
||||
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.42.0", "", {}, "sha512-icc5xCzndZfhuJMy5oqk5AvloWquR7jtae74qzpkKkhGp8BivK+oCcEXgGnjCdTfp8hA44l+w8gE8yYJbocJJw=="],
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
|
||||
|
||||
"@opentui-ui/dialog": ["@opentui-ui/dialog@0.1.2", "", { "peerDependencies": { "@opentui/core": "^0.1.69", "@opentui/react": "^0.1.69", "@opentui/solid": "^0.1.69" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-EZ4FG5u5sxU75+6pcsJsLzsD5JqO05So/1ceZUKUu7nxZ9IF7gcZEi+MU4HnYC9cb2Q7w6hM9y3/iW+jE1C53w=="],
|
||||
|
||||
@@ -1772,7 +1772,7 @@
|
||||
|
||||
"@playwright/test": ["@playwright/test@1.61.1", "", { "dependencies": { "playwright": "1.61.1" }, "bin": { "playwright": "cli.js" } }, "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig=="],
|
||||
|
||||
"@posthog/core": ["@posthog/core@1.40.0", "", { "dependencies": { "@posthog/types": "^1.393.0" } }, "sha512-oGDbIwlTquNwdHbEL5ZLEkuW4UFkkEanfx3QAxDgyVbISv+OAA6YGQwrvo0JD3MUJEbJZvyh8XsX+WYDGw9XHw=="],
|
||||
"@posthog/core": ["@posthog/core@1.40.1", "", { "dependencies": { "@posthog/types": "^1.393.0" } }, "sha512-jXuMtZCwA7AMpYlo1wjm6GlC58YBlz/ZxpDIsF9hroUfqYoPPDmQbsQb4iiZAS43+o/kwloxdKJIlE0IiwQ5HQ=="],
|
||||
|
||||
"@posthog/types": ["@posthog/types@1.393.0", "", {}, "sha512-vzWeEJZ7ERQhFRoQYaP5jzN1JvIu46UJyHXsuv+dTGW2r3sMgREOhNxXLZjmFHwZ8/FOHQoyqqQmXTCXZSfMSg=="],
|
||||
|
||||
@@ -1820,7 +1820,7 @@
|
||||
|
||||
"@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
|
||||
|
||||
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
|
||||
|
||||
@@ -1842,7 +1842,7 @@
|
||||
|
||||
"@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="],
|
||||
|
||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
|
||||
|
||||
@@ -1864,7 +1864,7 @@
|
||||
|
||||
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||
|
||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.8", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA=="],
|
||||
|
||||
@@ -2260,7 +2260,7 @@
|
||||
|
||||
"@simple-git/argv-parser": ["@simple-git/argv-parser@1.1.1", "", { "dependencies": { "@simple-git/args-pathspec": "^1.0.3" } }, "sha512-Q9lBcfQ+VQCpQqGJFHe5yooOS5hGdLFFbJ5R+R5aDsnkPCahtn1hSkMcORX65J2Z5lxSkD0lQorMsncuBQxYUw=="],
|
||||
|
||||
"@sinclair/typebox": ["@sinclair/typebox@0.34.49", "", {}, "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A=="],
|
||||
"@sinclair/typebox": ["@sinclair/typebox@0.34.50", "", {}, "sha512-ydBWw0G6WFwWHzh9RK4B5c690UkreOG0llq0r+DaI7LgKgxigf8mhHzIPI3S0850g1BPkq/zpuCfrq4QFgUlTQ=="],
|
||||
|
||||
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
|
||||
|
||||
@@ -2556,7 +2556,7 @@
|
||||
|
||||
"@types/get-folder-size": ["@types/get-folder-size@3.0.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-tSf/k7Undx6jKRwpChR9tl+0ZPf0BVwkjBRtJ5qSnz6iWm2ZRYMAS2MktC2u7YaTAFHmxpL/LBxI85M7ioJCSg=="],
|
||||
|
||||
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
|
||||
"@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="],
|
||||
|
||||
"@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="],
|
||||
|
||||
@@ -2754,7 +2754,7 @@
|
||||
|
||||
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||
|
||||
"ai": ["ai@6.0.221", "", { "dependencies": { "@ai-sdk/gateway": "3.0.145", "@ai-sdk/provider": "3.0.13", "@ai-sdk/provider-utils": "4.0.37", "@opentelemetry/api": "^1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cB7qJbNTMuD5spdJEo+guejX0rkjhSQpc4PHITNB+iBFBnGYHLUZOM+uSeIkY4mS4sVVKBKm3kSQQoI5cUwU3g=="],
|
||||
"ai": ["ai@6.0.222", "", { "dependencies": { "@ai-sdk/gateway": "3.0.146", "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38", "@opentelemetry/api": "^1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kUzBaIHIfaDgBX7X22V4tE48MyYyS2IgCuj/zfANx0JfDAwgKwzKjl9pZUpYSnYPChI7i7yRGRoeTkebAFx1VQ=="],
|
||||
|
||||
"ai-sdk-ollama": ["ai-sdk-ollama@3.8.8", "", { "dependencies": { "@ai-sdk/provider": "^3.0.10", "@ai-sdk/provider-utils": "^4.0.30", "jsonrepair": "^3.14.0", "ollama": "^0.6.3" }, "peerDependencies": { "ai": "^6.0.197" } }, "sha512-peWelPf6sVsRULQyYhfyu1dMZhwewRszsbQVfbuhNLflh+ncRXn6pe1BRE3NAcSsWd7JMRZAV5RzcuR3R9ZfaQ=="],
|
||||
|
||||
@@ -3292,7 +3292,7 @@
|
||||
|
||||
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.21.6", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ=="],
|
||||
"enhanced-resolve": ["enhanced-resolve@5.24.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw=="],
|
||||
|
||||
"enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="],
|
||||
|
||||
@@ -3402,7 +3402,7 @@
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-equals": ["fast-equals@5.4.0", "", {}, "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw=="],
|
||||
"fast-equals": ["fast-equals@5.4.1", "", {}, "sha512-DjlFSM5Pk9cGcL0q5QXl66eGzx0N6szNgaswwc5ZphlBohjTVJSnGgI+rJVOgOi65qUoQnDZN4nDqi33udtydQ=="],
|
||||
|
||||
"fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="],
|
||||
|
||||
@@ -4196,7 +4196,7 @@
|
||||
|
||||
"node-pty": ["node-pty@1.2.0-beta.11", "", { "dependencies": { "node-addon-api": "^7.1.0" } }, "sha512-THcUyu1WwdgoIyUvgXOZ70EOMXzheGa0q3tbEb5kUIfKgcpBJ+AJ9Q1kq0bKtYmQzr77usXiTORZTLmAUQlnoQ=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.50", "", {}, "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg=="],
|
||||
"node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="],
|
||||
|
||||
"node-rsa": ["node-rsa@1.1.1", "", { "dependencies": { "asn1": "^0.2.4" } }, "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw=="],
|
||||
|
||||
@@ -4244,7 +4244,7 @@
|
||||
|
||||
"open-graph-scraper": ["open-graph-scraper@6.12.0", "", { "dependencies": { "chardet": "^2.2.0", "cheerio": "^1.2.0", "iconv-lite": "^0.7.2", "undici": "^7.28.0" } }, "sha512-x0fS3eHxdCox+rFBhQSVe+qBznSPn1pspp8A4BoaVEkiECZEwagEb8z06swLfaFFE2gefj1BvEBeJmdeGTDnYw=="],
|
||||
|
||||
"openai": ["openai@6.45.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "ws", "zod"] }, "sha512-5DQVNErssk0afNpTTHUm/qZPU4iKR9OYdNid8Ib4puq4gHNNvGWZht2zY4h9a8JMF949Ik6m8gQutllVPbjdnw=="],
|
||||
"openai": ["openai@6.46.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "ws", "zod"] }, "sha512-DFg6jEPT2RO+oAyXtddeUJU8zkGy1OQ1AjGzNIJUMQG03TTqvCpy9tBpQ+2VVVnvrl3E56F8GEin2JYtWpITtA=="],
|
||||
|
||||
"opentui-spinner": ["opentui-spinner@0.0.6", "", { "dependencies": { "cli-spinners": "^3.3.0" }, "peerDependencies": { "@opentui/core": "^0.1.49", "@opentui/react": "^0.1.49", "@opentui/solid": "^0.1.49", "typescript": "^5" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-xupLOeVQEAXEvVJCvHkfX6fChDWmJIPHe5jyUrVb8+n4XVTX8mBNhitFfB9v2ZbkC1H2UwPab/ElePHoW37NcA=="],
|
||||
|
||||
@@ -4376,7 +4376,7 @@
|
||||
|
||||
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||
|
||||
"posthog-js": ["posthog-js@1.399.0", "", { "dependencies": { "@posthog/core": "^1.40.0", "@posthog/types": "^1.393.0", "core-js": "^3.49.0", "dompurify": "^3.3.2", "fflate": "^0.4.8", "preact": "^10.29.3", "query-selector-shadow-dom": "^1.0.1", "web-vitals": "^5.3.0" } }, "sha512-8l+uZJZM3+OAc0D0+iLBMDRVfWF9s26Rt0jv8EC3kMJcA/9oyOets0zDgqIZk2TTfUs3H96ycLE6Lwj1wWG16Q=="],
|
||||
"posthog-js": ["posthog-js@1.399.1", "", { "dependencies": { "@posthog/core": "^1.40.1", "@posthog/types": "^1.393.0", "core-js": "^3.49.0", "dompurify": "^3.3.2", "fflate": "^0.4.8", "preact": "^10.29.3", "query-selector-shadow-dom": "^1.0.1", "web-vitals": "^5.3.0" } }, "sha512-xuDe1ZnWgpW0vPs9lvEEWeyMSookjkjUYzdNsMmdbVaBuiRm/bVLvuN72mezqNBf07P+Rjg+5FkNif3VysRL6g=="],
|
||||
|
||||
"posthog-node": ["posthog-node@5.40.0", "", { "dependencies": { "@posthog/core": "^1.39.6" }, "peerDependencies": { "rxjs": "^7.0.0" }, "optionalPeers": ["rxjs"] }, "sha512-DrLfHuauO0W6qruF80iqr5JdmLysef74XzOB4eh36oRLRhxCySLraTqsi2Pj161LZnp9/JNdRDxwT8ei8VK2YA=="],
|
||||
|
||||
@@ -4610,7 +4610,7 @@
|
||||
|
||||
"rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
"safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
|
||||
|
||||
@@ -5046,7 +5046,7 @@
|
||||
|
||||
"victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="],
|
||||
|
||||
"vite": ["vite@8.1.3", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.16", "rolldown": "~1.1.3", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.3.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA=="],
|
||||
"vite": ["vite@8.1.4", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.5", "postcss": "^8.5.16", "rolldown": "~1.1.4", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.3.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ=="],
|
||||
|
||||
"vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
|
||||
|
||||
@@ -5454,30 +5454,46 @@
|
||||
|
||||
"@radix-ui/react-accessible-icon/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-arrow/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
"@radix-ui/react-aspect-ratio/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-avatar/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="],
|
||||
|
||||
"@radix-ui/react-avatar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-avatar/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-checkbox/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-checkbox/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-checkbox/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-collapsible/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-collapsible/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-collapsible/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-collapsible/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-collapsible/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-collection/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-collection/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
@@ -5486,48 +5502,68 @@
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-dismissable-layer/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-focus-scope/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/primitive": ["@radix-ui/primitive@1.1.5", "", {}, "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-label": ["@radix-ui/react-label@2.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3PKvDDxOn62k0oV1n4QtNtD2vpu+zYjXR7ojLBPaO6SPvhy53yg0vAmgNeBQeJW5rV3dffoRG+HYfLBZuzw0CQ=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
"@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
@@ -5540,30 +5576,24 @@
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/primitive": ["@radix-ui/primitive@1.1.5", "", {}, "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
@@ -5572,6 +5602,8 @@
|
||||
|
||||
"@radix-ui/react-popper/@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
|
||||
|
||||
"@radix-ui/react-popper/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-popper/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-popper/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
@@ -5580,22 +5612,40 @@
|
||||
|
||||
"@radix-ui/react-portal/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-presence/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-progress/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="],
|
||||
|
||||
"@radix-ui/react-progress/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-radio-group/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-radio-group/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-radio-group/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-scroll-area/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-scroll-area/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-scroll-area/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
@@ -5604,20 +5654,32 @@
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-slider/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-slider/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-slider/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-slider/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-switch/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-switch/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-switch/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
|
||||
"@radix-ui/react-toast/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-toast/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-toast/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
@@ -5638,14 +5700,16 @@
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jRhe86+8PF7VZ1u14eOWVOuh2BuAhALg/FT1VcMC4OHedMTRUazDnDlKTt+yxo5cRNKHMfmvZ4sSQtWDeMV4CQ=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-toggle": "1.1.14", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-gIC5Q+Xljg7lmUdzSuDoy0t97yZn1sZl00Ra37ZvKrYdWnQLU6sWLd09yG8cIB9jUAlQfHgJ2ACAG00MFwsqSQ=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
@@ -5720,7 +5784,9 @@
|
||||
|
||||
"@streamdown/code/shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="],
|
||||
"@tailwindcss/node/enhanced-resolve": ["enhanced-resolve@5.21.6", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="],
|
||||
|
||||
@@ -5834,6 +5900,8 @@
|
||||
|
||||
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg=="],
|
||||
|
||||
"compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
"conf/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||
@@ -5958,6 +6026,8 @@
|
||||
|
||||
"jszip/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"jwa/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
|
||||
|
||||
"keytar/node-addon-api": ["node-addon-api@4.3.0", "", {}, "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="],
|
||||
@@ -6064,8 +6134,6 @@
|
||||
|
||||
"radix-ui/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-menu": "2.1.20", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-PS+gKE0z2prJ74Y0sM+brAGK4mYOHIR7TlcV5EJgUQ6E0xMvyswkK2X4yRqyganrzsRL+WCSKAPu0NQITICRWg=="],
|
||||
@@ -6100,8 +6168,6 @@
|
||||
|
||||
"radix-ui/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.7", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.12", "", { "dependencies": { "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ZPHyI0JyzoH/rP0tq2uRaIZTj/4s8+kAbqPz+e2N8+ejHvwPJ889dHhqn+vh7PNvNeq+boAoH9yzqeoShzwF2w=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WwZFjWV4s3aC1QtR3k04R+oANHtX2q6fgKlc7MCEiDNlnTxCZ3H8k3mHtEgVlOejystwk1WQgarQhNOQZ2bK1g=="],
|
||||
@@ -6212,6 +6278,8 @@
|
||||
|
||||
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
|
||||
@@ -6240,8 +6308,6 @@
|
||||
|
||||
"unzipper/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg=="],
|
||||
|
||||
"verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
|
||||
|
||||
"vite-node/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
|
||||
@@ -6502,7 +6568,7 @@
|
||||
|
||||
"@opentelemetry/sdk-node/@opentelemetry/sdk-trace-node/@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@1.29.0", "", { "dependencies": { "@opentelemetry/core": "1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-EXIEYmFgybnFMijVgqx1mq/diWwSQcd0JWVksytAVQEnAiaDvP45WuncEVQkFIAC0gVxa2+Xr8wL5pF5jCVKbg=="],
|
||||
|
||||
"@radix-ui/react-accessible-icon/@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
"@radix-ui/react-accordion/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
@@ -6510,8 +6576,6 @@
|
||||
|
||||
"@radix-ui/react-accordion/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-checkbox/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-checkbox/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
@@ -6528,12 +6592,16 @@
|
||||
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-dismissable-layer/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-dropdown-menu/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
@@ -6542,14 +6610,16 @@
|
||||
|
||||
"@radix-ui/react-focus-scope/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
|
||||
"@radix-ui/react-hover-card/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-menubar/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
@@ -6562,13 +6632,9 @@
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-roving-focus/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field/@radix-ui/react-roving-focus/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
"@radix-ui/react-popover/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
|
||||
@@ -6584,6 +6650,8 @@
|
||||
|
||||
"@radix-ui/react-radio-group/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-roving-focus/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
@@ -6604,6 +6672,8 @@
|
||||
|
||||
"@radix-ui/react-switch/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-tabs/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
@@ -6626,20 +6696,16 @@
|
||||
|
||||
"@radix-ui/react-toggle/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus/@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-toggle-group/@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QI/hB65XKWACA66P64A+aHxtLUgHJeJLkaQa+awUNXT6T3swndtY5DojeHA+vldrTspMTtFBd7HfZ9QGbM1Qrw=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-use-controllable-state/@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
@@ -6828,6 +6894,22 @@
|
||||
|
||||
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.5", "", {}, "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-effect-event": "0.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.13", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.7", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"conf/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
@@ -6838,8 +6920,6 @@
|
||||
|
||||
"d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="],
|
||||
|
||||
"duplexer2/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"duplexer2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"enquirer/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
@@ -6892,12 +6972,8 @@
|
||||
|
||||
"jest-util/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
|
||||
"jszip/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"log-symbols/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
@@ -6930,40 +7006,20 @@
|
||||
|
||||
"pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-accordion/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-checkbox/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-collapsible/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-dialog/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-dropdown-menu/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-menu/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-menubar/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-navigation-menu/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-navigation-menu/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-popover/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-popper/@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.2", "", { "dependencies": { "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-popper/@radix-ui/rect": ["@radix-ui/rect@1.1.2", "", {}, "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-radio-group/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-roving-focus/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-scroll-area/@radix-ui/number": ["@radix-ui/number@1.1.2", "", {}, "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-select/@radix-ui/number": ["@radix-ui/number@1.1.2", "", {}, "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-select/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-select/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-slider/@radix-ui/number": ["@radix-ui/number@1.1.2", "", {}, "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig=="],
|
||||
@@ -6972,10 +7028,6 @@
|
||||
|
||||
"radix-ui/@radix-ui/react-switch/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-tabs/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-tooltip/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"react-remark/remark-parse/mdast-util-from-markdown": ["mdast-util-from-markdown@0.8.5", "", { "dependencies": { "@types/mdast": "^3.0.0", "mdast-util-to-string": "^2.0.0", "micromark": "~2.11.0", "parse-entities": "^2.0.0", "unist-util-stringify-position": "^2.0.0" } }, "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ=="],
|
||||
|
||||
"react-remark/remark-rehype/mdast-util-to-hast": ["mdast-util-to-hast@10.2.0", "", { "dependencies": { "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", "mdast-util-definitions": "^4.0.0", "mdurl": "^1.0.0", "unist-builder": "^2.0.0", "unist-util-generated": "^1.0.0", "unist-util-position": "^3.0.0", "unist-util-visit": "^2.0.0" } }, "sha512-JoPBfJ3gBnHZ18icCwHR50orC9kNH81tiR1gs01D8Q5YpV6adHNO9nKNuFBCJQ941/32PT1a63UF/DitmS3amQ=="],
|
||||
@@ -7070,32 +7122,8 @@
|
||||
|
||||
"test-exclude/minimatch/brace-expansion": ["brace-expansion@5.0.7", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA=="],
|
||||
|
||||
"unzipper/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"unzipper/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.5", "", {}, "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-effect-event": "0.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.13", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.7", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"webview-ui/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"webview-ui/@vitejs/plugin-react-swc/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
|
||||
@@ -7190,14 +7218,20 @@
|
||||
|
||||
"@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||
|
||||
"@radix-ui/react-accessible-icon/@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
"@radix-ui/react-context-menu/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
"@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
"@radix-ui/react-tabs/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-toggle-group/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-toggle/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-roving-focus/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="],
|
||||
|
||||
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@so-ric/colorspace/color/color-convert/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="],
|
||||
|
||||
"@so-ric/colorspace/color/color-string/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="],
|
||||
@@ -7264,6 +7298,10 @@
|
||||
|
||||
"claude-dev/@opentelemetry/sdk-trace-node/@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="],
|
||||
|
||||
"exceljs/archiver/archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||
|
||||
"exceljs/archiver/archiver-utils/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
@@ -7342,10 +7380,6 @@
|
||||
|
||||
"test-exclude/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="],
|
||||
|
||||
"webview-ui/vitest/@vitest/utils/loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],
|
||||
|
||||
"webview-ui/vitest/chai/check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],
|
||||
@@ -7374,8 +7408,6 @@
|
||||
|
||||
"@microsoft/tui-test/jest-diff/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.10", "", {}, "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA=="],
|
||||
|
||||
"@radix-ui/react-accessible-icon/@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="],
|
||||
|
||||
"@storybook/react-vite/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
|
||||
|
||||
"@vscode/test-cli/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||
@@ -7404,8 +7436,6 @@
|
||||
|
||||
"claude-dev/@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.28.0", "", {}, "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA=="],
|
||||
|
||||
"exceljs/archiver/archiver-utils/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"exceljs/archiver/archiver-utils/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"exceljs/archiver/zip-stream/archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# Cline SDK Changelog
|
||||
|
||||
## 0.0.64
|
||||
|
||||
- Improved max output token handling across providers (gateway routing, OpenAI vendor, and reasoning models)
|
||||
- Frontmatter and user-instruction files that start with a UTF-8 byte order mark (e.g. saved by Windows editors) now parse correctly
|
||||
|
||||
## 0.0.63
|
||||
|
||||
- The session runtime now emits `task.mistake_limit_reached` telemetry when the consecutive-mistake limit is hit, so every host (CLI, VS Code extension, hub daemon) captures it — including auto-stops when no host prompt is configured
|
||||
|
||||
## 0.0.62
|
||||
|
||||
- Fixed Ollama native API routing so context window and timeout settings work again
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"!@cline/core/telemetry",
|
||||
"!@cline/core/rpc",
|
||||
"!@cline/shared/browser",
|
||||
"!@cline/shared/node",
|
||||
"!@cline/shared/types",
|
||||
"!@cline/shared/storage",
|
||||
"!@cline/shared/db"
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
type AgentToolContext,
|
||||
ClineCore,
|
||||
createTool,
|
||||
stripUtf8Bom,
|
||||
} from "@cline/core";
|
||||
import YAML from "yaml";
|
||||
import { z } from "zod";
|
||||
@@ -179,6 +180,9 @@ function parseFrontmatter(md: string): {
|
||||
data: Record<string, unknown>;
|
||||
body: string;
|
||||
} {
|
||||
// stripUtf8Bom keeps the frontmatter match below working for files saved with a leading
|
||||
// UTF-8 BOM (see cline/cline#12151).
|
||||
md = stripUtf8Bom(md);
|
||||
const m = md.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
||||
if (!m) return { data: {}, body: md.trim() };
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cline/agents",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cline/cline",
|
||||
|
||||
@@ -69,6 +69,50 @@ describe("AgentRuntime", () => {
|
||||
expect(model.requests).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("fails a turn that hits the model output token limit before completion", async () => {
|
||||
const logger = {
|
||||
debug: vi.fn(),
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
const model = new ScriptedModel([
|
||||
() => [
|
||||
{ type: "reasoning-delta", text: "thinking..." },
|
||||
{ type: "finish", reason: "max-tokens" },
|
||||
],
|
||||
]);
|
||||
const runtime = new AgentRuntime({ model, logger });
|
||||
|
||||
const result = await runtime.run("Hi");
|
||||
|
||||
expect(result.status).toBe("failed");
|
||||
expect(result.error?.message).toContain("maximum output token limit");
|
||||
expect(model.requests).toHaveLength(1);
|
||||
expect(result.messages).toHaveLength(2);
|
||||
expect(result.messages.at(-1)).toMatchObject({
|
||||
role: "assistant",
|
||||
content: [{ type: "reasoning", text: "thinking..." }],
|
||||
});
|
||||
expect(logger.log).toHaveBeenCalledWith(
|
||||
"Agent loop caught error",
|
||||
expect.objectContaining({
|
||||
severity: "error",
|
||||
status: "failed",
|
||||
errorMessage: expect.stringContaining("maximum output token limit"),
|
||||
iteration: 1,
|
||||
assistantContentPartCount: 1,
|
||||
}),
|
||||
);
|
||||
expect(logger.error).toHaveBeenCalledWith(
|
||||
"Agent run failed",
|
||||
expect.objectContaining({
|
||||
error: expect.objectContaining({
|
||||
message: expect.stringContaining("maximum output token limit"),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not persist an empty assistant message when the model stream fails", async () => {
|
||||
const model = new ScriptedModel([
|
||||
() => [{ type: "finish", reason: "error", error: "upstream failed" }],
|
||||
@@ -1725,6 +1769,14 @@ describe("AgentRuntime", () => {
|
||||
|
||||
expect(result.status).toBe("failed");
|
||||
expect(events).toContain("run-failed");
|
||||
expect(logger.log).toHaveBeenCalledWith(
|
||||
"Agent loop caught error",
|
||||
expect.objectContaining({
|
||||
severity: "error",
|
||||
status: "failed",
|
||||
errorMessage: "model failed",
|
||||
}),
|
||||
);
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
expect(telemetry.capture).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -34,6 +34,9 @@ import {
|
||||
} from "@cline/shared";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
const MAX_TOKENS_INCOMPLETE_TURN_MESSAGE =
|
||||
"Model reached the maximum output token limit before completing the turn";
|
||||
|
||||
// Local `createUID` helper. The clinee source imports this from
|
||||
// `@cline/shared` (see `packages/shared/dist/identifier.ts`), but
|
||||
// sdk-re's shared package does not expose it yet. Inlining here keeps
|
||||
@@ -645,6 +648,9 @@ export class AgentRuntime {
|
||||
finishReason,
|
||||
});
|
||||
|
||||
if (finishReason === "max-tokens" && toolCalls.length === 0) {
|
||||
throw new Error(MAX_TOKENS_INCOMPLETE_TURN_MESSAGE);
|
||||
}
|
||||
if (finishReason === "error" && toolCalls.length === 0) {
|
||||
throw new Error(this.state.lastError ?? "Model stream failed");
|
||||
}
|
||||
@@ -718,23 +724,33 @@ export class AgentRuntime {
|
||||
const normalized =
|
||||
error instanceof Error ? error : new Error(String(error));
|
||||
const isControlledStop = normalized instanceof ControlledStopError;
|
||||
const status =
|
||||
this.abortController.signal.aborted || isControlledStop
|
||||
? "aborted"
|
||||
: "failed";
|
||||
const isAborted = this.abortController.signal.aborted || isControlledStop;
|
||||
const status = isAborted ? "aborted" : "failed";
|
||||
this.state.status = status;
|
||||
this.state.lastError = normalized.message;
|
||||
const lastAssistantMessage = this.findLastAssistantMessage();
|
||||
const result: AgentRunResult = {
|
||||
agentId: this.state.agentId,
|
||||
agentRole: this.state.agentRole,
|
||||
runId: this.state.runId ?? createUID("run"),
|
||||
status,
|
||||
iterations: this.state.iteration,
|
||||
outputText: textFromMessage(this.findLastAssistantMessage()),
|
||||
outputText: textFromMessage(lastAssistantMessage),
|
||||
messages: cloneMessages(this.state.messages),
|
||||
usage: cloneUsage(this.state.usage),
|
||||
error: status === "failed" ? normalized : undefined,
|
||||
};
|
||||
this.config.logger?.log?.("Agent loop caught error", {
|
||||
severity: status === "failed" ? "error" : "warn",
|
||||
agentId: this.state.agentId,
|
||||
agentRole: this.state.agentRole,
|
||||
runId: result.runId,
|
||||
status,
|
||||
iteration: this.state.iteration,
|
||||
errorName: normalized.name,
|
||||
errorMessage: normalized.message,
|
||||
assistantContentPartCount: lastAssistantMessage?.content.length ?? 0,
|
||||
});
|
||||
await this.callAfterRunHooks(result);
|
||||
if (status === "failed") {
|
||||
await this.emit({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@cline/core",
|
||||
"description": "Cline Core SDK for Node Runtime",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cline/cline",
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Origin-session delivery for agent-created scheduled tasks.
|
||||
*
|
||||
* When an agent creates a schedule with `deliverTo: "origin_session"`, the
|
||||
* scheduled run still executes in its own isolated session. On completion, its
|
||||
* result is fed back into the session that created the schedule as a queued
|
||||
* follow-up turn, so the main agent can continue working with it.
|
||||
*
|
||||
* Delivery is best-effort: if the origin session is not currently active
|
||||
* (persisted-but-not-in-memory), `runTurn` rejects and we skip rather than
|
||||
* throw. Appending into a persisted-but-inactive session is a follow-up.
|
||||
*/
|
||||
|
||||
import type { RuntimeHost } from "../../runtime/host/runtime-host";
|
||||
|
||||
interface LooseMessage {
|
||||
role?: string;
|
||||
content?: unknown;
|
||||
}
|
||||
|
||||
function extractText(content: unknown): string {
|
||||
if (typeof content === "string") {
|
||||
return content;
|
||||
}
|
||||
if (Array.isArray(content)) {
|
||||
return content
|
||||
.map((part) => {
|
||||
if (typeof part === "string") {
|
||||
return part;
|
||||
}
|
||||
if (
|
||||
part &&
|
||||
typeof part === "object" &&
|
||||
"text" in part &&
|
||||
typeof (part as { text?: unknown }).text === "string"
|
||||
) {
|
||||
return (part as { text: string }).text;
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function extractLastAssistantText(
|
||||
messages: readonly LooseMessage[],
|
||||
): string | undefined {
|
||||
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
||||
if (messages[i]?.role === "assistant") {
|
||||
const text = extractText(messages[i]?.content).trim();
|
||||
if (text) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface OriginSessionDeliveryInput {
|
||||
host: RuntimeHost;
|
||||
/** Session that created the schedule (delivery target). */
|
||||
originSessionId: string;
|
||||
/** Session the scheduled run executed in (source of the reply). */
|
||||
runSessionId?: string;
|
||||
scheduleId: string;
|
||||
/** Normalized execution status ("success" | "failed" | ...). */
|
||||
status: string;
|
||||
errorMessage?: string;
|
||||
logger?: { log?: (message: string, meta?: unknown) => void };
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver a completed scheduled run's result into its origin session as a
|
||||
* queued follow-up turn. Returns true when the turn was queued, false when the
|
||||
* origin session was not active (skipped) or delivery otherwise failed.
|
||||
*/
|
||||
export async function deliverScheduleResultToOriginSession(
|
||||
input: OriginSessionDeliveryInput,
|
||||
): Promise<boolean> {
|
||||
const { host, originSessionId, runSessionId } = input;
|
||||
if (!originSessionId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let body: string;
|
||||
if (input.status === "success" && runSessionId) {
|
||||
const messages = (await host
|
||||
.readSessionMessages(runSessionId)
|
||||
.catch(() => [])) as readonly LooseMessage[];
|
||||
const text = extractLastAssistantText(messages);
|
||||
body = text
|
||||
? `[Scheduled task ${input.scheduleId} completed]\n\n${text}`
|
||||
: `[Scheduled task ${input.scheduleId} completed with no textual output.]`;
|
||||
} else {
|
||||
body = `[Scheduled task ${input.scheduleId} ${input.status}]${
|
||||
input.errorMessage ? `: ${input.errorMessage}` : "."
|
||||
}`;
|
||||
}
|
||||
|
||||
try {
|
||||
await host.runTurn({
|
||||
sessionId: originSessionId,
|
||||
prompt: body,
|
||||
delivery: "queue",
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
input.logger?.log?.(
|
||||
`schedule origin-session delivery skipped (session not active): ${originSessionId}`,
|
||||
{ error: error instanceof Error ? error.message : String(error) },
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -415,6 +415,14 @@ export class CronRunner {
|
||||
: run.status === "queued"
|
||||
? "pending"
|
||||
: "failed";
|
||||
const deliveryMode =
|
||||
typeof spec.metadata?.deliveryMode === "string"
|
||||
? spec.metadata.deliveryMode
|
||||
: undefined;
|
||||
const originSessionId =
|
||||
typeof spec.metadata?.originSessionId === "string"
|
||||
? spec.metadata.originSessionId
|
||||
: undefined;
|
||||
this.options.eventPublisher(eventType, {
|
||||
scheduleId: spec.externalId,
|
||||
executionId: run.runId,
|
||||
@@ -426,6 +434,10 @@ export class CronRunner {
|
||||
: undefined,
|
||||
status,
|
||||
errorMessage: run.error,
|
||||
// Delivery routing hints for agent-created schedules. Consumers use
|
||||
// these to feed a run's output back into the origin session.
|
||||
...(deliveryMode ? { deliveryMode } : {}),
|
||||
...(originSessionId ? { originSessionId } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -526,7 +538,12 @@ export class CronRunner {
|
||||
provider,
|
||||
model,
|
||||
mode,
|
||||
source: spec.source?.trim() || "user",
|
||||
// Hub-created schedules surface their run sessions in history tagged
|
||||
// with source "schedule" so users can distinguish scheduled runs.
|
||||
source:
|
||||
spec.source?.trim() === "hub-schedule"
|
||||
? "schedule"
|
||||
: spec.source?.trim() || "user",
|
||||
systemPrompt: await this.buildSystemPrompt(
|
||||
spec,
|
||||
workspaceRoot,
|
||||
|
||||
@@ -60,6 +60,10 @@ export class HubScheduleCommandService {
|
||||
tags: Array.isArray(envelope.payload?.tags)
|
||||
? (envelope.payload?.tags as string[])
|
||||
: undefined,
|
||||
originSessionId:
|
||||
typeof envelope.payload?.originSessionId === "string"
|
||||
? envelope.payload.originSessionId
|
||||
: undefined,
|
||||
}),
|
||||
});
|
||||
case "schedule.get":
|
||||
|
||||
@@ -83,6 +83,12 @@ export interface ListSchedulesOptions {
|
||||
enabled?: boolean;
|
||||
limit?: number;
|
||||
tags?: string[];
|
||||
/**
|
||||
* Only return schedules created by an agent from this origin session
|
||||
* (matched against `metadata.originSessionId`). Used to surface the
|
||||
* schedule↔session linkage ("N scheduled tasks opened for this session").
|
||||
*/
|
||||
originSessionId?: string;
|
||||
}
|
||||
|
||||
export interface ListScheduleExecutionsOptions {
|
||||
@@ -249,9 +255,22 @@ export class HubScheduleService {
|
||||
}
|
||||
|
||||
public listSchedules(options: ListSchedulesOptions = {}): ScheduleRecord[] {
|
||||
return this.store
|
||||
.listHubSchedules(options)
|
||||
const { originSessionId, limit } = options;
|
||||
// When filtering by origin session we must filter on the mapped record's
|
||||
// metadata, so drop the store-level limit and re-apply it afterwards.
|
||||
const storeOptions = originSessionId
|
||||
? { ...options, limit: undefined }
|
||||
: options;
|
||||
const schedules = this.store
|
||||
.listHubSchedules(storeOptions)
|
||||
.map((spec) => specToSchedule(spec));
|
||||
if (!originSessionId) {
|
||||
return schedules;
|
||||
}
|
||||
const filtered = schedules.filter(
|
||||
(schedule) => schedule.metadata?.originSessionId === originSessionId,
|
||||
);
|
||||
return typeof limit === "number" ? filtered.slice(0, limit) : filtered;
|
||||
}
|
||||
|
||||
public updateSchedule(
|
||||
|
||||
@@ -86,6 +86,24 @@ ${content}`);
|
||||
expect(updateSkillMarkdownEnabledState(content, true)).toBe(content);
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/cline/cline/issues/12151: a leading UTF-8 BOM
|
||||
// (e.g. saved by Windows Notepad's "UTF-8 with BOM" encoding) must not prevent frontmatter
|
||||
// from being recognized when toggling a skill's enabled state.
|
||||
it("disables a skill whose content starts with a UTF-8 BOM", () => {
|
||||
const content = `\uFEFF---
|
||||
name: code-review
|
||||
description: Review code carefully
|
||||
---
|
||||
First line.`;
|
||||
|
||||
const updated = updateSkillMarkdownEnabledState(content, false);
|
||||
const parsed = parseSkillConfigFromMarkdown(updated, "fallback");
|
||||
|
||||
expect(parsed.disabled).toBe(true);
|
||||
expect(parsed.frontmatter.name).toBe("code-review");
|
||||
expect(parsed.frontmatter.description).toBe("Review code carefully");
|
||||
});
|
||||
|
||||
it("writes toggled content and returns the resulting state", async () => {
|
||||
const tempRoot = await mkdtemp(join(tmpdir(), "core-skill-toggle-"));
|
||||
tempRoots.push(tempRoot);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { stripUtf8Bom } from "@cline/shared";
|
||||
import YAML from "yaml";
|
||||
|
||||
export interface ToggleSkillFrontmatterOptions {
|
||||
@@ -19,10 +20,15 @@ interface MarkdownFrontmatterParts {
|
||||
}
|
||||
|
||||
function parseMarkdownFrontmatter(content: string): MarkdownFrontmatterParts {
|
||||
// Strip a leading UTF-8 BOM (e.g. added by Windows Notepad's "UTF-8 with BOM" encoding),
|
||||
// which Node's `utf-8` decoding does not strip on its own. Without this the frontmatter
|
||||
// regex below never matches a file that starts with "\uFEFF---" (see cline/cline#12151).
|
||||
const normalizedContent = stripUtf8Bom(content);
|
||||
|
||||
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
||||
const match = content.match(frontmatterRegex);
|
||||
const match = normalizedContent.match(frontmatterRegex);
|
||||
if (!match) {
|
||||
return { data: {}, body: content, hadFrontmatter: false };
|
||||
return { data: {}, body: normalizedContent, hadFrontmatter: false };
|
||||
}
|
||||
|
||||
const [, yamlContent, body] = match;
|
||||
|
||||
@@ -137,6 +137,23 @@ Document rollout and rollback steps.`,
|
||||
expect(workflow.disabled).toBe(true);
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/cline/cline/issues/12151: a leading UTF-8 BOM
|
||||
// (e.g. saved by Windows Notepad's "UTF-8 with BOM" encoding) must not prevent frontmatter
|
||||
// from being recognized.
|
||||
it("parses markdown frontmatter when the content starts with a UTF-8 BOM", () => {
|
||||
const skill = parseSkillConfigFromMarkdown(
|
||||
`\uFEFF---
|
||||
name: my-skill
|
||||
description: A test skill
|
||||
---
|
||||
This is a test skill.`,
|
||||
"fallback",
|
||||
);
|
||||
expect(skill.name).toBe("my-skill");
|
||||
expect(skill.description).toBe("A test skill");
|
||||
expect(skill.instructions).toBe("This is a test skill.");
|
||||
});
|
||||
|
||||
it("emits typed events for skills, rules, and workflows in one watcher", async () => {
|
||||
const tempRoot = await mkdtemp(
|
||||
join(tmpdir(), "core-user-instructions-loader-"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { readdir, readFile, stat } from "node:fs/promises";
|
||||
import { basename, dirname, extname, join, resolve } from "node:path";
|
||||
import { stripUtf8Bom } from "@cline/shared";
|
||||
import {
|
||||
AGENTS_RULES_FILE_NAME,
|
||||
RULES_CONFIG_DIRECTORY_NAME,
|
||||
@@ -193,10 +194,15 @@ async function discoverManagedPluginRoots(
|
||||
function parseMarkdownFrontmatter(
|
||||
content: string,
|
||||
): ParseMarkdownFrontmatterResult {
|
||||
// Strip a leading UTF-8 BOM (e.g. added by Windows Notepad's "UTF-8 with BOM" encoding),
|
||||
// which Node's `utf-8` decoding does not strip on its own. Without this the frontmatter
|
||||
// regex below never matches a file that starts with "\uFEFF---" (see cline/cline#12151).
|
||||
const normalizedContent = stripUtf8Bom(content);
|
||||
|
||||
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
||||
const match = content.match(frontmatterRegex);
|
||||
const match = normalizedContent.match(frontmatterRegex);
|
||||
if (!match) {
|
||||
return { data: {}, body: content, hadFrontmatter: false };
|
||||
return { data: {}, body: normalizedContent, hadFrontmatter: false };
|
||||
}
|
||||
|
||||
const [, yamlContent, body] = match;
|
||||
@@ -211,7 +217,7 @@ function parseMarkdownFrontmatter(
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
data: {},
|
||||
body: content,
|
||||
body: normalizedContent,
|
||||
hadFrontmatter: true,
|
||||
parseError: message,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ export const DefaultToolNames = {
|
||||
SKILLS: "skills",
|
||||
ASK: "ask_question",
|
||||
SUBMIT_AND_EXIT: "submit_and_exit",
|
||||
SCHEDULE_TASK: "schedule_task",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
@@ -34,4 +35,5 @@ export const ALL_DEFAULT_TOOL_NAMES: DefaultToolName[] = [
|
||||
DefaultToolNames.SKILLS,
|
||||
DefaultToolNames.ASK,
|
||||
DefaultToolNames.SUBMIT_AND_EXIT,
|
||||
DefaultToolNames.SCHEDULE_TASK,
|
||||
];
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
getToolContextTelemetry,
|
||||
} from "../../services/telemetry/tool-context";
|
||||
import {
|
||||
buildRunCommandsDescription,
|
||||
createDefaultTools,
|
||||
createReadFilesTool,
|
||||
createSearchTool,
|
||||
@@ -481,54 +480,6 @@ describe("default apply_patch tool", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("run_commands tool description", () => {
|
||||
it("names PowerShell with ';' sequencing for PowerShell shells", () => {
|
||||
const description = buildRunCommandsDescription("powershell", true);
|
||||
expect(description).toContain("Commands run through PowerShell");
|
||||
expect(description).toContain("use ';' to sequence commands");
|
||||
expect(description).toContain("in Windows environment");
|
||||
});
|
||||
|
||||
it("names cmd.exe with '&&' sequencing for cmd shells", () => {
|
||||
const description = buildRunCommandsDescription("cmd", true);
|
||||
expect(description).toContain("Commands run through cmd.exe");
|
||||
expect(description).toContain("use '&&' to sequence commands");
|
||||
expect(description).not.toContain("PowerShell");
|
||||
});
|
||||
|
||||
it("describes WSL bash with the /mnt working-directory mapping", () => {
|
||||
const description = buildRunCommandsDescription("wsl", true);
|
||||
expect(description).toContain("bash in WSL");
|
||||
expect(description).toContain("/mnt/<drive>");
|
||||
expect(description).not.toContain("PowerShell");
|
||||
});
|
||||
|
||||
it("notes the Windows host for POSIX shells on Windows only", () => {
|
||||
const onWindows = buildRunCommandsDescription("posix", true);
|
||||
expect(onWindows).toContain("POSIX (bash-compatible) shell on Windows");
|
||||
expect(onWindows).not.toContain("PowerShell");
|
||||
|
||||
const onUnix = buildRunCommandsDescription("posix", false);
|
||||
expect(onUnix).not.toContain("Windows");
|
||||
expect(onUnix).toContain("grep/head/tail");
|
||||
});
|
||||
|
||||
it("derives the createShellTool description from config.shell", () => {
|
||||
const posixTool = createShellTool(async () => "ok", {
|
||||
shell: "/bin/bash",
|
||||
});
|
||||
expect(posixTool.description).toContain(
|
||||
"Run non-interactive shell commands",
|
||||
);
|
||||
expect(posixTool.description).not.toContain("PowerShell");
|
||||
|
||||
const cmdTool = createShellTool(async () => "ok", {
|
||||
shell: "C:\\Windows\\System32\\cmd.exe",
|
||||
});
|
||||
expect(cmdTool.description).toContain("Commands run through cmd.exe");
|
||||
});
|
||||
});
|
||||
|
||||
describe("default run_commands tool", () => {
|
||||
function createTelemetryStub(): ITelemetryService {
|
||||
return {
|
||||
|
||||
@@ -8,9 +8,6 @@ import {
|
||||
type AgentTool,
|
||||
type AgentToolContext,
|
||||
createTool,
|
||||
getDefaultShell,
|
||||
getShellKind,
|
||||
type ShellKind,
|
||||
validateWithZod,
|
||||
zodToJsonSchema,
|
||||
} from "@cline/shared";
|
||||
@@ -49,6 +46,8 @@ import {
|
||||
ReadFilesInputSchema,
|
||||
ReadFilesInputUnionSchema,
|
||||
RunCommandsInputSchema,
|
||||
type ScheduleTaskInput,
|
||||
ScheduleTaskInputSchema,
|
||||
type SearchCodebaseInput,
|
||||
SearchCodebaseInputSchema,
|
||||
SearchCodebaseUnionInputSchema,
|
||||
@@ -65,6 +64,7 @@ import type {
|
||||
DefaultToolsConfig,
|
||||
EditorExecutor,
|
||||
FileReadExecutor,
|
||||
ScheduleTaskExecutor,
|
||||
SearchExecutor,
|
||||
ShellExecutor,
|
||||
SkillsExecutorWithMetadata,
|
||||
@@ -398,55 +398,15 @@ const RUN_COMMANDS_SHARED_INSTRUCTIONS =
|
||||
"Use for listing files, checking git status, running builds, executing tests, etc. " +
|
||||
"Commands must be non-interactive. Commands that require follow-up input like pagers should be skipped or used with supported flags/env (e.g. git --no-pager, --non-interactive) to bypass the interaction steps. ";
|
||||
|
||||
/**
|
||||
* Build the run_commands tool description for the shell that will actually
|
||||
* execute the commands. The shell kind decides the syntax guidance (quoting,
|
||||
* sequencing, heredocs), and isWindows adds environment context for POSIX
|
||||
* shells running on a Windows host (e.g. Git Bash).
|
||||
*/
|
||||
export function buildRunCommandsDescription(
|
||||
shellKind: ShellKind,
|
||||
isWindows: boolean,
|
||||
): string {
|
||||
if (shellKind === "powershell" || shellKind === "cmd") {
|
||||
const shellName = shellKind === "powershell" ? "PowerShell" : "cmd.exe";
|
||||
const sequencingOperator = shellKind === "powershell" ? "';'" : "'&&'";
|
||||
return (
|
||||
"Run non-interactive shell commands from the root of the workspace in Windows environment. " +
|
||||
RUN_COMMANDS_SHARED_INSTRUCTIONS +
|
||||
`Output beyond ~${Math.round(MAX_COMMAND_OUTPUT_CHARS / 1000)}k characters is middle-truncated (start and end preserved); filter output when you need specific sections. ` +
|
||||
`Commands run through ${shellName}; quote paths and arguments for ${shellName} and use ${sequencingOperator} to sequence commands. ` +
|
||||
"Include multiple commands in the same call when they are independent and safe to run concurrently. When independent reads, searches, or edits are also needed, call those tools in the same response."
|
||||
);
|
||||
}
|
||||
|
||||
const environmentNote =
|
||||
shellKind === "wsl"
|
||||
? "Commands run through bash in WSL (wsl.exe); the Windows working directory is mounted under /mnt/<drive>. "
|
||||
: isWindows
|
||||
? "Commands run through a POSIX (bash-compatible) shell on Windows. "
|
||||
: "";
|
||||
return (
|
||||
"Run non-interactive shell commands from the root of the workspace. " +
|
||||
RUN_COMMANDS_SHARED_INSTRUCTIONS +
|
||||
environmentNote +
|
||||
"Commands should be properly shell-escaped and targeted to avoid error or timeout. Include multiple commands in the same call when they are independent complete shell commands and safe to run concurrently; multiline scripts and heredocs must be a single command string. When independent reads, searches, or edits are also needed, call those tools in the same response. " +
|
||||
`Output beyond ~${Math.round(MAX_COMMAND_OUTPUT_CHARS / 1000)}k characters is middle-truncated (start and end preserved); pipe through grep/head/tail when you need specific sections of large output. ` +
|
||||
"For long-running commands, run them in background and redirect output to a tmp file that you can read from later."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the run_commands shell tool for the current platform.
|
||||
*
|
||||
* This preserves the SDK's platform-specific prompting/schema choices while
|
||||
* exposing a single generic shell-tool factory for host integrations. Pass
|
||||
* config.shell (matching the executor's shell) so the syntax guidance in the
|
||||
* tool description matches the shell that actually runs the commands.
|
||||
* exposing a single generic shell-tool factory for host integrations.
|
||||
*/
|
||||
export function createShellTool(
|
||||
executor: ShellExecutor,
|
||||
config: Pick<DefaultToolsConfig, "cwd" | "bashTimeoutMs" | "shell"> = {},
|
||||
config: Pick<DefaultToolsConfig, "cwd" | "bashTimeoutMs"> = {},
|
||||
): AgentTool<unknown, ToolOperationResult[]> {
|
||||
const timeoutMs = config.bashTimeoutMs ?? 30000;
|
||||
const timeoutSource =
|
||||
@@ -455,11 +415,19 @@ export function createShellTool(
|
||||
: "configured_setting";
|
||||
const cwd = config.cwd ?? process.cwd();
|
||||
const isWindows = process.platform === "win32";
|
||||
const shell = config.shell ?? getDefaultShell(process.platform);
|
||||
|
||||
return createTool<unknown, ToolOperationResult[]>({
|
||||
name: "run_commands",
|
||||
description: buildRunCommandsDescription(getShellKind(shell), isWindows),
|
||||
description: isWindows
|
||||
? "Run non-interactive shell commands from the root of the workspace in Windows environment. " +
|
||||
RUN_COMMANDS_SHARED_INSTRUCTIONS +
|
||||
`Output beyond ~${Math.round(MAX_COMMAND_OUTPUT_CHARS / 1000)}k characters is middle-truncated (start and end preserved); filter output when you need specific sections. ` +
|
||||
"Commands run through PowerShell; quote paths and arguments for PowerShell and use ';' to sequence commands. Include multiple commands in the same call when they are independent and safe to run concurrently. When independent reads, searches, or edits are also needed, call those tools in the same response."
|
||||
: "Run non-interactive shell commands from the root of the workspace. " +
|
||||
RUN_COMMANDS_SHARED_INSTRUCTIONS +
|
||||
"Commands should be properly shell-escaped and targeted to avoid error or timeout. Include multiple commands in the same call when they are independent complete shell commands and safe to run concurrently; multiline scripts and heredocs must be a single command string. When independent reads, searches, or edits are also needed, call those tools in the same response. " +
|
||||
`Output beyond ~${Math.round(MAX_COMMAND_OUTPUT_CHARS / 1000)}k characters is middle-truncated (start and end preserved); pipe through grep/head/tail when you need specific sections of large output. ` +
|
||||
"For long-running commands, run them in background and redirect output to a tmp file that you can read from later.",
|
||||
inputSchema: zodToJsonSchema(RunCommandsInputSchema),
|
||||
timeoutMs: timeoutMs * 2,
|
||||
retryable: false,
|
||||
@@ -480,6 +448,40 @@ export function createShellTool(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the schedule_task tool
|
||||
*
|
||||
* Lets the agent create a recurring scheduled task. The actual scheduling work
|
||||
* is delegated to the injected {@link ScheduleTaskExecutor}, which closes over a
|
||||
* host-provided schedule client — that is why this tool only appears when a
|
||||
* `scheduleTask` executor is supplied.
|
||||
*/
|
||||
export function createScheduleTaskTool(
|
||||
executor: ScheduleTaskExecutor,
|
||||
config: Pick<DefaultToolsConfig, "scheduleTaskTimeoutMs"> = {},
|
||||
): AgentTool<ScheduleTaskInput, string> {
|
||||
const timeoutMs = config.scheduleTaskTimeoutMs ?? 15000;
|
||||
|
||||
return createTool<ScheduleTaskInput, string>({
|
||||
name: "schedule_task",
|
||||
description:
|
||||
"Schedule a recurring task that runs a prompt on a cron cadence. " +
|
||||
"Use `schedule` for a five-field cron pattern (e.g. '0 9 * * *' for 09:00 daily). " +
|
||||
"`deliverTo` controls where each run's output goes: 'new_session' (an independent session that shows up in session history), " +
|
||||
"'origin_session' (delivered back into THIS session as follow-up work for you to continue), or " +
|
||||
"'connector' (posted into the current chat thread as a notification; only valid inside a connector session). " +
|
||||
"Defaults to 'new_session'. Use this when the user asks to run something on a schedule or be reminded periodically.",
|
||||
inputSchema: zodToJsonSchema(ScheduleTaskInputSchema),
|
||||
timeoutMs,
|
||||
retryable: false,
|
||||
maxRetries: 0,
|
||||
execute: async (input, context) => {
|
||||
const validatedInput = validateWithZod(ScheduleTaskInputSchema, input);
|
||||
return executor(validatedInput, context);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the fetch_web_content tool
|
||||
*
|
||||
@@ -856,6 +858,7 @@ export function createDefaultTools(
|
||||
enableSkills = true,
|
||||
enableAskQuestion = true,
|
||||
enableSubmitAndExit = false,
|
||||
enableScheduleTask = true,
|
||||
...config
|
||||
} = options;
|
||||
|
||||
@@ -907,5 +910,10 @@ export function createDefaultTools(
|
||||
tools.push(createSubmitAndExitTool(submitExecutor, config));
|
||||
}
|
||||
|
||||
// Add schedule_task tool if enabled and executor provided
|
||||
if (enableScheduleTask && executors.scheduleTask) {
|
||||
tools.push(createScheduleTaskTool(executors.scheduleTask, config));
|
||||
}
|
||||
|
||||
return tools as unknown as AgentTool[];
|
||||
}
|
||||
|
||||
@@ -41,6 +41,14 @@ export {
|
||||
createFileReadExecutor,
|
||||
type FileReadExecutorOptions,
|
||||
} from "./file-read";
|
||||
export {
|
||||
createScheduleTaskExecutor,
|
||||
type ScheduleTaskClient,
|
||||
type ScheduleTaskConnectorDelivery,
|
||||
type ScheduleTaskCreateInput,
|
||||
type ScheduleTaskCreateResult,
|
||||
type ScheduleTaskExecutorOptions,
|
||||
} from "./schedule-task";
|
||||
export { createSearchExecutor, type SearchExecutorOptions } from "./search";
|
||||
export {
|
||||
createWebFetchExecutor,
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import type { AgentToolContext } from "@cline/shared";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { ScheduleTaskInput } from "../schemas";
|
||||
import {
|
||||
createScheduleTaskExecutor,
|
||||
type ScheduleTaskCreateInput,
|
||||
} from "./schedule-task";
|
||||
|
||||
function ctx(sessionId?: string): AgentToolContext {
|
||||
return { agentId: "agent-1", iteration: 0, sessionId };
|
||||
}
|
||||
|
||||
function baseInput(
|
||||
overrides: Partial<ScheduleTaskInput> = {},
|
||||
): ScheduleTaskInput {
|
||||
return {
|
||||
name: "Daily summary",
|
||||
prompt: "Summarize activity",
|
||||
schedule: "0 9 * * *",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("createScheduleTaskExecutor", () => {
|
||||
it("defaults deliverTo to new_session and records originSessionId in metadata", async () => {
|
||||
const createSchedule = vi.fn(async (_input: ScheduleTaskCreateInput) => ({
|
||||
scheduleId: "sched_1",
|
||||
nextRunAt: 1_000,
|
||||
}));
|
||||
const executor = createScheduleTaskExecutor({
|
||||
client: { createSchedule },
|
||||
defaults: { workspaceRoot: "/repo", cwd: "/repo/app" },
|
||||
});
|
||||
|
||||
const result = await executor(baseInput(), ctx("origin-1"));
|
||||
|
||||
expect(createSchedule).toHaveBeenCalledTimes(1);
|
||||
const call = createSchedule.mock.calls[0][0];
|
||||
expect(call.name).toBe("Daily summary");
|
||||
expect(call.cronPattern).toBe("0 9 * * *");
|
||||
expect(call.workspaceRoot).toBe("/repo");
|
||||
expect(call.cwd).toBe("/repo/app");
|
||||
expect(call.createdBy).toBe("agent");
|
||||
expect(call.originSessionId).toBe("origin-1");
|
||||
expect(call.metadata).toMatchObject({
|
||||
deliveryMode: "new_session",
|
||||
originSessionId: "origin-1",
|
||||
});
|
||||
expect(result).toContain("sched_1");
|
||||
expect(result).toContain("new_session");
|
||||
});
|
||||
|
||||
it("passes deliveryMode=origin_session through metadata", async () => {
|
||||
const createSchedule = vi.fn(async () => ({ scheduleId: "sched_2" }));
|
||||
const executor = createScheduleTaskExecutor({
|
||||
client: { createSchedule },
|
||||
defaults: { workspaceRoot: "/repo" },
|
||||
});
|
||||
|
||||
await executor(baseInput({ deliverTo: "origin_session" }), ctx("origin-2"));
|
||||
|
||||
const call = createSchedule.mock.calls[0][0];
|
||||
expect(call.metadata?.deliveryMode).toBe("origin_session");
|
||||
expect(call.metadata?.originSessionId).toBe("origin-2");
|
||||
});
|
||||
|
||||
it("attaches the connector delivery descriptor when provided", async () => {
|
||||
const createSchedule = vi.fn(async () => ({ scheduleId: "sched_3" }));
|
||||
const executor = createScheduleTaskExecutor({
|
||||
client: { createSchedule },
|
||||
defaults: { workspaceRoot: "/repo" },
|
||||
connectorDelivery: { adapter: "telegram", threadId: "telegram:42" },
|
||||
});
|
||||
|
||||
await executor(baseInput({ deliverTo: "connector" }), ctx("origin-3"));
|
||||
|
||||
const call = createSchedule.mock.calls[0][0];
|
||||
expect(call.metadata?.deliveryMode).toBe("connector");
|
||||
expect(call.metadata?.delivery).toEqual({
|
||||
adapter: "telegram",
|
||||
threadId: "telegram:42",
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves delivery unset for connector mode when no descriptor is provided (host resolves it)", async () => {
|
||||
const createSchedule = vi.fn(async () => ({ scheduleId: "sched_4" }));
|
||||
const executor = createScheduleTaskExecutor({
|
||||
client: { createSchedule },
|
||||
defaults: { workspaceRoot: "/repo" },
|
||||
});
|
||||
|
||||
await executor(baseInput({ deliverTo: "connector" }), ctx("origin-4"));
|
||||
|
||||
const call = createSchedule.mock.calls[0][0];
|
||||
expect(call.metadata?.deliveryMode).toBe("connector");
|
||||
expect(call.metadata?.delivery).toBeUndefined();
|
||||
});
|
||||
|
||||
it("prefers explicit workspaceRoot/cwd from the tool input over defaults", async () => {
|
||||
const createSchedule = vi.fn(async () => ({ scheduleId: "sched_5" }));
|
||||
const executor = createScheduleTaskExecutor({
|
||||
client: { createSchedule },
|
||||
defaults: { workspaceRoot: "/repo", cwd: "/repo" },
|
||||
});
|
||||
|
||||
await executor(
|
||||
baseInput({ workspaceRoot: "/other", cwd: "/other/pkg" }),
|
||||
ctx("origin-5"),
|
||||
);
|
||||
|
||||
const call = createSchedule.mock.calls[0][0];
|
||||
expect(call.workspaceRoot).toBe("/other");
|
||||
expect(call.cwd).toBe("/other/pkg");
|
||||
});
|
||||
|
||||
it("records the timezone in metadata when provided", async () => {
|
||||
const createSchedule = vi.fn(async () => ({ scheduleId: "sched_6" }));
|
||||
const executor = createScheduleTaskExecutor({
|
||||
client: { createSchedule },
|
||||
defaults: { workspaceRoot: "/repo" },
|
||||
});
|
||||
|
||||
await executor(
|
||||
baseInput({ timezone: "America/New_York" }),
|
||||
ctx("origin-6"),
|
||||
);
|
||||
|
||||
const call = createSchedule.mock.calls[0][0];
|
||||
expect(call.metadata?.timezone).toBe("America/New_York");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Executor implementation for the `schedule_task` agent tool.
|
||||
*
|
||||
* The tool lets an agent create a recurring scheduled task from inside a
|
||||
* session. This module is host-agnostic: it defines a minimal
|
||||
* {@link ScheduleTaskClient} seam that the host wires to a real schedule
|
||||
* service (e.g. the hub `HubScheduleService`, or a `LocalScheduleClient`), and
|
||||
* a factory that builds the executor closure around it.
|
||||
*/
|
||||
|
||||
import type { ScheduleTaskExecutor } from "../types";
|
||||
|
||||
/**
|
||||
* Delivery descriptor for `deliverTo: "connector"` — mirrors the `delivery`
|
||||
* block the connector host stashes in a schedule's metadata for user-typed
|
||||
* `/schedule create`, so the existing per-adapter delivery path can post the
|
||||
* result into the originating chat thread with no extra wiring.
|
||||
*/
|
||||
export interface ScheduleTaskConnectorDelivery {
|
||||
adapter: string;
|
||||
threadId?: string;
|
||||
bindingKey?: string;
|
||||
channelId?: string;
|
||||
participantKey?: string;
|
||||
userName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized input the executor passes to the host's schedule client.
|
||||
*
|
||||
* `workspaceRoot` is optional: when the model omits it and the host provides no
|
||||
* default, the host client is expected to resolve it from the origin session
|
||||
* (`metadata.originSessionId`).
|
||||
*/
|
||||
export interface ScheduleTaskCreateInput {
|
||||
name: string;
|
||||
cronPattern: string;
|
||||
prompt: string;
|
||||
workspaceRoot?: string;
|
||||
cwd?: string;
|
||||
mode?: "act" | "plan";
|
||||
timezone?: string;
|
||||
/** Origin session id (also mirrored in `metadata.originSessionId`). */
|
||||
originSessionId?: string;
|
||||
/** Who created the schedule; the tool passes "agent". */
|
||||
createdBy?: string;
|
||||
/**
|
||||
* Free-form metadata persisted on the schedule spec. The tool populates
|
||||
* `deliveryMode`, `originSessionId`, and (for connector delivery) `delivery`.
|
||||
*/
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ScheduleTaskCreateResult {
|
||||
scheduleId: string;
|
||||
/** Epoch millis of the next scheduled run, when known. */
|
||||
nextRunAt?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal schedule client the executor depends on. The host implements this by
|
||||
* delegating to whatever schedule service it has access to.
|
||||
*/
|
||||
export interface ScheduleTaskClient {
|
||||
createSchedule(
|
||||
input: ScheduleTaskCreateInput,
|
||||
): Promise<ScheduleTaskCreateResult>;
|
||||
}
|
||||
|
||||
export interface ScheduleTaskExecutorOptions {
|
||||
/** Client used to persist the schedule. */
|
||||
client: ScheduleTaskClient;
|
||||
/**
|
||||
* Session defaults used when the model omits `workspaceRoot`/`cwd`.
|
||||
*/
|
||||
defaults?: {
|
||||
workspaceRoot?: string;
|
||||
cwd?: string;
|
||||
};
|
||||
/**
|
||||
* When the current session is connector-backed, the delivery descriptor for
|
||||
* its chat thread. Required for `deliverTo: "connector"`; absent otherwise.
|
||||
*/
|
||||
connectorDelivery?: ScheduleTaskConnectorDelivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the `schedule_task` executor closure. The returned executor reads the
|
||||
* origin session id from the tool context and records it (plus the chosen
|
||||
* delivery mode) on the schedule's metadata so downstream delivery and the
|
||||
* schedule↔session linkage can find it.
|
||||
*/
|
||||
export function createScheduleTaskExecutor(
|
||||
options: ScheduleTaskExecutorOptions,
|
||||
): ScheduleTaskExecutor {
|
||||
return async (input, context) => {
|
||||
const deliverTo = input.deliverTo ?? "new_session";
|
||||
|
||||
// workspaceRoot/cwd may be omitted; the host client resolves them from the
|
||||
// origin session when they are absent.
|
||||
const workspaceRoot =
|
||||
input.workspaceRoot?.trim() || options.defaults?.workspaceRoot?.trim();
|
||||
const cwd = input.cwd?.trim() || options.defaults?.cwd?.trim();
|
||||
const originSessionId = context.sessionId?.trim();
|
||||
|
||||
const metadata: Record<string, unknown> = {
|
||||
deliveryMode: deliverTo,
|
||||
...(originSessionId ? { originSessionId } : {}),
|
||||
...(input.timezone ? { timezone: input.timezone } : {}),
|
||||
};
|
||||
|
||||
// For connector delivery, use a host-provided descriptor when present
|
||||
// (e.g. a client-side executor that already knows its thread). Otherwise
|
||||
// leave it unset so the host client can resolve it from the origin
|
||||
// session's metadata (the hub does this); it validates/errors there.
|
||||
if (deliverTo === "connector" && options.connectorDelivery) {
|
||||
metadata.delivery = options.connectorDelivery;
|
||||
}
|
||||
|
||||
const result = await options.client.createSchedule({
|
||||
name: input.name,
|
||||
cronPattern: input.schedule,
|
||||
prompt: input.prompt,
|
||||
workspaceRoot,
|
||||
cwd,
|
||||
mode: input.mode,
|
||||
timezone: input.timezone,
|
||||
originSessionId,
|
||||
createdBy: "agent",
|
||||
metadata,
|
||||
});
|
||||
|
||||
const parts = [
|
||||
`Scheduled task "${input.name}" created (id: ${result.scheduleId}).`,
|
||||
`Cron: ${input.schedule}${input.timezone ? ` in ${input.timezone}` : ""}.`,
|
||||
`Delivery: ${deliverTo}.`,
|
||||
];
|
||||
if (typeof result.nextRunAt === "number") {
|
||||
parts.push(`Next run: ${new Date(result.nextRunAt).toISOString()}.`);
|
||||
}
|
||||
return parts.join(" ");
|
||||
};
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export {
|
||||
createDefaultTools,
|
||||
createEditorTool,
|
||||
createReadFilesTool,
|
||||
createScheduleTaskTool,
|
||||
createSearchTool,
|
||||
createShellTool,
|
||||
createSkillsTool,
|
||||
@@ -31,6 +32,7 @@ export {
|
||||
createDefaultShellExecutor,
|
||||
createEditorExecutor,
|
||||
createFileReadExecutor,
|
||||
createScheduleTaskExecutor,
|
||||
createSearchExecutor,
|
||||
createShellExecutor,
|
||||
createWebFetchExecutor,
|
||||
@@ -39,6 +41,11 @@ export {
|
||||
type FileReadExecutorOptions,
|
||||
PatchActionType,
|
||||
type PatchFileChange,
|
||||
type ScheduleTaskClient,
|
||||
type ScheduleTaskConnectorDelivery,
|
||||
type ScheduleTaskCreateInput,
|
||||
type ScheduleTaskCreateResult,
|
||||
type ScheduleTaskExecutorOptions,
|
||||
type SearchExecutorOptions,
|
||||
type ShellExecutorOptions,
|
||||
type WebFetchExecutorOptions,
|
||||
@@ -86,6 +93,10 @@ export {
|
||||
ReadFilesInputSchema,
|
||||
type RunCommandsInput,
|
||||
RunCommandsInputSchema,
|
||||
type ScheduleTaskDeliverTo,
|
||||
ScheduleTaskDeliverToSchema,
|
||||
type ScheduleTaskInput,
|
||||
ScheduleTaskInputSchema,
|
||||
type SearchCodebaseInput,
|
||||
SearchCodebaseInputSchema,
|
||||
type SkillsInput,
|
||||
@@ -107,6 +118,7 @@ export type {
|
||||
DefaultToolsConfig,
|
||||
EditorExecutor,
|
||||
FileReadExecutor,
|
||||
ScheduleTaskExecutor,
|
||||
SearchExecutor,
|
||||
ShellExecutor,
|
||||
SkillsExecutor,
|
||||
|
||||
@@ -44,6 +44,7 @@ const TOOL_NAME_TO_FLAG: Record<
|
||||
| "enableSkills"
|
||||
| "enableAskQuestion"
|
||||
| "enableSubmitAndExit"
|
||||
| "enableScheduleTask"
|
||||
>
|
||||
> = {
|
||||
read_files: "enableReadFiles",
|
||||
@@ -55,6 +56,7 @@ const TOOL_NAME_TO_FLAG: Record<
|
||||
skills: "enableSkills",
|
||||
ask_question: "enableAskQuestion",
|
||||
submit_and_exit: "enableSubmitAndExit",
|
||||
schedule_task: "enableScheduleTask",
|
||||
};
|
||||
|
||||
export const DEFAULT_MODEL_TOOL_ROUTING_RULES: ToolRoutingRule[] = [
|
||||
|
||||
@@ -346,3 +346,79 @@ export type AskQuestionInput = z.infer<typeof AskQuestionInputSchema>;
|
||||
* Input for the submit and exit tool
|
||||
*/
|
||||
export type SubmitInput = z.infer<typeof SubmitInputSchema>;
|
||||
|
||||
/**
|
||||
* Where a scheduled task's output is delivered.
|
||||
* - `new_session`: each run creates its own session that appears in session
|
||||
* history (marked with source=schedule).
|
||||
* - `origin_session`: the run's output is delivered back into the session that
|
||||
* created the schedule, as follow-up work for the main agent.
|
||||
* - `connector`: the run's output is posted into the connector chat thread this
|
||||
* session belongs to (only valid inside a connector-backed session).
|
||||
*/
|
||||
export const ScheduleTaskDeliverToSchema = z
|
||||
.enum(["new_session", "origin_session", "connector"])
|
||||
.describe(
|
||||
"Where each scheduled run's output goes: 'new_session' (independent session in history), 'origin_session' (fed back into this session as follow-up work), or 'connector' (posted into the current chat thread; only valid in a connector session).",
|
||||
);
|
||||
|
||||
/**
|
||||
* Schema for the schedule_task tool input
|
||||
*/
|
||||
export const ScheduleTaskInputSchema = z
|
||||
.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("Short human-readable name for the scheduled task."),
|
||||
prompt: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe(
|
||||
"The task instructions the scheduled run should execute each time it fires.",
|
||||
),
|
||||
schedule: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe(
|
||||
"Five-field cron pattern describing the cadence, e.g. '0 9 * * *' for 09:00 every day.",
|
||||
),
|
||||
deliverTo: ScheduleTaskDeliverToSchema.optional().describe(
|
||||
"Where each run's output goes. Defaults to 'new_session' when omitted.",
|
||||
),
|
||||
timezone: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional IANA timezone for interpreting the cron pattern, e.g. 'America/New_York'.",
|
||||
),
|
||||
mode: z
|
||||
.enum(["act", "plan"])
|
||||
.optional()
|
||||
.describe("Optional agent mode for the scheduled run."),
|
||||
workspaceRoot: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional absolute workspace root for the run; defaults to this session's workspace.",
|
||||
),
|
||||
cwd: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional working directory for the run; defaults to this session's cwd.",
|
||||
),
|
||||
})
|
||||
.describe(
|
||||
"Create a recurring scheduled task that runs a prompt on a cron cadence.",
|
||||
);
|
||||
|
||||
/**
|
||||
* Input for the schedule_task tool
|
||||
*/
|
||||
export type ScheduleTaskInput = z.infer<typeof ScheduleTaskInputSchema>;
|
||||
|
||||
/**
|
||||
* Delivery target for `deliverTo: 'new_session' | 'origin_session' | 'connector'`.
|
||||
*/
|
||||
export type ScheduleTaskDeliverTo = z.infer<typeof ScheduleTaskDeliverToSchema>;
|
||||
|
||||
@@ -23,6 +23,23 @@ You are a code reviewer.`);
|
||||
});
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/cline/cline/issues/12151: a leading UTF-8 BOM
|
||||
// (e.g. saved by Windows Notepad's "UTF-8 with BOM" encoding) must not prevent frontmatter
|
||||
// from being recognized.
|
||||
it("parses frontmatter when the content starts with a UTF-8 BOM", () => {
|
||||
const config = parseConfiguredAgentConfig(`\uFEFF---
|
||||
name: code-reviewer
|
||||
description: Reviews code
|
||||
---
|
||||
You are a code reviewer.`);
|
||||
|
||||
expect(config).toMatchObject({
|
||||
name: "code-reviewer",
|
||||
description: "Reviews code",
|
||||
systemPrompt: "You are a code reviewer.",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not treat delimiter lines in the body as frontmatter delimiters", () => {
|
||||
const config = parseConfiguredAgentConfig(`---
|
||||
name: code-reviewer
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Dirent, existsSync, readdirSync, readFileSync } from "node:fs";
|
||||
import { basename, extname, join } from "node:path";
|
||||
import { stripUtf8Bom } from "@cline/shared";
|
||||
import { resolveAgentConfigSearchPaths } from "@cline/shared/storage";
|
||||
import YAML from "yaml";
|
||||
import { z } from "zod";
|
||||
@@ -40,6 +41,11 @@ function splitFrontmatter(content: string): {
|
||||
frontmatter: string;
|
||||
body: string;
|
||||
} {
|
||||
// Strip a leading UTF-8 BOM (e.g. added by Windows Notepad's "UTF-8 with BOM" encoding),
|
||||
// which Node's `utf-8` decoding does not strip on its own. Without this the frontmatter
|
||||
// match below never matches a file that starts with "\uFEFF---" (see cline/cline#12151).
|
||||
content = stripUtf8Bom(content);
|
||||
|
||||
const firstLineMatch = content.match(/^(---)[^\S\r\n]*(?:\r?\n|$)/);
|
||||
if (!firstLineMatch) {
|
||||
throw new Error("Missing YAML frontmatter block in agent config file.");
|
||||
|
||||
@@ -13,6 +13,7 @@ import type {
|
||||
ApplyPatchInput,
|
||||
EditFileInput,
|
||||
ReadFileRequest,
|
||||
ScheduleTaskInput,
|
||||
StructuredCommandInput,
|
||||
} from "./schemas";
|
||||
|
||||
@@ -192,6 +193,23 @@ export type VerifySubmitExecutor = (
|
||||
context: AgentToolContext,
|
||||
) => Promise<string>;
|
||||
|
||||
/**
|
||||
* Executor for creating a scheduled (recurring) task
|
||||
*
|
||||
* The executor closes over a schedule client (and, when the session is
|
||||
* connector-backed, the current thread's delivery descriptor). It is only
|
||||
* injected for hosts that can reach a schedule service, which is why
|
||||
* `schedule_task` only appears when this executor is provided.
|
||||
*
|
||||
* @param input - Validated schedule_task input
|
||||
* @param context - Tool execution context (carries the origin `sessionId`)
|
||||
* @returns A human-readable confirmation string for the model
|
||||
*/
|
||||
export type ScheduleTaskExecutor = (
|
||||
input: ScheduleTaskInput,
|
||||
context: AgentToolContext,
|
||||
) => Promise<string>;
|
||||
|
||||
/**
|
||||
* Collection of all tool executors
|
||||
*/
|
||||
@@ -214,6 +232,8 @@ export interface ToolExecutors {
|
||||
askQuestion?: AskQuestionExecutor;
|
||||
/** Final submission implementation */
|
||||
submit?: VerifySubmitExecutor;
|
||||
/** Scheduled-task creation implementation */
|
||||
scheduleTask?: ScheduleTaskExecutor;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -232,7 +252,8 @@ export type DefaultToolName =
|
||||
| "editor"
|
||||
| "skills"
|
||||
| "ask_question"
|
||||
| "submit_and_exit";
|
||||
| "submit_and_exit"
|
||||
| "schedule_task";
|
||||
|
||||
/**
|
||||
* Configuration for enabling/disabling default tools
|
||||
@@ -292,19 +313,18 @@ export interface DefaultToolsConfig {
|
||||
*/
|
||||
enableSubmitAndExit?: boolean;
|
||||
|
||||
/**
|
||||
* Enable the schedule_task tool. Only takes effect when a `scheduleTask`
|
||||
* executor is also provided (it requires a schedule client the host injects).
|
||||
* @default true
|
||||
*/
|
||||
enableScheduleTask?: boolean;
|
||||
|
||||
/**
|
||||
* Current working directory for tools that need it
|
||||
*/
|
||||
cwd?: string;
|
||||
|
||||
/**
|
||||
* Shell executable (name or full path) the run_commands executor will use.
|
||||
* The tool description tells the model which shell syntax to write, so this
|
||||
* must match the shell configured on the executor.
|
||||
* @default getDefaultShell(process.platform) — "/bin/bash" on Unix, "powershell" on Windows
|
||||
*/
|
||||
shell?: string;
|
||||
|
||||
/**
|
||||
* Timeout for file read operations in milliseconds
|
||||
* @default 10000
|
||||
@@ -352,6 +372,12 @@ export interface DefaultToolsConfig {
|
||||
* @default 15000
|
||||
*/
|
||||
submitTimeoutMs?: number;
|
||||
|
||||
/**
|
||||
* Timeout for schedule_task operations in milliseconds
|
||||
* @default 15000
|
||||
*/
|
||||
scheduleTaskTimeoutMs?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,12 +3,15 @@ import type {
|
||||
HubCommandEnvelope,
|
||||
HubEventEnvelope,
|
||||
HubReplyEnvelope,
|
||||
HubScheduleCreateInput,
|
||||
ToolApprovalRequest,
|
||||
} from "@cline/shared";
|
||||
import { captureSdkError, createSessionId } from "@cline/shared";
|
||||
import { deliverScheduleResultToOriginSession } from "../../cron/delivery/origin-session-delivery";
|
||||
import { CronService } from "../../cron/service/cron-service";
|
||||
import { HubScheduleCommandService } from "../../cron/service/schedule-command-service";
|
||||
import { HubScheduleService } from "../../cron/service/schedule-service";
|
||||
import { createScheduleTaskExecutor } from "../../extensions/tools";
|
||||
import { LocalRuntimeHost } from "../../runtime/host/local-runtime-host";
|
||||
import type {
|
||||
PendingPromptsRuntimeService,
|
||||
@@ -184,13 +187,78 @@ export class HubServerTransport implements NativeHubTransport {
|
||||
private readonly ctx: HubTransportContext;
|
||||
|
||||
constructor(readonly options: HubWebSocketServerOptions) {
|
||||
// The schedule_task tool executor runs inside hub-hosted agent sessions.
|
||||
// It reaches this hub's own HubScheduleService (assigned later in this
|
||||
// constructor) via a lazy reference and resolves workspaceRoot/cwd from
|
||||
// the origin session when the agent omits them.
|
||||
const sessionHostRef: {
|
||||
current?: RuntimeHost & Partial<PendingPromptsRuntimeService>;
|
||||
} = {};
|
||||
const scheduleTaskExecutor = createScheduleTaskExecutor({
|
||||
client: {
|
||||
createSchedule: async (input) => {
|
||||
let workspaceRoot = input.workspaceRoot?.trim();
|
||||
let cwd = input.cwd?.trim();
|
||||
const originSessionId = input.originSessionId?.trim();
|
||||
const metadata: Record<string, unknown> = {
|
||||
...(input.metadata ?? {}),
|
||||
};
|
||||
const needsConnectorDelivery =
|
||||
metadata.deliveryMode === "connector" && !metadata.delivery;
|
||||
if (
|
||||
(!workspaceRoot || !cwd || needsConnectorDelivery) &&
|
||||
originSessionId
|
||||
) {
|
||||
const originSession = await sessionHostRef.current
|
||||
?.getSession(originSessionId)
|
||||
.catch(() => undefined);
|
||||
workspaceRoot = workspaceRoot || originSession?.workspaceRoot;
|
||||
cwd = cwd || originSession?.cwd;
|
||||
if (needsConnectorDelivery) {
|
||||
const delivery = originSession?.metadata?.delivery;
|
||||
if (delivery && typeof delivery === "object") {
|
||||
metadata.delivery = delivery;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (metadata.deliveryMode === "connector" && !metadata.delivery) {
|
||||
throw new Error(
|
||||
"schedule_task deliverTo='connector' is only available inside a connector-backed session (no thread delivery target found).",
|
||||
);
|
||||
}
|
||||
if (!workspaceRoot) {
|
||||
throw new Error(
|
||||
"schedule_task could not resolve a workspaceRoot for the scheduled run.",
|
||||
);
|
||||
}
|
||||
const created = this.schedules.createSchedule({
|
||||
name: input.name,
|
||||
cronPattern: input.cronPattern,
|
||||
prompt: input.prompt,
|
||||
workspaceRoot,
|
||||
cwd,
|
||||
mode: input.mode,
|
||||
createdBy: input.createdBy,
|
||||
metadata: metadata as HubScheduleCreateInput["metadata"],
|
||||
});
|
||||
return {
|
||||
scheduleId: created.scheduleId,
|
||||
nextRunAt: created.nextRunAt,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
this.sessionHost =
|
||||
options.sessionHost ??
|
||||
new LocalRuntimeHost({
|
||||
sessionService: new CoreSessionService(new SqliteSessionStore()),
|
||||
fetch: options.fetch,
|
||||
telemetry: options.telemetry,
|
||||
capabilities: {
|
||||
toolExecutors: { scheduleTask: scheduleTaskExecutor },
|
||||
},
|
||||
});
|
||||
sessionHostRef.current = this.sessionHost;
|
||||
this.ctx = {
|
||||
clients: this.clients,
|
||||
sessionState: this.sessionState,
|
||||
@@ -239,6 +307,41 @@ export class HubServerTransport implements NativeHubTransport {
|
||||
: undefined,
|
||||
),
|
||||
);
|
||||
// For agent-created schedules with deliverTo:"origin_session",
|
||||
// feed the run's result back into the originating session as a
|
||||
// queued follow-up turn (best-effort; skipped if not active).
|
||||
const record =
|
||||
payload && typeof payload === "object"
|
||||
? (payload as Record<string, unknown>)
|
||||
: undefined;
|
||||
if (record?.deliveryMode === "origin_session") {
|
||||
const originSessionId =
|
||||
typeof record.originSessionId === "string"
|
||||
? record.originSessionId
|
||||
: undefined;
|
||||
if (originSessionId) {
|
||||
void deliverScheduleResultToOriginSession({
|
||||
host: this.sessionHost,
|
||||
originSessionId,
|
||||
runSessionId:
|
||||
typeof record.sessionId === "string"
|
||||
? record.sessionId
|
||||
: undefined,
|
||||
scheduleId:
|
||||
typeof record.scheduleId === "string"
|
||||
? record.scheduleId
|
||||
: "unknown",
|
||||
status:
|
||||
typeof record.status === "string" ? record.status : "unknown",
|
||||
errorMessage:
|
||||
typeof record.errorMessage === "string"
|
||||
? record.errorMessage
|
||||
: undefined,
|
||||
}).catch(() => {
|
||||
// Best-effort delivery.
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
this.scheduleCommands = new HubScheduleCommandService(this.schedules);
|
||||
|
||||
@@ -112,6 +112,7 @@ export {
|
||||
parseUserCommandEnvelope,
|
||||
registerDisposable,
|
||||
SDK_ERROR_TELEMETRY_EVENT,
|
||||
stripUtf8Bom,
|
||||
} from "@cline/shared";
|
||||
export * from "@cline/shared/storage";
|
||||
export {
|
||||
@@ -136,11 +137,6 @@ export {
|
||||
type UserRemoteConfigOrganization,
|
||||
type UserRemoteConfigResponse,
|
||||
} from "./account";
|
||||
export {
|
||||
hashSecret,
|
||||
setSdkLogger,
|
||||
sdkDebug,
|
||||
} from "./logging/early-logger";
|
||||
export {
|
||||
createOAuthClientCallbacks,
|
||||
type OAuthClientCallbacksOptions,
|
||||
@@ -406,6 +402,11 @@ export type {
|
||||
export * from "./hub";
|
||||
export { HubRuntimeHost } from "./hub/runtime-host/hub-runtime-host";
|
||||
export { RemoteRuntimeHost } from "./hub/runtime-host/remote-runtime-host";
|
||||
export {
|
||||
hashSecret,
|
||||
sdkDebug,
|
||||
setSdkLogger,
|
||||
} from "./logging/early-logger";
|
||||
export {
|
||||
buildRemoteConfigSessionBlobUploadMetadata,
|
||||
createRemoteConfigSessionMessagesArtifactUploader,
|
||||
@@ -651,6 +652,7 @@ export {
|
||||
captureMentionFailed,
|
||||
captureMentionSearchResults,
|
||||
captureMentionUsed,
|
||||
captureMistakeLimitReached,
|
||||
captureModeSwitch,
|
||||
captureProviderApiError,
|
||||
captureProviderConfigured,
|
||||
|
||||
@@ -2189,6 +2189,61 @@ describe("SessionRuntime.run — tracker wiring (P1 #3)", () => {
|
||||
expect(abortCalls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("captures task.mistake_limit_reached telemetry exactly once when the limit is hit", async () => {
|
||||
const capture = vi.fn();
|
||||
const telemetry = {
|
||||
capture,
|
||||
captureRequired: vi.fn(),
|
||||
setDistinctId: vi.fn(),
|
||||
setMetadata: vi.fn(),
|
||||
updateMetadata: vi.fn(),
|
||||
setCommonProperties: vi.fn(),
|
||||
updateCommonProperties: vi.fn(),
|
||||
isEnabled: vi.fn(() => true),
|
||||
recordCounter: vi.fn(),
|
||||
recordHistogram: vi.fn(),
|
||||
recordGauge: vi.fn(),
|
||||
flush: vi.fn(async () => {}),
|
||||
dispose: vi.fn(async () => {}),
|
||||
};
|
||||
const { deps } = makeScriptedRuntime({
|
||||
events: failedToolTurnEvents(),
|
||||
});
|
||||
const session = new SessionRuntime(
|
||||
makeAgentConfig({
|
||||
execution: { maxConsecutiveMistakes: 2 },
|
||||
sessionId: "sess_mistakes",
|
||||
telemetry,
|
||||
}),
|
||||
deps,
|
||||
);
|
||||
|
||||
await session.run("one");
|
||||
// First failed turn — counter 1 < 2, no telemetry yet.
|
||||
const limitEvents = () =>
|
||||
capture.mock.calls
|
||||
.map((call) => call[0])
|
||||
.filter((event) => event.event === "task.mistake_limit_reached");
|
||||
expect(limitEvents()).toHaveLength(0);
|
||||
|
||||
await session.continue("two");
|
||||
// Second failed turn hits the limit: exactly one event, even though
|
||||
// no `onConsecutiveMistakeLimitReached` callback is configured (the
|
||||
// tracker falls back to the default stop decision).
|
||||
const events = limitEvents();
|
||||
expect(events).toHaveLength(1);
|
||||
expect(events[0].properties).toMatchObject({
|
||||
ulid: "sess_mistakes",
|
||||
model: "claude-3-5-sonnet",
|
||||
provider: "anthropic",
|
||||
reason: "tool_execution_failed",
|
||||
consecutiveMistakes: 2,
|
||||
maxConsecutiveMistakes: 2,
|
||||
isSubagent: false,
|
||||
});
|
||||
expect(events[0].properties.agentId).toMatch(/^agent_/);
|
||||
});
|
||||
|
||||
it("aborts on hard-threshold loop detection of identical tool calls", async () => {
|
||||
const identical = (i: number): AgentRuntimeEvent => ({
|
||||
type: "tool-started",
|
||||
|
||||
@@ -52,6 +52,7 @@ import {
|
||||
createAgentModelFromConfig,
|
||||
resolveKnownModelsFromConfig,
|
||||
} from "../../services/llms/handler-factory";
|
||||
import { captureMistakeLimitReached } from "../../services/telemetry/core-events";
|
||||
import { CLINE_INTERNAL_TELEMETRY_METADATA_KEY } from "../../services/telemetry/tool-context";
|
||||
import {
|
||||
getMessageBuilderOptionsFromEnv,
|
||||
@@ -276,10 +277,10 @@ export class SessionRuntime {
|
||||
private readonly agentId: string;
|
||||
private readonly parentAgentId?: string;
|
||||
private readonly logger?: BasicLogger;
|
||||
// Reserved for §3.4.4 telemetry parity (not yet consumed — §3.4.4
|
||||
// listed as explicitly deferred until telemetry wiring is added).
|
||||
// Typed as `readonly` to preserve the field slot for future use
|
||||
// without re-touching the constructor.
|
||||
// §3.4.4 telemetry parity. Currently consumed by the MistakeTracker's
|
||||
// `onLimitTelemetry` hook (task.mistake_limit_reached); most other
|
||||
// runtime telemetry is emitted host-side from the agent event stream
|
||||
// (services/agent-events.ts).
|
||||
readonly telemetry?: ITelemetryService;
|
||||
private readonly conversation: ConversationStore;
|
||||
private readonly mistakeTracker: MistakeTracker;
|
||||
@@ -401,6 +402,22 @@ export class SessionRuntime {
|
||||
this.mistakeTracker = new MistakeTracker({
|
||||
maxConsecutiveMistakes: maxMistakes,
|
||||
onLimitReached: config.onConsecutiveMistakeLimitReached,
|
||||
onLimitTelemetry: (context) => {
|
||||
// Read connection fields from `this.config` at fire time so a
|
||||
// mid-session `updateConnection` is reflected in the event.
|
||||
captureMistakeLimitReached(this.telemetry, {
|
||||
ulid: this.config.sessionId ?? this.conversation.getConversationId(),
|
||||
model: this.config.modelId,
|
||||
provider: this.config.providerId,
|
||||
reason: context.reason,
|
||||
consecutiveMistakes: context.consecutiveMistakes,
|
||||
maxConsecutiveMistakes: context.maxConsecutiveMistakes,
|
||||
agentId: this.agentId,
|
||||
conversationId: this.conversation.getConversationId(),
|
||||
parentAgentId: this.parentAgentId,
|
||||
isSubagent: Boolean(this.parentAgentId),
|
||||
});
|
||||
},
|
||||
emit: (event) => this.emitLegacyEvent(event),
|
||||
log: (level, message, metadata) =>
|
||||
leveledLog(this.logger, level, message, metadata),
|
||||
|
||||
@@ -60,6 +60,12 @@ export interface MistakeTrackerOptions {
|
||||
) =>
|
||||
| Promise<ConsecutiveMistakeLimitDecision>
|
||||
| ConsecutiveMistakeLimitDecision;
|
||||
/**
|
||||
* Observability hook fired exactly once per limit hit, right before the
|
||||
* limit decision is resolved — regardless of whether `onLimitReached` is
|
||||
* configured or what it decides. Used for telemetry.
|
||||
*/
|
||||
readonly onLimitTelemetry?: (ctx: ConsecutiveMistakeLimitContext) => void;
|
||||
readonly emit: (event: AgentEvent) => void;
|
||||
readonly log: LeveledLog;
|
||||
readonly agentId: string;
|
||||
@@ -107,14 +113,16 @@ export class MistakeTracker {
|
||||
return { action: "continue" };
|
||||
}
|
||||
|
||||
const limitContext: ConsecutiveMistakeLimitContext = {
|
||||
iteration: input.iteration,
|
||||
consecutiveMistakes: next,
|
||||
maxConsecutiveMistakes: max,
|
||||
reason: input.reason,
|
||||
details: input.details,
|
||||
};
|
||||
this.options.onLimitTelemetry?.(limitContext);
|
||||
const decision = await resolveConsecutiveMistakeDecision(
|
||||
{
|
||||
iteration: input.iteration,
|
||||
consecutiveMistakes: next,
|
||||
maxConsecutiveMistakes: max,
|
||||
reason: input.reason,
|
||||
details: input.details,
|
||||
},
|
||||
limitContext,
|
||||
this.options.onLimitReached,
|
||||
);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
import type * as LlmsProviders from "@cline/llms";
|
||||
import type { AgentConfig, AgentEvent, AgentResult } from "@cline/shared";
|
||||
import { normalizeUserInput, stripRuntimeNotices } from "@cline/shared";
|
||||
import { normalizeUserInput, stripModeNotices } from "@cline/shared";
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
parseSubSessionId,
|
||||
@@ -235,9 +235,7 @@ export function deriveTitleFromPrompt(
|
||||
// stripped here rather than inside normalizeUserInput -- that function also
|
||||
// sanitizes model-bound prompts (prepareTurnInput), where the notice must
|
||||
// survive to reach the model.
|
||||
const normalized = stripRuntimeNotices(
|
||||
normalizeUserInput(prompt ?? ""),
|
||||
).trim();
|
||||
const normalized = stripModeNotices(normalizeUserInput(prompt ?? "")).trim();
|
||||
if (!normalized) return undefined;
|
||||
return normalizeTitle(normalized.split("\n")[0]?.trim());
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
captureCompactionExecuted,
|
||||
captureCompactionSkipped,
|
||||
captureExtensionActivated,
|
||||
captureMistakeLimitReached,
|
||||
captureProviderConfigured,
|
||||
captureRunCommandsTimeout,
|
||||
captureTelemetryOptOut,
|
||||
@@ -270,6 +271,35 @@ describe("captureWorkspacePathResolved", () => {
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("captureMistakeLimitReached", () => {
|
||||
const baseProps = {
|
||||
ulid: "sess-1",
|
||||
model: "claude-3-5-sonnet",
|
||||
provider: "anthropic",
|
||||
reason: "tool_execution_failed",
|
||||
consecutiveMistakes: 3,
|
||||
maxConsecutiveMistakes: 3,
|
||||
};
|
||||
|
||||
test("emits task.mistake_limit_reached with limit context and a timestamp", () => {
|
||||
const stub = createTelemetryStub();
|
||||
captureMistakeLimitReached(stub.telemetry, baseProps);
|
||||
expect(stub.capture).toHaveBeenCalledTimes(1);
|
||||
expect(stub.captureRequired).not.toHaveBeenCalled();
|
||||
const { event, properties } = captureCallAt(stub, 0);
|
||||
expect(event).toBe("task.mistake_limit_reached");
|
||||
expect(properties).toMatchObject(baseProps);
|
||||
expect(typeof properties?.timestamp).toBe("string");
|
||||
});
|
||||
|
||||
test("no-ops when telemetry is undefined", () => {
|
||||
expect(() =>
|
||||
captureMistakeLimitReached(undefined, baseProps),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("captureCompactionExecuted", () => {
|
||||
const baseProps = {
|
||||
ulid: "ulid-1",
|
||||
|
||||
@@ -63,6 +63,7 @@ export const CORE_TELEMETRY_EVENTS = {
|
||||
SKILL_USED: "task.skill_used",
|
||||
DIFF_EDIT_FAILED: "task.diff_edit_failed",
|
||||
PROVIDER_API_ERROR: "task.provider_api_error",
|
||||
MISTAKE_LIMIT_REACHED: "task.mistake_limit_reached",
|
||||
MENTION_USED: "task.mention_used",
|
||||
MENTION_FAILED: "task.mention_failed",
|
||||
MENTION_SEARCH_RESULTS: "task.mention_search_results",
|
||||
@@ -490,6 +491,28 @@ export function captureProviderApiError(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Records when the consecutive mistake limit is reached, right before the
|
||||
* limit decision (host prompt / auto-stop) is resolved.
|
||||
*/
|
||||
export function captureMistakeLimitReached(
|
||||
telemetry: ITelemetryService | undefined,
|
||||
properties: {
|
||||
ulid: string;
|
||||
model: string;
|
||||
provider?: string;
|
||||
/** What kind of mistake tripped the limit. */
|
||||
reason: string;
|
||||
consecutiveMistakes: number;
|
||||
maxConsecutiveMistakes: number;
|
||||
} & Partial<TelemetryAgentIdentityProperties>,
|
||||
): void {
|
||||
emit(telemetry, CORE_TELEMETRY_EVENTS.TASK.MISTAKE_LIMIT_REACHED, {
|
||||
...properties,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
export function captureRunCommandsTimeout(
|
||||
telemetry: ITelemetryService | undefined,
|
||||
properties: RunCommandsTimeoutTelemetryProperties,
|
||||
|
||||
@@ -45,6 +45,7 @@ export const SessionSource = {
|
||||
IDE: "ide",
|
||||
JETBRAINS: "jetbrains",
|
||||
NEOVIM: "neovim",
|
||||
SCHEDULE: "schedule",
|
||||
UNKNOWN: "unknown",
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cline/llms",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"description": "Config-driven SDK for selecting, extending, and instantiating LLM providers and models",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -77,13 +77,16 @@ while generating the catalog. Conceptually:
|
||||
safeOutputTokens = min(
|
||||
modelReportedMaxOutput,
|
||||
contextWindow - estimatedPromptTokens - reserveTokens,
|
||||
userConfiguredOutputCap,
|
||||
userConfiguredOutputCap or productDefaultOutputCap,
|
||||
)
|
||||
```
|
||||
|
||||
The SDK gateway only sends an output token limit when the caller provides
|
||||
`request.options.maxTokens` or an equivalent host configuration. Catalog
|
||||
metadata does not become a request parameter by itself.
|
||||
The SDK gateway resolves an output token limit for the provider request. It uses
|
||||
`request.options.maxTokens` or an equivalent host configuration when present,
|
||||
otherwise it applies the product default output cap
|
||||
(`DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS`, currently 32000) when the model catalog has
|
||||
either an output limit or a context window. Provider modules are responsible for
|
||||
forwarding that limit only to wire API surfaces that support it.
|
||||
|
||||
The exact request-limit policy belongs in the provider/gateway/core request
|
||||
path, not in generated catalog data.
|
||||
@@ -161,5 +164,5 @@ and observable.
|
||||
- `catalog-live.test.ts`: tests catalog normalization behavior.
|
||||
- `catalog.generated.ts`: checked-in generated provider/model catalog.
|
||||
- `../../scripts/generate-models.ts`: writes generated catalog output.
|
||||
- `../providers/ai-sdk.ts`: passes `maxOutputTokens` into AI SDK.
|
||||
- `../providers/ai-sdk.ts`: conditionally passes `maxOutputTokens` into AI SDK.
|
||||
- `../providers/gateway.ts`: resolves per-request/default `maxTokens`.
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
parseJsonStream,
|
||||
sanitizeSurrogates,
|
||||
} from "@cline/shared";
|
||||
import { jsonSchema, NoSuchToolError, streamText } from "ai";
|
||||
import { type CallSettings, jsonSchema, NoSuchToolError, streamText } from "ai";
|
||||
import { nanoid } from "nanoid";
|
||||
import { extractErrorMessage } from "./format";
|
||||
import {
|
||||
@@ -53,6 +53,18 @@ interface GatewayNormalizedUsage {
|
||||
}
|
||||
type ProviderModuleKind = AiSdkProviderOptionsTarget;
|
||||
|
||||
export function buildAiSdkStreamConfig(
|
||||
request: GatewayStreamRequest,
|
||||
_context: GatewayProviderContext,
|
||||
): Partial<CallSettings> {
|
||||
return {
|
||||
...(request.maxTokens !== undefined
|
||||
? { maxOutputTokens: request.maxTokens }
|
||||
: {}),
|
||||
temperature: request.temperature,
|
||||
};
|
||||
}
|
||||
|
||||
function buildCachedAiSdkMessages(
|
||||
request: GatewayStreamRequest,
|
||||
context: GatewayProviderContext,
|
||||
@@ -352,10 +364,15 @@ function toAiSdkMessages(
|
||||
}
|
||||
}
|
||||
|
||||
// A message left empty only because its reasoning was dropped is
|
||||
// omitted entirely instead of forwarded as an empty turn.
|
||||
const emptiedByDroppedReasoning = !includeReasoning && skippedReasoning;
|
||||
if (content.length > 0) {
|
||||
normalizedMessages.push({ role: message.role, content });
|
||||
} else if (!includeReasoning && skippedReasoning) {
|
||||
} else if (message.role === "user" || message.role === "assistant") {
|
||||
} else if (
|
||||
!emptiedByDroppedReasoning &&
|
||||
(message.role === "user" || message.role === "assistant")
|
||||
) {
|
||||
normalizedMessages.push({ role: message.role, content: "" });
|
||||
}
|
||||
}
|
||||
@@ -1178,6 +1195,9 @@ function createAiSdkProvider(kind: ProviderModuleKind): GatewayProviderFactory {
|
||||
context,
|
||||
kind,
|
||||
) as never;
|
||||
const requestConfig = provider.buildStreamConfig
|
||||
? provider.buildStreamConfig(request, context)
|
||||
: buildAiSdkStreamConfig(request, context);
|
||||
recordProviderRequestCapture({
|
||||
stage: "ai_sdk_prompt",
|
||||
request,
|
||||
@@ -1186,8 +1206,7 @@ function createAiSdkProvider(kind: ProviderModuleKind): GatewayProviderFactory {
|
||||
...(useSystemOption ? { system: systemPrompt } : {}),
|
||||
tools,
|
||||
providerOptions,
|
||||
maxOutputTokens: request.maxTokens,
|
||||
temperature: request.temperature,
|
||||
...requestConfig,
|
||||
},
|
||||
});
|
||||
stream = streamText({
|
||||
@@ -1195,16 +1214,13 @@ function createAiSdkProvider(kind: ProviderModuleKind): GatewayProviderFactory {
|
||||
messages: messages as never,
|
||||
...(useSystemOption ? { system: systemPrompt } : {}),
|
||||
tools: tools as never,
|
||||
temperature: request.temperature,
|
||||
...(request.maxTokens !== undefined
|
||||
? { maxOutputTokens: request.maxTokens }
|
||||
: {}),
|
||||
abortSignal: request.signal,
|
||||
experimental_repairToolCall: repairMalformedToolCall as never,
|
||||
experimental_telemetry: {
|
||||
isEnabled: langfuse,
|
||||
},
|
||||
providerOptions,
|
||||
...requestConfig,
|
||||
onError: ({ error: streamError }) => {
|
||||
const msg = extractErrorMessage(streamError);
|
||||
capturedError.current = msg;
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
toGatewayRequestMessages,
|
||||
} from "./compat";
|
||||
import { ClineNotSubscribedError } from "./errors";
|
||||
import { DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS } from "./gateway";
|
||||
import type { Message } from "./types";
|
||||
|
||||
const streamTextSpy = vi.fn();
|
||||
@@ -361,7 +362,7 @@ describe("createGatewayApiHandler.createMessage", () => {
|
||||
openaiCompatibleSpy.mockClear();
|
||||
});
|
||||
|
||||
it("does not convert catalog maxTokens into request maxOutputTokens", async () => {
|
||||
it("uses the default maxOutputTokens without expanding to catalog maxTokens", async () => {
|
||||
streamTextSpy.mockReturnValue({
|
||||
fullStream: (async function* () {
|
||||
yield { type: "finish", finishReason: "stop" };
|
||||
@@ -395,7 +396,10 @@ describe("createGatewayApiHandler.createMessage", () => {
|
||||
const call = streamTextSpy.mock.calls.at(-1)?.[0] as
|
||||
| { maxOutputTokens?: unknown }
|
||||
| undefined;
|
||||
expect(call).not.toHaveProperty("maxOutputTokens");
|
||||
expect(call).toHaveProperty(
|
||||
"maxOutputTokens",
|
||||
DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS,
|
||||
);
|
||||
});
|
||||
|
||||
it("sends configured OpenAI-compatible maxOutputTokens to the provider request", async () => {
|
||||
|
||||
@@ -15,7 +15,11 @@ import {
|
||||
} from "@cline/shared";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { normalizeModelsDevProviderModels } from "../catalog/catalog-live";
|
||||
import { createGateway, resolveGatewayRequestMaxTokens } from "./gateway";
|
||||
import {
|
||||
createGateway,
|
||||
DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS,
|
||||
resolveGatewayRequestMaxTokens,
|
||||
} from "./gateway";
|
||||
|
||||
const streamTextSpy = vi.fn();
|
||||
const openaiCompatibleFactorySpy = vi.fn();
|
||||
@@ -218,14 +222,46 @@ describe("sdk-gateway", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("does not synthesize request max tokens from catalog metadata", () => {
|
||||
it("uses the old default output cap when request max tokens are omitted", () => {
|
||||
expect(
|
||||
resolveGatewayRequestMaxTokens({
|
||||
requestedMaxTokens: undefined,
|
||||
model: { maxOutputTokens: 202_800, contextWindow: 202_800 },
|
||||
estimatedInputTokens: 1_000,
|
||||
}),
|
||||
).toBeUndefined();
|
||||
).toBe(DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS);
|
||||
});
|
||||
|
||||
it("lifts the default output cap above an explicit reasoning budget", () => {
|
||||
expect(
|
||||
resolveGatewayRequestMaxTokens({
|
||||
requestedMaxTokens: undefined,
|
||||
reasoningBudgetTokens: 50_000,
|
||||
model: { maxOutputTokens: 202_800, contextWindow: 202_800 },
|
||||
estimatedInputTokens: 1_000,
|
||||
outputReserveTokens: 1_024,
|
||||
}),
|
||||
).toBe(51_024);
|
||||
|
||||
// Still clamped by the model's max output tokens.
|
||||
expect(
|
||||
resolveGatewayRequestMaxTokens({
|
||||
requestedMaxTokens: undefined,
|
||||
reasoningBudgetTokens: 50_000,
|
||||
model: { maxOutputTokens: 40_000, contextWindow: 202_800 },
|
||||
estimatedInputTokens: 1_000,
|
||||
}),
|
||||
).toBe(40_000);
|
||||
|
||||
// Explicit request max tokens still win over the reasoning floor.
|
||||
expect(
|
||||
resolveGatewayRequestMaxTokens({
|
||||
requestedMaxTokens: 8_192,
|
||||
reasoningBudgetTokens: 50_000,
|
||||
model: { maxOutputTokens: 202_800, contextWindow: 202_800 },
|
||||
estimatedInputTokens: 1_000,
|
||||
}),
|
||||
).toBe(8_192);
|
||||
});
|
||||
|
||||
it("resolves explicit request max tokens from model and context caps", () => {
|
||||
@@ -290,10 +326,10 @@ describe("sdk-gateway", () => {
|
||||
expect(estimatedTokens).toBeGreaterThan(4_000);
|
||||
});
|
||||
|
||||
it("does not apply catalog output caps when the request omits max tokens", async () => {
|
||||
it("applies the old default output cap when the request omits max tokens", async () => {
|
||||
const createProvider = vi.fn(() => ({
|
||||
async *stream(request: { maxTokens?: number }) {
|
||||
expect(request.maxTokens).toBeUndefined();
|
||||
expect(request.maxTokens).toBe(DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS);
|
||||
yield { type: "finish", reason: "stop" } satisfies AgentModelEvent;
|
||||
},
|
||||
}));
|
||||
@@ -582,6 +618,41 @@ describe("sdk-gateway", () => {
|
||||
}),
|
||||
});
|
||||
expect(events.at(-1)).toEqual({ type: "finish", reason: "tool-calls" });
|
||||
const call = streamTextSpy.mock.calls.at(-1)?.[0] as
|
||||
| { maxOutputTokens?: unknown }
|
||||
| undefined;
|
||||
expect(call).not.toHaveProperty("maxOutputTokens");
|
||||
});
|
||||
|
||||
it("sends explicit maxOutputTokens through the OpenAI Responses provider", async () => {
|
||||
streamTextSpy.mockReturnValue({
|
||||
fullStream: makeStreamParts([
|
||||
{ type: "finish", usage: { inputTokens: 1, outputTokens: 1 } },
|
||||
]),
|
||||
});
|
||||
|
||||
const gateway = createGateway({
|
||||
providerConfigs: [
|
||||
{
|
||||
providerId: "openai-native",
|
||||
apiKey: "test",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await collect(
|
||||
await gateway.stream({
|
||||
providerId: "openai-native",
|
||||
modelId: "gpt-5-mini",
|
||||
messages: baseMessages,
|
||||
maxTokens: 8_192,
|
||||
}),
|
||||
);
|
||||
|
||||
const call = streamTextSpy.mock.calls.at(-1)?.[0] as
|
||||
| { maxOutputTokens?: unknown }
|
||||
| undefined;
|
||||
expect(call?.maxOutputTokens).toBe(8_192);
|
||||
});
|
||||
|
||||
it("surfaces nested AI SDK stream errors as human-readable finish messages", async () => {
|
||||
@@ -2249,6 +2320,32 @@ describe("sdk-gateway", () => {
|
||||
expect(call).not.toHaveProperty("maxOutputTokens");
|
||||
});
|
||||
|
||||
it("does not send explicit maxOutputTokens to ChatGPT OAuth", async () => {
|
||||
streamTextSpy.mockReturnValue({
|
||||
fullStream: makeStreamParts([
|
||||
{ type: "finish", usage: { inputTokens: 1, outputTokens: 1 } },
|
||||
]),
|
||||
});
|
||||
|
||||
const gateway = createGateway({
|
||||
providerConfigs: [{ providerId: "openai-codex" }],
|
||||
});
|
||||
|
||||
await collect(
|
||||
await gateway.stream({
|
||||
providerId: "openai-codex",
|
||||
modelId: "gpt-5.4",
|
||||
messages: baseMessages,
|
||||
maxTokens: 8_192,
|
||||
}),
|
||||
);
|
||||
|
||||
const call = streamTextSpy.mock.calls.at(-1)?.[0] as
|
||||
| { maxOutputTokens?: unknown }
|
||||
| undefined;
|
||||
expect(call).not.toHaveProperty("maxOutputTokens");
|
||||
});
|
||||
|
||||
it("passes Codex instructions through provider options and removes the system message from messages", async () => {
|
||||
streamTextSpy.mockReturnValue({
|
||||
fullStream: makeStreamParts([
|
||||
@@ -3496,7 +3593,7 @@ describe("sdk-gateway", () => {
|
||||
reasoning: { enabled: true },
|
||||
}),
|
||||
openrouter: expect.objectContaining({
|
||||
reasoning: { enabled: true },
|
||||
reasoning: { enabled: true, max_tokens: 19_200 },
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -15,9 +15,11 @@ import { estimateRequestInputTokens } from "@cline/shared";
|
||||
import { toAsyncIterable } from "./async";
|
||||
import { BUILTIN_PROVIDER_REGISTRATIONS } from "./builtins-runtime";
|
||||
import { GatewayRegistry } from "./registry";
|
||||
import { isPositiveFiniteNumber } from "./utils";
|
||||
|
||||
export type * from "@cline/shared";
|
||||
|
||||
export const DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS = 32_000;
|
||||
const GATEWAY_OUTPUT_RESERVE_TOKENS = 1_024;
|
||||
|
||||
function mergeRequestMetadata(
|
||||
@@ -115,27 +117,42 @@ class GatewayModelAdapter implements AgentModel {
|
||||
}
|
||||
}
|
||||
|
||||
function isPositiveFiniteNumber(value: unknown): value is number {
|
||||
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
||||
}
|
||||
|
||||
export function resolveGatewayRequestMaxTokens(input: {
|
||||
requestedMaxTokens?: number;
|
||||
model: Pick<GatewayModelDefinition, "contextWindow" | "maxOutputTokens">;
|
||||
estimatedInputTokens: number;
|
||||
defaultMaxOutputTokens?: number;
|
||||
outputReserveTokens?: number;
|
||||
reasoningBudgetTokens?: number;
|
||||
onContextOverflow?: (details: {
|
||||
contextWindow: number;
|
||||
estimatedInputTokens: number;
|
||||
reserveTokens: number;
|
||||
}) => void;
|
||||
}): number | undefined {
|
||||
if (!isPositiveFiniteNumber(input.requestedMaxTokens)) {
|
||||
return undefined;
|
||||
const caps: number[] = [];
|
||||
if (isPositiveFiniteNumber(input.requestedMaxTokens)) {
|
||||
caps.push(Math.floor(input.requestedMaxTokens));
|
||||
} else {
|
||||
// Providers like Anthropic require max_tokens to exceed the thinking
|
||||
// budget, so an explicit reasoning budget lifts the synthesized default
|
||||
// (still clamped by model max output and remaining context below).
|
||||
const reasoningFloor = isPositiveFiniteNumber(input.reasoningBudgetTokens)
|
||||
? Math.floor(input.reasoningBudgetTokens) +
|
||||
(input.outputReserveTokens ?? GATEWAY_OUTPUT_RESERVE_TOKENS)
|
||||
: 0;
|
||||
const defaultMaxOutputTokens = Math.max(
|
||||
input.defaultMaxOutputTokens ?? DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS,
|
||||
reasoningFloor,
|
||||
);
|
||||
if (
|
||||
isPositiveFiniteNumber(input.model.maxOutputTokens) ||
|
||||
isPositiveFiniteNumber(input.model.contextWindow)
|
||||
) {
|
||||
caps.push(defaultMaxOutputTokens);
|
||||
}
|
||||
}
|
||||
|
||||
const caps: number[] = [Math.floor(input.requestedMaxTokens)];
|
||||
|
||||
if (isPositiveFiniteNumber(input.model.maxOutputTokens)) {
|
||||
caps.push(Math.floor(input.model.maxOutputTokens));
|
||||
}
|
||||
@@ -234,30 +251,31 @@ export class DefaultGateway implements Gateway {
|
||||
request.providerId,
|
||||
);
|
||||
const provider = await providerRecord.createProvider(providerRecord.config);
|
||||
const maxTokens = isPositiveFiniteNumber(request.maxTokens)
|
||||
? resolveGatewayRequestMaxTokens({
|
||||
requestedMaxTokens: request.maxTokens,
|
||||
model: resolved.model,
|
||||
estimatedInputTokens: estimateRequestInputTokens(request),
|
||||
onContextOverflow: (details) => {
|
||||
this.logger?.log(
|
||||
"Estimated prompt tokens exceed model context window",
|
||||
{
|
||||
severity: "warn",
|
||||
providerId: resolved.provider.id,
|
||||
modelId: resolved.model.id,
|
||||
...details,
|
||||
},
|
||||
);
|
||||
const maxTokens = resolveGatewayRequestMaxTokens({
|
||||
requestedMaxTokens: request.maxTokens,
|
||||
model: resolved.model,
|
||||
estimatedInputTokens: estimateRequestInputTokens(request),
|
||||
reasoningBudgetTokens: request.reasoning?.budgetTokens,
|
||||
onContextOverflow: (details) => {
|
||||
this.logger?.log(
|
||||
"Estimated prompt tokens exceed model context window",
|
||||
{
|
||||
severity: "warn",
|
||||
providerId: resolved.provider.id,
|
||||
modelId: resolved.model.id,
|
||||
...details,
|
||||
},
|
||||
})
|
||||
: undefined;
|
||||
);
|
||||
},
|
||||
});
|
||||
const stream = await provider.stream(
|
||||
{
|
||||
...request,
|
||||
modelId: resolved.model.id,
|
||||
providerId: resolved.provider.id,
|
||||
maxTokens,
|
||||
defaultedMaxTokens:
|
||||
maxTokens !== undefined && !isPositiveFiniteNumber(request.maxTokens),
|
||||
},
|
||||
{
|
||||
provider: resolved.provider,
|
||||
|
||||
@@ -283,7 +283,7 @@ const openRouterReasoningRule: ProviderOptionRule = {
|
||||
build: (input) =>
|
||||
buildReasoningPatchForProvider(
|
||||
input,
|
||||
buildOpenRouterReasoningOptions(input.request),
|
||||
buildOpenRouterReasoningOptions(input.request, input.context),
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ type ContextOverrides = {
|
||||
providerId?: string;
|
||||
modelId?: string;
|
||||
family?: string;
|
||||
maxOutputTokens?: number;
|
||||
modelMetadata?: NonNullable<GatewayProviderContext["model"]["metadata"]>;
|
||||
capabilities?: GatewayProviderContext["model"]["capabilities"];
|
||||
metadata?: GatewayProviderContext["provider"]["metadata"];
|
||||
@@ -87,6 +88,7 @@ function makeContext(options?: ContextOverrides): GatewayProviderContext {
|
||||
id: modelId,
|
||||
name: modelId,
|
||||
providerId,
|
||||
maxOutputTokens: options?.maxOutputTokens,
|
||||
capabilities: options?.capabilities,
|
||||
metadata: modelMetadata,
|
||||
},
|
||||
@@ -605,7 +607,7 @@ describe("composeAiSdkProviderOptions: family/provider thinking patches", () =>
|
||||
expect: [
|
||||
{
|
||||
bucket: "openrouter",
|
||||
has: { reasoning: { enabled: true } },
|
||||
has: { reasoning: { enabled: true, max_tokens: 19_200 } },
|
||||
lacks: ["thinking", "effort", "reasoningEffort"],
|
||||
},
|
||||
{
|
||||
@@ -614,6 +616,65 @@ describe("composeAiSdkProviderOptions: family/provider thinking patches", () =>
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "openrouter reasoning enabled-only uses resolved output cap for reasoning budget",
|
||||
request: {
|
||||
providerId: "openrouter",
|
||||
modelId: "openai/gpt-oss-120b",
|
||||
maxTokens: 10_000,
|
||||
reasoning: { enabled: true },
|
||||
},
|
||||
expect: [
|
||||
{
|
||||
bucket: "openrouter",
|
||||
has: { reasoning: { enabled: true, max_tokens: 6_000 } },
|
||||
lacks: ["thinking", "effort", "reasoningEffort"],
|
||||
},
|
||||
{
|
||||
bucket: "openaiCompatible",
|
||||
lacks: ["thinking", "reasoning", "effort", "reasoningEffort"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "openrouter reasoning enabled-only uses model output cap when request cap is absent",
|
||||
request: {
|
||||
providerId: "openrouter",
|
||||
modelId: "openai/gpt-oss-120b",
|
||||
reasoning: { enabled: true },
|
||||
},
|
||||
context: { maxOutputTokens: 12_000 },
|
||||
expect: [
|
||||
{
|
||||
bucket: "openrouter",
|
||||
has: { reasoning: { enabled: true, max_tokens: 7_200 } },
|
||||
lacks: ["thinking", "effort", "reasoningEffort"],
|
||||
},
|
||||
{
|
||||
bucket: "openaiCompatible",
|
||||
lacks: ["thinking", "reasoning", "effort", "reasoningEffort"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "openrouter reasoning effort sends only effort (no max_tokens, which OpenRouter rejects alongside effort)",
|
||||
request: {
|
||||
providerId: "openrouter",
|
||||
modelId: "openai/gpt-oss-120b",
|
||||
reasoning: { effort: "high" },
|
||||
},
|
||||
expect: [
|
||||
{
|
||||
bucket: "openrouter",
|
||||
has: { reasoning: { effort: "high" } },
|
||||
lacks: ["thinking", "reasoningEffort"],
|
||||
},
|
||||
{
|
||||
bucket: "openaiCompatible",
|
||||
lacks: ["thinking", "reasoning", "effort", "reasoningEffort"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "openrouter unset reasoning -> no reasoning field",
|
||||
request: {
|
||||
@@ -665,7 +726,7 @@ describe("composeAiSdkProviderOptions: family/provider thinking patches", () =>
|
||||
expect: [
|
||||
{
|
||||
bucket: "openrouter",
|
||||
has: { reasoning: { enabled: true } },
|
||||
has: { reasoning: { enabled: true, max_tokens: 19_200 } },
|
||||
lacks: ["thinking"],
|
||||
},
|
||||
{
|
||||
@@ -1307,7 +1368,7 @@ describe("composeAiSdkProviderOptions: family/provider thinking patches", () =>
|
||||
expect: [
|
||||
{
|
||||
bucket: "openrouter",
|
||||
has: { reasoning: { enabled: true } },
|
||||
has: { reasoning: { enabled: true, max_tokens: 19_200 } },
|
||||
lacks: ["thinking", "effort", "reasoningEffort"],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import type { GatewayStreamRequest } from "@cline/shared";
|
||||
import type {
|
||||
GatewayProviderContext,
|
||||
GatewayStreamRequest,
|
||||
} from "@cline/shared";
|
||||
import { DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS } from "../gateway";
|
||||
import { isPositiveFiniteNumber } from "../utils";
|
||||
|
||||
// OpenRouter separates total output limits (`max_tokens` / `max_output_tokens`)
|
||||
// from `reasoning.max_tokens`, which caps only the reasoning-token portion.
|
||||
// Sources:
|
||||
// - https://openrouter.ai/docs/api/reference/parameters
|
||||
// - https://openrouter.ai/docs/api/reference/responses/reasoning
|
||||
const OPENROUTER_REASONING_BUDGET_FRACTION = 0.6;
|
||||
|
||||
export function hasReasoningControls(
|
||||
reasoning: GatewayStreamRequest["reasoning"],
|
||||
@@ -10,8 +22,24 @@ export function hasReasoningControls(
|
||||
);
|
||||
}
|
||||
|
||||
function resolveOpenRouterReasoningMaxTokens(
|
||||
request: GatewayStreamRequest,
|
||||
context?: GatewayProviderContext,
|
||||
): number {
|
||||
const outputMaxTokens = isPositiveFiniteNumber(request.maxTokens)
|
||||
? request.maxTokens
|
||||
: isPositiveFiniteNumber(context?.model.maxOutputTokens)
|
||||
? context.model.maxOutputTokens
|
||||
: DEFAULT_GATEWAY_MAX_OUTPUT_TOKENS;
|
||||
return Math.max(
|
||||
1,
|
||||
Math.floor(outputMaxTokens * OPENROUTER_REASONING_BUDGET_FRACTION),
|
||||
);
|
||||
}
|
||||
|
||||
export function buildOpenRouterReasoningOptions(
|
||||
request: GatewayStreamRequest,
|
||||
context?: GatewayProviderContext,
|
||||
): Record<string, unknown> | undefined {
|
||||
const reasoning = request.reasoning;
|
||||
if (!hasReasoningControls(reasoning)) {
|
||||
@@ -22,8 +50,13 @@ export function buildOpenRouterReasoningOptions(
|
||||
return { effort: "none" };
|
||||
}
|
||||
|
||||
// OpenRouter accepts one reasoning control mode. Preserve this precedence:
|
||||
// explicit disable, exact token budget, effort level, then plain enable.
|
||||
// AI SDK `maxOutputTokens` still caps the whole response. This provider option
|
||||
// reserves room within that response by capping OpenRouter reasoning tokens.
|
||||
// Preserve explicit reasoning budgets when present; otherwise derive the cap
|
||||
// from the resolved request budget, model catalog output limit, or default.
|
||||
// OpenRouter rejects requests carrying both `reasoning.effort` and
|
||||
// `reasoning.max_tokens`, so the effort branch sends only `effort`.
|
||||
// DOCS: https://openrouter.ai/docs/api/reference/responses/reasoning
|
||||
if (typeof reasoning?.budgetTokens === "number") {
|
||||
return { max_tokens: reasoning.budgetTokens };
|
||||
}
|
||||
@@ -33,7 +66,10 @@ export function buildOpenRouterReasoningOptions(
|
||||
}
|
||||
|
||||
if (reasoning?.enabled === true) {
|
||||
return { enabled: true };
|
||||
return {
|
||||
enabled: true,
|
||||
max_tokens: resolveOpenRouterReasoningMaxTokens(request, context),
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export function isPositiveFiniteNumber(value: unknown): value is number {
|
||||
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import type {
|
||||
GatewayResolvedProviderConfig,
|
||||
GatewayStreamRequest,
|
||||
} from "@cline/shared";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createOpenAIProviderModule } from "./openai";
|
||||
|
||||
const createOpenAIMock = vi.hoisted(() => vi.fn());
|
||||
const responsesModelMock = vi.hoisted(() =>
|
||||
vi.fn((modelId: string) => ({ provider: "openai", modelId })),
|
||||
);
|
||||
|
||||
vi.mock("@ai-sdk/openai", () => ({
|
||||
createOpenAI: createOpenAIMock,
|
||||
}));
|
||||
|
||||
describe("createOpenAIProviderModule", () => {
|
||||
beforeEach(() => {
|
||||
createOpenAIMock.mockReset();
|
||||
createOpenAIMock.mockReturnValue({
|
||||
responses: responsesModelMock,
|
||||
});
|
||||
responsesModelMock.mockClear();
|
||||
});
|
||||
|
||||
it("forwards maxOutputTokens for explicit caps from direct callers", async () => {
|
||||
const provider = await createOpenAIProviderModule(config(), context());
|
||||
|
||||
const streamConfig = provider.buildStreamConfig?.(
|
||||
request({ maxTokens: 8_192 }),
|
||||
context(),
|
||||
);
|
||||
|
||||
expect(streamConfig?.maxOutputTokens).toBe(8_192);
|
||||
});
|
||||
|
||||
it("forwards maxOutputTokens for gateway-resolved explicit caps", async () => {
|
||||
const provider = await createOpenAIProviderModule(config(), context());
|
||||
|
||||
const streamConfig = provider.buildStreamConfig?.(
|
||||
request({ maxTokens: 8_192, defaultedMaxTokens: false }),
|
||||
context(),
|
||||
);
|
||||
|
||||
expect(streamConfig?.maxOutputTokens).toBe(8_192);
|
||||
});
|
||||
|
||||
it("drops gateway-synthesized default caps", async () => {
|
||||
const provider = await createOpenAIProviderModule(config(), context());
|
||||
|
||||
const streamConfig = provider.buildStreamConfig?.(
|
||||
request({ maxTokens: 32_000, defaultedMaxTokens: true }),
|
||||
context(),
|
||||
);
|
||||
|
||||
expect(streamConfig).not.toHaveProperty("maxOutputTokens");
|
||||
});
|
||||
|
||||
it("drops explicit caps for the ChatGPT OAuth backend", async () => {
|
||||
const provider = await createOpenAIProviderModule(
|
||||
config({ baseUrl: "https://chatgpt.com/backend-api/codex" }),
|
||||
context(),
|
||||
);
|
||||
|
||||
const streamConfig = provider.buildStreamConfig?.(
|
||||
request({ maxTokens: 8_192 }),
|
||||
context(),
|
||||
);
|
||||
|
||||
expect(streamConfig).not.toHaveProperty("maxOutputTokens");
|
||||
});
|
||||
|
||||
it("does not treat non-chatgpt.com hosts containing 'chatgpt.com' as OAuth", async () => {
|
||||
for (const baseUrl of [
|
||||
"https://example.com/chatgpt.com",
|
||||
"https://chatgpt.com.example.com/v1",
|
||||
"https://notchatgpt.com/v1",
|
||||
]) {
|
||||
const provider = await createOpenAIProviderModule(
|
||||
config({ baseUrl }),
|
||||
context(),
|
||||
);
|
||||
|
||||
const streamConfig = provider.buildStreamConfig?.(
|
||||
request({ maxTokens: 8_192 }),
|
||||
context(),
|
||||
);
|
||||
|
||||
expect(streamConfig?.maxOutputTokens).toBe(8_192);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function config(
|
||||
overrides: Partial<GatewayResolvedProviderConfig> = {},
|
||||
): GatewayResolvedProviderConfig {
|
||||
return {
|
||||
providerId: "openai-native",
|
||||
apiKey: "test-api-key",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function context() {
|
||||
return {
|
||||
provider: {
|
||||
id: "openai-native",
|
||||
name: "OpenAI",
|
||||
defaultModelId: "gpt-5-mini",
|
||||
models: [],
|
||||
},
|
||||
model: {
|
||||
providerId: "openai-native",
|
||||
id: "gpt-5-mini",
|
||||
name: "gpt-5-mini",
|
||||
},
|
||||
config: config(),
|
||||
};
|
||||
}
|
||||
|
||||
function request(
|
||||
overrides: Partial<GatewayStreamRequest>,
|
||||
): GatewayStreamRequest {
|
||||
return {
|
||||
providerId: "openai-native",
|
||||
modelId: "gpt-5-mini",
|
||||
messages: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -6,6 +6,18 @@ import type {
|
||||
import { resolveApiKey } from "../http";
|
||||
import type { ProviderFactoryResult } from "./types";
|
||||
|
||||
function isChatGptOAuthBaseUrl(baseUrl: string | undefined): boolean {
|
||||
if (!baseUrl) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const { hostname } = new URL(baseUrl);
|
||||
return hostname === "chatgpt.com" || hostname.endsWith(".chatgpt.com");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function createOpenAIProviderModule(
|
||||
config: GatewayResolvedProviderConfig,
|
||||
context: GatewayProviderContext,
|
||||
@@ -18,7 +30,22 @@ export async function createOpenAIProviderModule(
|
||||
fetch: config.fetch,
|
||||
name: context.provider.id,
|
||||
});
|
||||
// The ChatGPT OAuth Codex backend rejects `max_output_tokens`, and the
|
||||
// OpenAI Responses API applies its own defaults, so gateway-synthesized
|
||||
// caps are never forwarded. Explicit caps — whether resolved by the
|
||||
// gateway from a caller request or passed straight to this provider —
|
||||
// are honored for API-key usage because that endpoint supports output
|
||||
// limits.
|
||||
const isChatGptOAuth = isChatGptOAuthBaseUrl(config.baseUrl);
|
||||
return {
|
||||
model: (modelId) => provider.responses(modelId),
|
||||
buildStreamConfig: (request) => ({
|
||||
...(!isChatGptOAuth &&
|
||||
request.maxTokens !== undefined &&
|
||||
request.defaultedMaxTokens !== true
|
||||
? { maxOutputTokens: request.maxTokens }
|
||||
: {}),
|
||||
temperature: request.temperature,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import type {
|
||||
GatewayProviderContext,
|
||||
GatewayStreamRequest,
|
||||
} from "@cline/shared";
|
||||
import type { CallSettings } from "ai";
|
||||
|
||||
export interface ProviderFactoryResult {
|
||||
model: (modelId: string) => unknown;
|
||||
buildStreamConfig?: (
|
||||
request: GatewayStreamRequest,
|
||||
context: GatewayProviderContext,
|
||||
) => Partial<CallSettings>;
|
||||
}
|
||||
|
||||
export interface AiSdkStreamPart {
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
"response": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"model\":\"claude-sonnet-4-6\",\"id\":\"ID_REDACTED\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"stop_reason\":null,\"stop_sequence\":null,\"stop_details\":null,\"usage\":{\"input_tokens\":22,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":1,\"service_tier\":\"standard\",\"inference_geo\":\"global\"}}}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"OK\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null,\"stop_details\":null},\"usage\":{\"input_tokens\":22,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"output_tokens\":4}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n",
|
||||
"responseIsBinary": false,
|
||||
"contentType": "text/event-stream; charset=utf-8",
|
||||
"requestBody": "{\"max_tokens\":128000,\"messages\":[{\"content\":[{\"cache_control\":{\"type\":\"ephemeral\"},\"text\":\"Reply with the single word OK.\",\"type\":\"text\"}],\"role\":\"user\"}],\"model\":\"claude-sonnet-4-6\",\"stream\":true,\"system\":[{\"text\":\"You are a concise assistant.\",\"type\":\"text\"}]}"
|
||||
"requestBody": "{\"max_tokens\":32000,\"messages\":[{\"content\":[{\"cache_control\":{\"type\":\"ephemeral\"},\"text\":\"Reply with the single word OK.\",\"type\":\"text\"}],\"role\":\"user\"}],\"model\":\"claude-sonnet-4-6\",\"stream\":true,\"system\":[{\"text\":\"You are a concise assistant.\",\"type\":\"text\"}]}"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
"response": "data: {\"id\":\"ID_REDACTED\",\"object\":\"chat.completion.chunk\",\"created\":0,\"model\":\"anthropic/claude-sonnet-4.6\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\"},\"logprobs\":null,\"finish_reason\":null}],\"system_fingerprint\":\"REDACTED\"}\n\ndata: {\"id\":\"ID_REDACTED\",\"object\":\"chat.completion.chunk\",\"created\":0,\"model\":\"anthropic/claude-sonnet-4.6\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"OK\"},\"logprobs\":null,\"finish_reason\":null}],\"system_fingerprint\":\"REDACTED\"}\n\ndata: {\"id\":\"ID_REDACTED\",\"object\":\"chat.completion.chunk\",\"created\":0,\"model\":\"anthropic/claude-sonnet-4.6\",\"choices\":[{\"index\":0,\"delta\":{\"provider_metadata\":{\"anthropic\":{\"usage\":{\"input_tokens\":22,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":4,\"service_tier\":\"standard\",\"inference_geo\":\"global\"},\"cacheCreationInputTokens\":0,\"stopSequence\":null,\"iterations\":null,\"container\":null,\"contextManagement\":null},\"gateway\":{\"routing\":{\"originalModelId\":\"anthropic/claude-sonnet-4.6\",\"resolvedProvider\":\"anthropic\",\"fallbacksAvailable\":[\"vertexAnthropic\",\"bedrock\"],\"planningReasoning\":\"REDACTED\",\"canonicalSlug\":\"anthropic/claude-sonnet-4.6\",\"finalProvider\":\"anthropic\",\"modelAttemptCount\":1,\"modelAttempts\":[{\"canonicalSlug\":\"anthropic/claude-sonnet-4.6\",\"success\":true,\"providerAttemptCount\":1,\"providerAttempts\":[{\"provider\":\"anthropic\",\"credentialType\":\"byok\",\"success\":true,\"startTime\":0,\"endTime\":0,\"providerRequestId\":\"ID_REDACTED\",\"statusCode\":200,\"providerResponseId\":\"ID_REDACTED\"}]}],\"totalProviderAttemptCount\":1},\"cost\":\"0\",\"marketCost\":\"0.000126\",\"surchargeCost\":\"0\",\"gatewayCost\":\"0\",\"generationId\":\"ID_REDACTED\"}}},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":22,\"completion_tokens\":4,\"total_tokens\":26,\"cost\":0,\"is_byok\":true,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0,\"video_tokens\":0},\"cost_details\":{\"upstream_inference_cost\":0.000126,\"upstream_inference_prompt_cost\":0,\"upstream_inference_completions_cost\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"image_tokens\":0},\"cache_creation_input_tokens\":0,\"market_cost\":0.000126},\"system_fingerprint\":\"REDACTED\",\"generationId\":\"ID_REDACTED\"}\n\ndata: [DONE]\n\n",
|
||||
"responseIsBinary": false,
|
||||
"contentType": "text/event-stream",
|
||||
"requestBody": "{\"cache_control\":{\"type\":\"ephemeral\"},\"messages\":[{\"content\":\"You are a concise assistant.\",\"role\":\"system\"},{\"cache_control\":{\"type\":\"ephemeral\"},\"content\":\"Reply with the single word OK.\",\"role\":\"user\"}],\"model\":\"anthropic/claude-sonnet-4.6\",\"stream\":true,\"stream_options\":{\"include_usage\":true}}"
|
||||
"requestBody": "{\"cache_control\":{\"type\":\"ephemeral\"},\"max_tokens\":32000,\"messages\":[{\"content\":\"You are a concise assistant.\",\"role\":\"system\"},{\"cache_control\":{\"type\":\"ephemeral\"},\"content\":\"Reply with the single word OK.\",\"role\":\"user\"}],\"model\":\"anthropic/claude-sonnet-4.6\",\"stream\":true,\"stream_options\":{\"include_usage\":true}}"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@cline/sdk",
|
||||
"description": "Cline SDK - user-facing alias for @cline/core",
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.64",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cline/cline",
|
||||
|
||||
@@ -37,6 +37,7 @@ await runBuild("node", {
|
||||
"./src/index.ts",
|
||||
"./src/automation/index.ts",
|
||||
"./src/db/index.ts",
|
||||
"./src/node.ts",
|
||||
"./src/remote-config/index.ts",
|
||||
"./src/storage/index.ts",
|
||||
],
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user