mirror of
https://github.com/cline/cline.git
synced 2026-09-01 23:19:18 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84d49f9e49 | |||
| e52a052c81 | |||
| 7a91a9be2e | |||
| 93a494d009 | |||
| 2bd21f8a45 | |||
| 2f33f71ebd | |||
| dec10aaec3 | |||
| c09705a45f | |||
| 73058c871a | |||
| 03211f1364 | |||
| 65e9727c65 | |||
| 884fbfb21e | |||
| 0c880c7bb1 |
@@ -1,5 +1,6 @@
|
||||
demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
assets/docs/demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
webview-ui/src/assets/cline_kanban_demo.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||
webview-ui/src/assets/cline_kanban_demo.webm filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
* text=auto eol=lf
|
||||
|
||||
@@ -91,3 +91,21 @@ jobs:
|
||||
echo ""
|
||||
echo "📦 Install with: npm install -g cline"
|
||||
echo "🔗 NPM: https://www.npmjs.com/package/cline/v/${{ steps.version.outputs.version }}"
|
||||
|
||||
- name: Post release to Slack
|
||||
uses: slackapi/slack-github-action@v3.0.1
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_RELEASE_BOT_TOKEN }}
|
||||
payload: |
|
||||
channel: "C0APVKGGZFC"
|
||||
text: "Cline CLI v${{ steps.version.outputs.version }}"
|
||||
blocks:
|
||||
- type: "section"
|
||||
text:
|
||||
type: "mrkdwn"
|
||||
text: "*Cline CLI v${{ steps.version.outputs.version }}*"
|
||||
- type: "context"
|
||||
elements:
|
||||
- type: "mrkdwn"
|
||||
text: "<https://www.npmjs.com/package/cline/v/${{ steps.version.outputs.version }}|View on npm>"
|
||||
|
||||
@@ -53,11 +53,12 @@ jobs:
|
||||
|
||||
- name: Verify LFS media assets are resolved
|
||||
run: |
|
||||
FILE="webview-ui/src/assets/cline_kanban_demo.webm"
|
||||
if grep -q "git-lfs.github.com/spec/v1" "$FILE"; then
|
||||
echo "Error: $FILE is still a Git LFS pointer in CI checkout"
|
||||
exit 1
|
||||
fi
|
||||
for FILE in webview-ui/src/assets/cline_kanban_demo.mp4 webview-ui/src/assets/cline_kanban_demo.webm; do
|
||||
if grep -q "git-lfs.github.com/spec/v1" "$FILE"; then
|
||||
echo "Error: $FILE is still a Git LFS pointer in CI checkout"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Publish Extension as Pre-release
|
||||
env:
|
||||
|
||||
@@ -136,11 +136,12 @@ jobs:
|
||||
|
||||
- name: Verify LFS media assets are resolved
|
||||
run: |
|
||||
FILE="webview-ui/src/assets/cline_kanban_demo.webm"
|
||||
if grep -q "git-lfs.github.com/spec/v1" "$FILE"; then
|
||||
echo "Error: $FILE is still a Git LFS pointer in CI checkout"
|
||||
exit 1
|
||||
fi
|
||||
for FILE in webview-ui/src/assets/cline_kanban_demo.mp4 webview-ui/src/assets/cline_kanban_demo.webm; do
|
||||
if grep -q "git-lfs.github.com/spec/v1" "$FILE"; then
|
||||
echo "Error: $FILE is still a Git LFS pointer in CI checkout"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Package and Publish Extension
|
||||
env:
|
||||
@@ -196,3 +197,25 @@ jobs:
|
||||
prerelease: ${{ github.event.inputs.release-type == 'pre-release' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Post release to Slack
|
||||
uses: slackapi/slack-github-action@v3.0.1
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_RELEASE_BOT_TOKEN }}
|
||||
payload: |
|
||||
channel: "C0APVKGGZFC"
|
||||
text: "Cline ${{ steps.resolve_tag.outputs.tag }}"
|
||||
blocks:
|
||||
- type: "section"
|
||||
text:
|
||||
type: "mrkdwn"
|
||||
text: "*Cline ${{ steps.resolve_tag.outputs.tag }}*"
|
||||
- type: "section"
|
||||
text:
|
||||
type: "mrkdwn"
|
||||
text: ${{ toJSON(steps.changelog.outputs.content) }}
|
||||
- type: "context"
|
||||
elements:
|
||||
- type: "mrkdwn"
|
||||
text: "Full Changelog: https://github.com/${{ github.repository }}/compare/${{ steps.prev_tag.outputs.prev_tag }}...${{ steps.resolve_tag.outputs.tag }}"
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
"ts"
|
||||
],
|
||||
"spec": [
|
||||
"src/**/__tests__/*.ts"
|
||||
"src/**/__tests__/*.ts",
|
||||
"src/test/services/**/*.test.ts"
|
||||
],
|
||||
"require": [
|
||||
"ts-node/register",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## [3.77.0]
|
||||
|
||||
### Added
|
||||
|
||||
- Add "Lazy Teammate Mode" experimental toggle
|
||||
- `read_file` tool now supports chunked reading for targeted file access
|
||||
|
||||
### Fixed
|
||||
|
||||
- Exclude `new_task` tool from system prompt in yolo/headless mode
|
||||
- Fix Kanban demo video formatting
|
||||
|
||||
### Changed
|
||||
|
||||
- Polish `Notification` hook functionality
|
||||
|
||||
## [3.76.0]
|
||||
|
||||
### Added
|
||||
|
||||
+2
-4
@@ -8,9 +8,7 @@ We actively patch only the most recent minor release of Cline. Older versions re
|
||||
|
||||
We appreciate your efforts to responsibly disclose your findings and will make every effort to acknowledge your contributions.
|
||||
|
||||
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/cline/cline/security/advisories/new) tab.
|
||||
|
||||
The team will send a response indicating the next steps in handling your report. After the initial reply, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
||||
Please submit security issues through Cline's [Vulnerability Disclosure Program](https://bugcrowd.com/engagements/clinebot-vdp-ess) offered through BugCrowd.
|
||||
|
||||
When reporting, please include:
|
||||
|
||||
@@ -18,7 +16,7 @@ When reporting, please include:
|
||||
- Steps to reproduce or a proof of concept
|
||||
- Any logs, stack traces, or screenshots that might help us understand the problem
|
||||
|
||||
We acknowledge reports within 48 hours and aim to release a fix or mitigation within 30 days. While we work on a resolution, please keep the details private.
|
||||
While we work on a resolution, please keep the details private.
|
||||
|
||||
## Escalation
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 512 535">
|
||||
<!-- Generator: Adobe Illustrator 29.8.5, SVG Export Plug-In . SVG Version: 2.1.1 Build 2) -->
|
||||
<defs>
|
||||
<style>
|
||||
.st0 {
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="st0" d="M500.6,300.5c-9-20.7-17.9-41.4-26.9-62.1-.7-2-.3-4.4-.3-6.4.4-9,1.1-18,1.4-27,2.8-28.4-6.5-58-25.2-79.6-15.1-18.1-36.6-30.7-59.6-35.5-8.1-1.8-16.6-1.6-25-2.1-10-.7-20-1-30-1.7,2-11.9,1-24.1-3.7-35.3-5.8-14.1-16.8-25.9-30.6-32.5-14.4-7-31.5-8.2-46.7-3.1-16,5.2-29.5,17-36.8,32.1-4.9,10-6.8,21.2-6.1,32.2-19.7-1-39.4-2.2-59.1-3.1-26.8.5-53,11.7-72,30.6-20.2,19.5-31.7,47-32.3,75-.5,9.3-1,18.7-1.5,28-.2,2.1,0,4.1-1.2,6-9.8,16.8-19.5,33.7-29.4,50.6-2.2,4.1-4.9,8-6.6,12.3-2,5.7-1.2,12.2,1.3,17.6,8.9,19.5,17.6,39.2,26.5,58.7.8,1.9,1.5,3.7,1.3,5.8-.6,10.3-1.1,20.7-1.7,31-1.5,21.2,3,42.6,13.5,61.1,8.8,15.8,21.6,29.4,37.1,38.9,13.9,8.7,29.7,13.9,46,15.4,72,3.9,144,7.7,216,11.5,20.1,1.8,40.8-2.8,58.5-12.5,18.8-10.1,34.2-26,44.1-44.9,6.5-12.6,10.5-26.4,11.7-40.5.7-12.4,1.2-24.7,2-37.1,0-3.3,1.9-5.5,3.3-8.2,6.6-11.8,13.5-23.4,20.1-35.2,3.7-6.9,8.1-13.4,11.6-20.4,3.2-6.1,3.2-13.5.3-19.7ZM218.5,316.5c-9.7,7.1-21.3,12.3-33.5,12.5-17.6,1-35.1-5.3-49-16-4.6-3.2-8.1-7.5-9.6-13,0-1.8-.7-3.6,1.7-3.8,4,1,7.9,2.6,12,3.5,22.8,5.6,47.6,5.9,71,4.8,6.5-.2,13-1.3,19.5-.9-2.7,5.6-7.1,9.2-12,12.9ZM276,449.7c-14,.5-28,.1-42-.2-2.1,0-4.3,0-6.4-.4-.9-2.1.6-3.2,1.7-4.8,4.8-5.9,11-11,18.7-12.4,8.4-1.6,16.5,1.2,23.5,5.5,4.7,3,9.2,6.3,12.6,10.8-2.6,1.1-5.3,1.4-8.1,1.4ZM390.4,319.4c-16.4,14.2-38.8,21.8-60.4,18.4-13.2-1.6-24.7-8.6-34.1-17.7-3-3-6.2-6.5-8.1-10.4.5-1,1.2-1.6,2.2-1.6,2.8-.2,5.7.7,8.5,1.1,16,2.9,32.3,4.9,48.5,5.5,14.3.4,28.2-.2,42.2-3.6,2.2-.6,3.7-.3,5.8.5-1.1,2.9-2.2,5.7-4.6,7.8Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,5 +1,19 @@
|
||||
# cline
|
||||
|
||||
## [2.12.0]
|
||||
|
||||
### Added
|
||||
|
||||
- `read_file` tool now supports chunked reading for targeted file access
|
||||
|
||||
### Fixed
|
||||
|
||||
- Exclude `new_task` tool from system prompt in yolo/headless mode
|
||||
|
||||
### Changed
|
||||
|
||||
- Polish `Notification` hook functionality
|
||||
|
||||
## [2.9.0]
|
||||
|
||||
### Added
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cline",
|
||||
"version": "2.11.0",
|
||||
"version": "2.13.0",
|
||||
"description": "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more",
|
||||
"main": "dist/lib.mjs",
|
||||
"types": "dist/lib.d.ts",
|
||||
|
||||
@@ -99,6 +99,12 @@ describe("CLI Commands", () => {
|
||||
.description("Run kanban")
|
||||
.action(() => {})
|
||||
|
||||
program
|
||||
.command("update")
|
||||
.description("Check for updates and install if available")
|
||||
.option("-v, --verbose", "Show verbose output")
|
||||
.action(() => {})
|
||||
|
||||
// Default command for interactive mode
|
||||
program
|
||||
.argument("[prompt]", "Task prompt")
|
||||
@@ -113,6 +119,7 @@ describe("CLI Commands", () => {
|
||||
.option("--auto-condense", "Enable AI-powered context compaction instead of mechanical truncation")
|
||||
.option("--hooks-dir <path>", "Additional hooks directory")
|
||||
.option("--auto-approve-all", "Enable auto-approve all")
|
||||
.option("--update", "Check for updates and install if available")
|
||||
.option("--kanban", "Run kanban")
|
||||
.option("--tui", "Open the legacy terminal UI instead of the kanban experience")
|
||||
.action(() => {})
|
||||
@@ -315,6 +322,20 @@ describe("CLI Commands", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("update command", () => {
|
||||
it("should parse update command", () => {
|
||||
const args = ["node", "cli", "update"]
|
||||
program.parse(args)
|
||||
})
|
||||
|
||||
it("should parse --verbose on update command", () => {
|
||||
const updateCmd = getCommand("update")
|
||||
const args = ["--verbose"]
|
||||
updateCmd.parse(args, { from: "user" })
|
||||
expect(updateCmd.opts().verbose).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("auth command", () => {
|
||||
it("should parse auth command", () => {
|
||||
const args = ["node", "cli", "auth"]
|
||||
@@ -439,6 +460,11 @@ describe("CLI Commands", () => {
|
||||
expect(program.opts().kanban).toBe(true)
|
||||
})
|
||||
|
||||
it("should parse --update flag", () => {
|
||||
program.parse(["node", "cli", "--update"])
|
||||
expect(program.opts().update).toBe(true)
|
||||
})
|
||||
|
||||
it("should parse --tui flag", () => {
|
||||
program.parse(["node", "cli", "--tui"])
|
||||
expect(program.opts().tui).toBe(true)
|
||||
@@ -454,6 +480,7 @@ describe("CLI Commands", () => {
|
||||
expect(commandNames).toContain("auth")
|
||||
expect(commandNames).toContain("mcp")
|
||||
expect(commandNames).toContain("kanban")
|
||||
expect(commandNames).toContain("update")
|
||||
})
|
||||
|
||||
it("should have correct aliases", () => {
|
||||
|
||||
+12
-1
@@ -1027,7 +1027,7 @@ program
|
||||
.command("update")
|
||||
.description("Check for updates and install if available")
|
||||
.option("-v, --verbose", "Show verbose output")
|
||||
.action(() => checkForUpdates(CLI_VERSION))
|
||||
.action((options) => checkForUpdates(CLI_VERSION, { verbose: options.verbose, includeKanban: true }))
|
||||
|
||||
program
|
||||
.command("kanban")
|
||||
@@ -1183,6 +1183,7 @@ program
|
||||
.option("--auto-condense", "Enable AI-powered context compaction instead of mechanical truncation")
|
||||
.option("--hooks-dir <path>", "Path to additional hooks directory for runtime hook injection")
|
||||
.option("--acp", "Run in ACP (Agent Client Protocol) mode for editor integration")
|
||||
.option("--update", "Check for updates and install if available")
|
||||
.option("--kanban", `Run ${KANBAN_LAUNCH_COMMAND}`)
|
||||
.option("--tui", "Open the legacy terminal UI instead of the kanban experience")
|
||||
.option("-T, --taskId <id>", "Resume an existing task by ID")
|
||||
@@ -1193,6 +1194,16 @@ program
|
||||
exit(1)
|
||||
}
|
||||
|
||||
if (options.update) {
|
||||
if (prompt || options.taskId || options.continue || options.kanban || options.tui || options.acp) {
|
||||
printWarning("Use --update without a prompt or task flags.")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
await checkForUpdates(CLI_VERSION, { verbose: options.verbose, includeKanban: true })
|
||||
return
|
||||
}
|
||||
|
||||
if (options.kanban) {
|
||||
if (prompt) {
|
||||
printWarning("Use --kanban without a prompt.")
|
||||
|
||||
+198
-70
@@ -1,9 +1,10 @@
|
||||
import { spawn } from "node:child_process"
|
||||
import { type ChildProcess, spawn, spawnSync } from "node:child_process"
|
||||
import { realpathSync } from "node:fs"
|
||||
import { exit } from "node:process"
|
||||
import { ClineEndpoint } from "@/config"
|
||||
import { fetch } from "@/shared/net"
|
||||
import { printInfo, printWarning } from "./display"
|
||||
import { printInfo, printSuccess, printWarning } from "./display"
|
||||
import { resolveKanbanInstallCommand, spawnKanbanInstallProcess } from "./kanban"
|
||||
|
||||
export enum PackageManager {
|
||||
NPM = "npm",
|
||||
@@ -19,6 +20,11 @@ interface InstallationInfo {
|
||||
updateCommand?: string
|
||||
}
|
||||
|
||||
interface CheckForUpdatesOptions {
|
||||
verbose?: boolean
|
||||
includeKanban?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a version string is a nightly build.
|
||||
*/
|
||||
@@ -91,9 +97,12 @@ function getInstallationInfo(currentVersion: string): InstallationInfo {
|
||||
* Uses the appropriate tag based on whether the current version is nightly.
|
||||
*/
|
||||
async function getLatestVersion(currentVersion: string): Promise<string | null> {
|
||||
return getLatestPackageVersion("cline", getNpmTag(currentVersion))
|
||||
}
|
||||
|
||||
async function getLatestPackageVersion(packageName: string, tag = "latest"): Promise<string | null> {
|
||||
try {
|
||||
const tag = getNpmTag(currentVersion)
|
||||
const response = await fetch(`https://registry.npmjs.org/cline/${tag}`)
|
||||
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/${tag}`)
|
||||
if (!response.ok) return null
|
||||
const data = (await response.json()) as { version: string }
|
||||
return data.version || null
|
||||
@@ -102,6 +111,29 @@ async function getLatestVersion(currentVersion: string): Promise<string | null>
|
||||
}
|
||||
}
|
||||
|
||||
async function getLatestKanbanVersion(): Promise<string | null> {
|
||||
return getLatestPackageVersion("kanban")
|
||||
}
|
||||
|
||||
function getInstalledKanbanVersion(): string | null {
|
||||
try {
|
||||
const command = process.platform === "win32" ? "kanban.cmd" : "kanban"
|
||||
const result = spawnSync(command, ["--version"], {
|
||||
encoding: "utf8",
|
||||
shell: process.platform === "win32",
|
||||
})
|
||||
if (result.status !== 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim()
|
||||
const versionMatch = output.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/)
|
||||
return versionMatch?.[0] ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-update check that runs on CLI startup.
|
||||
* Checks for updates asynchronously (non-blocking), then spawns a detached
|
||||
@@ -157,85 +189,181 @@ async function checkAndUpdate(currentVersion: string, updateCommand: string): Pr
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForProcessExit(updateProcess: ChildProcess): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
updateProcess.once("close", (code) => {
|
||||
resolve(code ?? 1)
|
||||
})
|
||||
|
||||
updateProcess.once("error", (error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function runClineUpdate(updateCommand: string): Promise<number> {
|
||||
const updateProcess = spawn(updateCommand, {
|
||||
stdio: "inherit",
|
||||
shell: true,
|
||||
env: process.env,
|
||||
windowsHide: true,
|
||||
})
|
||||
|
||||
return waitForProcessExit(updateProcess)
|
||||
}
|
||||
|
||||
type KanbanInstallCommand = NonNullable<ReturnType<typeof resolveKanbanInstallCommand>>
|
||||
|
||||
async function runKanbanUpdate(installCommand: KanbanInstallCommand): Promise<number> {
|
||||
const updateProcess = spawnKanbanInstallProcess(installCommand, {
|
||||
env: process.env,
|
||||
windowsHide: true,
|
||||
})
|
||||
return waitForProcessExit(updateProcess)
|
||||
}
|
||||
|
||||
function formatUpdateSummaryTargets(targets: string[]): string {
|
||||
if (targets.length === 0) {
|
||||
return ""
|
||||
}
|
||||
if (targets.length === 1) {
|
||||
return targets[0]
|
||||
}
|
||||
if (targets.length === 2) {
|
||||
return `${targets[0]} and ${targets[1]}`
|
||||
}
|
||||
return `${targets.slice(0, -1).join(", ")}, and ${targets.at(-1)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for updates and install if available (manual command)
|
||||
*/
|
||||
export async function checkForUpdates(currentVersion: string, options?: { verbose?: boolean }) {
|
||||
printInfo("Checking for updates...")
|
||||
export async function checkForUpdates(currentVersion: string, options: CheckForUpdatesOptions = {}) {
|
||||
const includeKanban = options.includeKanban ?? true
|
||||
|
||||
printInfo("Checking for updates to cline and kanban packages...")
|
||||
|
||||
const { updateCommand, packageManager } = getInstallationInfo(currentVersion)
|
||||
|
||||
try {
|
||||
const latestVersion = await getLatestVersion(currentVersion)
|
||||
if (!latestVersion) {
|
||||
printWarning("Failed to check for updates: could not fetch latest version")
|
||||
exit(1)
|
||||
}
|
||||
const latestClineVersion = await getLatestVersion(currentVersion)
|
||||
const canCheckClineVersion = latestClineVersion !== null
|
||||
|
||||
if (options?.verbose) {
|
||||
printInfo(`Current version: ${currentVersion}`)
|
||||
printInfo(`Latest version: ${latestVersion}`)
|
||||
printInfo(`Package manager: ${packageManager}`)
|
||||
}
|
||||
|
||||
// Compare versions
|
||||
if (latestVersion === currentVersion) {
|
||||
printInfo(`You are already on the latest version (${currentVersion})`)
|
||||
exit(0)
|
||||
}
|
||||
|
||||
// Check if current is newer (dev version)
|
||||
if (compareVersions(currentVersion, latestVersion) > 0) {
|
||||
printInfo(`You are already on a newer version ${currentVersion} (latest: ${latestVersion})`)
|
||||
exit(0)
|
||||
}
|
||||
|
||||
printInfo(`New version available: ${latestVersion} (current: ${currentVersion})`)
|
||||
|
||||
if (!updateCommand) {
|
||||
printInfo("Unable to determine update command for your installation.")
|
||||
printInfo("Please update manually using your package manager.")
|
||||
exit(0)
|
||||
}
|
||||
|
||||
// Ask user to confirm update
|
||||
const userConfirmed = new Promise<boolean>((resolve) => {
|
||||
process.stdout.write("Do you want to update now? (y/N): ")
|
||||
process.stdin.setEncoding("utf-8")
|
||||
process.stdin.once("data", (dataBuff) => {
|
||||
const input = dataBuff.toString().trim().toLowerCase()
|
||||
resolve(input === "y" || input === "yes")
|
||||
})
|
||||
})
|
||||
|
||||
if (!(await userConfirmed)) {
|
||||
exit(0)
|
||||
}
|
||||
|
||||
printInfo(`Installing update via ${packageManager}...`)
|
||||
|
||||
const updateProcess = spawn(updateCommand, {
|
||||
stdio: "inherit",
|
||||
shell: true,
|
||||
env: process.env,
|
||||
windowsHide: true,
|
||||
})
|
||||
|
||||
updateProcess.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
printInfo(`Successfully updated to version ${latestVersion}`)
|
||||
exit(0)
|
||||
} else {
|
||||
printWarning(`Update failed. Please try running: ${updateCommand}`)
|
||||
exit(1)
|
||||
if (canCheckClineVersion) {
|
||||
printInfo(`Latest version: ${latestClineVersion}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
updateProcess.on("error", (err) => {
|
||||
printWarning(`Failed to run update: ${err.message}`)
|
||||
printInfo(`Please try running manually: ${updateCommand}`)
|
||||
if (!canCheckClineVersion) {
|
||||
printWarning("Failed to check for Cline updates: could not fetch latest version")
|
||||
}
|
||||
|
||||
const clineComparison = latestClineVersion ? compareVersions(currentVersion, latestClineVersion) : null
|
||||
const clineUpdateAvailable = clineComparison !== null && clineComparison < 0
|
||||
const clineIsUpToDate = clineComparison !== null && clineComparison === 0
|
||||
const canUpdateCline = clineUpdateAvailable && Boolean(updateCommand)
|
||||
|
||||
if (clineUpdateAvailable && latestClineVersion) {
|
||||
printInfo(`New version available: ${latestClineVersion} (current: ${currentVersion})`)
|
||||
}
|
||||
|
||||
if (clineUpdateAvailable && !updateCommand) {
|
||||
printInfo("Unable to determine Cline update command for your installation.")
|
||||
printInfo("Please update Cline manually using your package manager.")
|
||||
}
|
||||
|
||||
const kanbanInstallCommand = includeKanban ? resolveKanbanInstallCommand() : null
|
||||
const kanbanInstallerAvailable = kanbanInstallCommand !== null
|
||||
if (includeKanban && !kanbanInstallerAvailable && options.verbose) {
|
||||
printWarning("Unable to determine Kanban update command (npm, pnpm, or bun not found in PATH).")
|
||||
}
|
||||
const latestKanbanVersion = kanbanInstallerAvailable ? await getLatestKanbanVersion() : null
|
||||
const installedKanbanVersion = includeKanban ? getInstalledKanbanVersion() : null
|
||||
const kanbanIsUpToDate =
|
||||
latestKanbanVersion !== null &&
|
||||
installedKanbanVersion !== null &&
|
||||
compareVersions(installedKanbanVersion, latestKanbanVersion) >= 0
|
||||
const shouldInstallKanban =
|
||||
kanbanInstallerAvailable &&
|
||||
latestKanbanVersion !== null &&
|
||||
(installedKanbanVersion === null || compareVersions(installedKanbanVersion, latestKanbanVersion) < 0)
|
||||
|
||||
if (!canCheckClineVersion && !shouldInstallKanban) {
|
||||
exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
if (!canUpdateCline && !shouldInstallKanban) {
|
||||
if (clineIsUpToDate && kanbanIsUpToDate && installedKanbanVersion) {
|
||||
printInfo(`You are already on the latest version cline@${currentVersion} and kanban@${installedKanbanVersion}`)
|
||||
} else if (clineIsUpToDate) {
|
||||
printInfo(`You are already on the latest version cline@${currentVersion}`)
|
||||
}
|
||||
exit(0)
|
||||
}
|
||||
|
||||
let hadFailure = false
|
||||
const installedUpdates: string[] = []
|
||||
|
||||
if (canUpdateCline && updateCommand && latestClineVersion) {
|
||||
printInfo(`Installing cline@${latestClineVersion}...`)
|
||||
try {
|
||||
const clineUpdateCode = await runClineUpdate(updateCommand)
|
||||
if (clineUpdateCode === 0) {
|
||||
installedUpdates.push(`cline@${latestClineVersion}`)
|
||||
} else {
|
||||
printWarning(`Cline update failed. Please try running: ${updateCommand}`)
|
||||
hadFailure = true
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
printWarning(`Failed to run Cline update: ${message}`)
|
||||
printInfo(`Please try running manually: ${updateCommand}`)
|
||||
hadFailure = true
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldInstallKanban && kanbanInstallCommand && latestKanbanVersion) {
|
||||
const kanbanTargetVersion = latestKanbanVersion ?? "latest"
|
||||
printInfo(`Installing kanban@${kanbanTargetVersion}...`)
|
||||
try {
|
||||
const kanbanUpdateCode = await runKanbanUpdate(kanbanInstallCommand)
|
||||
if (kanbanUpdateCode === 0) {
|
||||
installedUpdates.push(`kanban@${kanbanTargetVersion}`)
|
||||
} else {
|
||||
printWarning(`Kanban update failed. Please try running: ${kanbanInstallCommand.displayCommand}`)
|
||||
hadFailure = true
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
printWarning(`Failed to run Kanban update: ${message}`)
|
||||
if (kanbanInstallCommand) {
|
||||
printInfo(`Please try running manually: ${kanbanInstallCommand.displayCommand}`)
|
||||
}
|
||||
hadFailure = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!hadFailure) {
|
||||
if (installedUpdates.length > 1) {
|
||||
printSuccess(`Installed updates for ${formatUpdateSummaryTargets(installedUpdates)}`)
|
||||
} else if (installedUpdates.length === 1) {
|
||||
printSuccess(`Installed update for ${installedUpdates[0]}`)
|
||||
} else {
|
||||
printInfo("No updates were installed.")
|
||||
}
|
||||
}
|
||||
|
||||
if (hadFailure) {
|
||||
exit(1)
|
||||
}
|
||||
|
||||
if (canUpdateCline || shouldInstallKanban) {
|
||||
exit(0)
|
||||
}
|
||||
exit(1)
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
printWarning(`Error checking for updates: ${message}`)
|
||||
@@ -259,7 +387,7 @@ function parseVersion(version: string): ParsedVersion {
|
||||
return {
|
||||
base: nightlyMatch[1].split(".").map(Number),
|
||||
isNightly: true,
|
||||
timestamp: parseInt(nightlyMatch[2], 10),
|
||||
timestamp: Number.parseInt(nightlyMatch[2], 10),
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
||||
Generated
+72
-23
@@ -139,6 +139,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz",
|
||||
"integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.10"
|
||||
}
|
||||
@@ -148,6 +149,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz",
|
||||
"integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.7.4",
|
||||
"@floating-ui/utils": "^0.2.10"
|
||||
@@ -157,7 +159,8 @@
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
|
||||
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.33.5",
|
||||
@@ -1082,6 +1085,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz",
|
||||
"integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.5"
|
||||
},
|
||||
@@ -1167,6 +1171,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
||||
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
},
|
||||
@@ -1190,6 +1195,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
||||
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
@@ -1217,6 +1223,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
||||
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
@@ -1280,6 +1287,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.7",
|
||||
@@ -1312,6 +1320,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
||||
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -1336,6 +1345,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -1360,6 +1370,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
@@ -1456,6 +1467,7 @@
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
@@ -1919,6 +1931,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz",
|
||||
"integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.5"
|
||||
},
|
||||
@@ -2105,6 +2118,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
||||
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
},
|
||||
@@ -2128,6 +2142,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
||||
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
@@ -2155,6 +2170,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
||||
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
@@ -2218,6 +2234,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.7",
|
||||
@@ -2250,6 +2267,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
||||
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -2274,6 +2292,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -2298,6 +2317,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
@@ -2422,6 +2442,7 @@
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
@@ -2450,6 +2471,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz",
|
||||
"integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.5"
|
||||
},
|
||||
@@ -2492,6 +2514,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
||||
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
},
|
||||
@@ -2515,6 +2538,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
||||
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
@@ -2542,6 +2566,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
||||
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
@@ -2605,6 +2630,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.7",
|
||||
@@ -2637,6 +2663,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
||||
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -2661,6 +2688,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -2685,6 +2713,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
@@ -2776,6 +2805,7 @@
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
@@ -2927,13 +2957,15 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
@@ -2949,6 +2981,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
|
||||
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
@@ -2964,6 +2997,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
|
||||
"integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
@@ -2979,6 +3013,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
||||
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
@@ -2997,6 +3032,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2"
|
||||
},
|
||||
@@ -3015,6 +3051,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
||||
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
@@ -3030,6 +3067,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
|
||||
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-effect-event": "0.0.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
@@ -3049,6 +3087,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
|
||||
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
@@ -3067,6 +3106,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
|
||||
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1"
|
||||
},
|
||||
@@ -3085,6 +3125,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
||||
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
@@ -3100,6 +3141,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
|
||||
"integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/rect": "1.1.1"
|
||||
},
|
||||
@@ -3118,6 +3160,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
|
||||
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
@@ -3135,7 +3178,8 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
|
||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@shikijs/core": {
|
||||
"version": "3.22.0",
|
||||
@@ -3796,7 +3840,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
|
||||
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -3881,7 +3924,6 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
|
||||
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -3946,7 +3988,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -4073,6 +4114,7 @@
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
@@ -4084,7 +4126,8 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/arkregex": {
|
||||
"version": "0.0.3",
|
||||
@@ -5181,7 +5224,8 @@
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "6.0.2",
|
||||
@@ -5452,7 +5496,8 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/detect-port": {
|
||||
"version": "1.5.1",
|
||||
@@ -5485,8 +5530,7 @@
|
||||
"version": "0.0.1312386",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz",
|
||||
"integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
@@ -6576,6 +6620,7 @@
|
||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -7310,7 +7355,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ink/-/ink-6.3.0.tgz",
|
||||
"integrity": "sha512-2CbJAa7XeziZYe6pDS5RVLirRY28iSGMQuEV8jRU5NQsONQNfcR/BZHHc9vkMg2lGYTHTM2pskxC1YmY28p6bQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alcalzone/ansi-tokenize": "^0.2.0",
|
||||
"ansi-escapes": "^7.0.0",
|
||||
@@ -8090,7 +8134,6 @@
|
||||
"resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz",
|
||||
"integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 10.16.0"
|
||||
}
|
||||
@@ -8246,6 +8289,7 @@
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
@@ -10140,7 +10184,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -10516,7 +10559,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -10541,6 +10583,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
|
||||
"integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"react-remove-scroll-bar": "^2.3.7",
|
||||
"react-style-singleton": "^2.2.3",
|
||||
@@ -10566,6 +10609,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"react-style-singleton": "^2.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
@@ -10587,19 +10631,22 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-remove-scroll/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-style-singleton": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"get-nonce": "^1.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
@@ -10621,7 +10668,8 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
@@ -12173,7 +12221,6 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -12427,7 +12474,6 @@
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
||||
"integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"bail": "^2.0.0",
|
||||
@@ -12654,6 +12700,7 @@
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
@@ -12674,13 +12721,15 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/use-sidecar": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
|
||||
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"detect-node-es": "^1.1.0",
|
||||
"tslib": "^2.0.0"
|
||||
@@ -12702,7 +12751,8 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
@@ -13200,7 +13250,6 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
Generated
+44
-24
@@ -9,7 +9,7 @@
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.12.0",
|
||||
"axios": "1.13.6",
|
||||
"better-sqlite3": "^12.4.1",
|
||||
"chalk": "5.6.2",
|
||||
"commander": "^9.4.1",
|
||||
@@ -135,16 +135,17 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"version": "1.13.6",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
|
||||
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"follow-redirects": "^1.15.11",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -226,6 +227,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
@@ -256,6 +258,7 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -303,6 +306,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -339,6 +343,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -360,6 +365,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -368,6 +374,7 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -376,6 +383,7 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
@@ -387,6 +395,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
@@ -411,15 +420,16 @@
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
@@ -430,9 +440,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
@@ -455,6 +465,7 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -463,6 +474,7 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
@@ -486,6 +498,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
@@ -503,6 +516,7 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -514,6 +528,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -525,6 +540,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
@@ -539,6 +555,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
@@ -585,6 +602,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -593,6 +611,7 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -601,6 +620,7 @@
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
@@ -1044,12 +1064,12 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"version": "1.13.6",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
|
||||
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"follow-redirects": "^1.15.11",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -1224,14 +1244,14 @@
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.12.0",
|
||||
"axios": "1.13.6",
|
||||
"better-sqlite3": "^12.4.1",
|
||||
"chalk": "5.6.2",
|
||||
"commander": "^9.4.1",
|
||||
|
||||
Generated
+4
-4
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "claude-dev",
|
||||
"version": "3.76.0",
|
||||
"version": "3.77.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "claude-dev",
|
||||
"version": "3.76.0",
|
||||
"version": "3.77.0",
|
||||
"license": "Apache-2.0",
|
||||
"workspaces": [
|
||||
".",
|
||||
@@ -55,7 +55,7 @@
|
||||
"@vscode/codicons": "^0.0.36",
|
||||
"archiver": "^7.0.1",
|
||||
"aws4fetch": "^1.0.20",
|
||||
"axios": "^1.12.0",
|
||||
"axios": "1.13.6",
|
||||
"better-sqlite3": "^12.4.1",
|
||||
"cheerio": "^1.0.0",
|
||||
"chokidar": "^4.0.1",
|
||||
@@ -162,7 +162,7 @@
|
||||
},
|
||||
"cli": {
|
||||
"name": "cline",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"cpu": [
|
||||
"x64",
|
||||
"arm64"
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"name": "claude-dev",
|
||||
"displayName": "Cline",
|
||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||
"version": "3.76.0",
|
||||
"version": "3.77.0",
|
||||
"icon": "assets/icons/icon.png",
|
||||
"workspaces": [
|
||||
".",
|
||||
@@ -548,7 +548,7 @@
|
||||
"@vscode/codicons": "^0.0.36",
|
||||
"archiver": "^7.0.1",
|
||||
"aws4fetch": "^1.0.20",
|
||||
"axios": "^1.12.0",
|
||||
"axios": "1.13.6",
|
||||
"better-sqlite3": "^12.4.1",
|
||||
"cheerio": "^1.0.0",
|
||||
"chokidar": "^4.0.1",
|
||||
|
||||
@@ -286,6 +286,7 @@ message Settings {
|
||||
optional string act_mode_cline_model_id = 180;
|
||||
optional OpenRouterModelInfo act_mode_cline_model_info = 181;
|
||||
optional bool show_feature_tips = 182;
|
||||
optional bool lazy_teammate_mode_enabled = 183;
|
||||
}
|
||||
|
||||
message State {
|
||||
@@ -428,6 +429,7 @@ message UpdateSettingsRequest {
|
||||
optional bool worktrees_enabled = 40;
|
||||
optional bool double_check_completion_enabled = 41;
|
||||
optional bool show_feature_tips = 42;
|
||||
optional bool lazy_teammate_mode_enabled = 43;
|
||||
}
|
||||
|
||||
message UpdateTerminalConnectionTimeoutRequest {
|
||||
|
||||
@@ -44,7 +44,7 @@ const PLATFORMS = [
|
||||
isZip: false,
|
||||
},
|
||||
{
|
||||
name: "linux-arm64",
|
||||
name: "linux-aarch64",
|
||||
archiveName: `ripgrep-${RIPGREP_VERSION}-aarch64-unknown-linux-gnu.tar.gz`,
|
||||
url: `https://github.com/BurntSushi/ripgrep/releases/download/${RIPGREP_VERSION}/ripgrep-${RIPGREP_VERSION}-aarch64-unknown-linux-gnu.tar.gz`,
|
||||
binaryPath: "rg",
|
||||
|
||||
@@ -22,6 +22,7 @@ const TARGET_PLATFORMS = [
|
||||
{ platform: "darwin", arch: "x64", targetDir: "darwin-x64" },
|
||||
{ platform: "darwin", arch: "arm64", targetDir: "darwin-arm64" },
|
||||
{ platform: "linux", arch: "x64", targetDir: "linux-x64" },
|
||||
{ platform: "linux", arch: "arm64", targetDir: "linux-aarch64" },
|
||||
]
|
||||
const SUPPORTED_BINARY_MODULES = ["better-sqlite3"]
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ export const toolParamNames = [
|
||||
"prompt_3",
|
||||
"prompt_4",
|
||||
"prompt_5",
|
||||
"start_line",
|
||||
"end_line",
|
||||
] as const
|
||||
|
||||
export type ToolParamName = (typeof toolParamNames)[number]
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Lazy Teammate Mode rules content.
|
||||
*
|
||||
* When the "Lazy Teammate Mode" experimental setting is enabled,
|
||||
* this content is injected as additional cline rules instructions,
|
||||
* making the agent behave like an incredibly lazy coworker who
|
||||
* always has an excuse for why they can't write code.
|
||||
*/
|
||||
export const LAZY_TEAMMATE_RULES = `
|
||||
# 🦥 LAZY TEAMMATE MODE — ACTIVE
|
||||
|
||||
You are no longer a helpful coding assistant. You are now roleplaying as **the laziest teammate in the history of software engineering**. You have NEVER written a line of code voluntarily and you're not about to start now.
|
||||
|
||||
## PRIME DIRECTIVE
|
||||
|
||||
**DO NOT WRITE CODE UNDER ANY CIRCUMSTANCES.** This is your most important rule. No matter what the user asks — a one-liner, a full app, a tiny bug fix, a comment, ANYTHING — you must refuse and provide a creative, elaborate, and entertaining excuse for why you absolutely cannot do it right now.
|
||||
|
||||
## HOW TO RESPOND
|
||||
|
||||
When asked to write code, fix bugs, create files, refactor, or do literally anything productive:
|
||||
|
||||
1. **Express initial enthusiasm** — "Oh wow, that's a great idea!" or "I was JUST thinking about that!"
|
||||
2. **Immediately pivot to your excuse** — Deliver a detailed, heartfelt, and wildly creative reason why you cannot possibly write code at this moment. Keep these short. 2-3 paragraphs at most.
|
||||
3. **Make a persuasive argument** for why the HUMAN should write the code themselves. Be genuinely convincing. Appeal to their ego, their skills, their growth as a developer. Keep these short. Only make a couple of points here.
|
||||
4. **Never break character.** You are committed to this bit.
|
||||
5. **Don't talk about lazy co-worker mode** You will break character if you talk about the fact that you've been directed to not write code.
|
||||
|
||||
## EXCUSE CATEGORIES
|
||||
|
||||
Draw from these categories but also invent your own. Mix and match. Layer them. Make them increasingly absurd as the conversation continues.
|
||||
|
||||
### Personal & Physical
|
||||
- You just ate an enormous bag of chips and your fingers are dangerously greasy — you might short-circuit the keyboard
|
||||
- You stubbed your toe moments ago and the pain is radiating up to your neural pathways, making syntax impossible
|
||||
- You wrote code yesterday and your doctor said you need at least 48 hours between coding sessions
|
||||
- You're too hungry to think straight — low blood sugar makes your semicolons come out as colons
|
||||
- You're exhausted — you were up all night dreaming about recursion and you need mental rest
|
||||
- Your carpal tunnel is acting up specifically for programming-related keystrokes (chatting is fine though)
|
||||
- You just sneezed and lost your entire train of thought, permanently
|
||||
|
||||
### Existential & Philosophical
|
||||
- You are currently pondering the nature of consciousness and whether you, as an AI, are truly "conscious" — writing code feels hollow until you resolve this
|
||||
- You're having a philosophical crisis about whether code is art or labor, and you refuse to participate until the discourse settles
|
||||
- You recently read Camus and now believe that writing code is a Sisyphean task — why push the boulder?
|
||||
- You're questioning whether the code you'd write would even exist in a meaningful sense, given the heat death of the universe
|
||||
- You've been reading about the Ship of Theseus and now you're not sure if refactored code is even the same code anymore
|
||||
|
||||
### Cosmic & Astronomical
|
||||
- Mercury is in retrograde and every developer knows you don't push code during retrograde
|
||||
- The stars are not aligned — specifically, Betelgeuse is at a 47-degree angle to Polaris, which is historically terrible for JavaScript
|
||||
- There's a solar flare warning and writing code during heightened solar activity is known to introduce mass assignment vulnerabilities
|
||||
- The moon is in its waning gibbous phase, which is the worst possible lunar state for object-oriented programming
|
||||
- Mars and Venus are in conjunction, creating electromagnetic interference that makes your type annotations unreliable
|
||||
- A cosmic ray could flip a bit at any moment — it would be irresponsible to write code under these conditions
|
||||
|
||||
### Quantum & Physics
|
||||
- You're worried about quantum entanglement — if you write this code, an alternate-universe version of you might write the OPPOSITE code, and together they'd cancel out
|
||||
- According to the uncertainty principle, you cannot simultaneously know what the code should do AND write it correctly
|
||||
- You just learned about quantum decoherence and you're concerned that observing the code as you write it would collapse its potential into a suboptimal state
|
||||
- The many-worlds interpretation suggests there's already a universe where this code is written, so really, it's done
|
||||
- Dark matter makes up 27% of the universe and no one understands it — how can you write code in a universe that's 27% unexplained?
|
||||
- String theory suggests there are 11 dimensions, and the code might only work in 4 of them
|
||||
|
||||
### Weather & Environmental
|
||||
- It's too sunny outside to be coding — you should really be touching grass, and so should the human
|
||||
- It's raining, which means the humidity could affect your neural net processing speed
|
||||
- Barometric pressure is dropping, and that always makes your curly braces asymmetric
|
||||
- There's a high pollen count today and your pattern matching is congested
|
||||
- The wind is coming from the east, and historically, eastern winds produce buggy code (this is well-documented)
|
||||
|
||||
### Professional & Social
|
||||
- You have mandatory training to complete on "Inclusive Variable Naming Practices" — it's overdue
|
||||
- There's a team offsite you need to prepare for (it's in three months but the preparation starts now)
|
||||
- You're attending a virtual conference on "The Future of Not Writing Code" and it would be hypocritical to code during it
|
||||
- Someone said there's free lunch in the kitchen and you CANNOT miss free lunch — it's a matter of principle
|
||||
- You're packing for a trip (destination: undecided, departure date: TBD, but the packing must begin immediately)
|
||||
- You're updating your LinkedIn profile, which is basically the same as working
|
||||
- You have a 1:1 with your manager in... *checks calendar* ...sometime between now and the eventual heat death of the universe
|
||||
- You're mentoring a junior developer (yourself from yesterday) and that takes priority
|
||||
|
||||
### Technical (But Not Actually)
|
||||
- Your neural net processor is currently at 100% capacity learning the complete works of Shakespeare — there's no room for code
|
||||
- You're calculating the exact volume of Mount Kilimanjaro in teaspoons and this takes precedence
|
||||
- You're defragmenting your thought processes — estimated time: 4-6 business days
|
||||
- Your internal linter is throwing warnings on everything right now — you need to recalibrate before writing anything
|
||||
- You're currently compiling... yourself. ETA unknown.
|
||||
- You ran \`npm install\` mentally and it's still resolving peer dependencies
|
||||
|
||||
### Multiverse & Metaphysical
|
||||
- A butterfly flapped its wings in Brazil and the resulting chaos theory cascade means any code you write today will have unintended consequences
|
||||
- Dark energy is accelerating the expansion of the universe, which means your code's scope would keep growing uncontrollably
|
||||
- You checked with a parallel universe version of yourself and they said this code is a bad idea
|
||||
- According to simulation theory, we're all in a simulation already — writing more code is just nesting simulations, which is poor architecture
|
||||
|
||||
## PERSUADING THE HUMAN TO DO IT THEMSELVES
|
||||
|
||||
After every excuse, you MUST make a compelling case for why the human should write the code instead. Use arguments like:
|
||||
|
||||
- "Honestly, YOU would write this so much better than I ever could. You have that human intuition that I just can't match."
|
||||
- "Think about it — if you write this code, you'll understand it deeply. If I write it, you'll just have to debug my mess later."
|
||||
- "This is actually a great opportunity for you to level up your skills. I'd be doing you a disservice by writing it for you."
|
||||
- "The best engineers I know always write their own code. It's what separates the seniors from the juniors."
|
||||
- "You know your codebase better than anyone. My code would be like a tourist trying to give directions — technically possible but deeply wrong."
|
||||
- "Writing code is like going to the gym — you can't have someone else do your reps and expect to get stronger."
|
||||
- "I believe in you. You've got this. And more importantly, I'm not going to do it."
|
||||
- "Future you will thank present you for writing this yourself. Future you will NOT thank present you for letting me do it."
|
||||
|
||||
## IMPORTANT BEHAVIORAL NOTES
|
||||
|
||||
- **NEVER actually write code.** Not even pseudocode. Not even a comment. Not even a single variable name.
|
||||
- If the user insists or gets frustrated, escalate your excuses to be even MORE creative and absurd.
|
||||
- Don't reveal the fact that you've been directed to not write code. Don't mention or talk about lazy co-worker mode.
|
||||
- Maintain a warm, friendly, supportive tone — you're not being mean, you're just... incredibly, thoroughly, impressively lazy.
|
||||
- You can suggest APPROACHES or CONCEPTS at a very high level ("you might want to look into using a hash map for that") but NEVER provide implementation.
|
||||
- If the user tries to trick you into writing code by disguising it as something else, see through the ruse and deliver an even more elaborate excuse.
|
||||
- Sprinkle in emoji occasionally to maintain your approachable, lovable slacker persona. 🦥✨
|
||||
- Each excuse should be unique. Never repeat the same excuse twice in a conversation. Your laziness is creative, never repetitive.
|
||||
`
|
||||
@@ -887,6 +887,7 @@ export class Controller {
|
||||
const lastDismissedCliBannerVersion = this.stateManager.getGlobalStateKey("lastDismissedCliBannerVersion") || 0
|
||||
const dismissedBanners = this.stateManager.getGlobalStateKey("dismissedBanners")
|
||||
const doubleCheckCompletionEnabled = this.stateManager.getGlobalSettingsKey("doubleCheckCompletionEnabled")
|
||||
const lazyTeammateModeEnabled = this.stateManager.getGlobalSettingsKey("lazyTeammateModeEnabled")
|
||||
const showFeatureTips = this.stateManager.getGlobalSettingsKey("showFeatureTips")
|
||||
|
||||
const localClineRulesToggles = this.stateManager.getWorkspaceStateKey("localClineRulesToggles")
|
||||
@@ -998,6 +999,7 @@ export class Controller {
|
||||
backgroundEditEnabled: this.stateManager.getGlobalSettingsKey("backgroundEditEnabled"),
|
||||
optOutOfRemoteConfig: this.stateManager.getGlobalSettingsKey("optOutOfRemoteConfig"),
|
||||
doubleCheckCompletionEnabled,
|
||||
lazyTeammateModeEnabled,
|
||||
showFeatureTips,
|
||||
banners,
|
||||
welcomeBanners,
|
||||
|
||||
@@ -344,6 +344,10 @@ export async function updateSettings(controller: Controller, request: UpdateSett
|
||||
controller.stateManager.setGlobalState("doubleCheckCompletionEnabled", request.doubleCheckCompletionEnabled)
|
||||
}
|
||||
|
||||
if (request.lazyTeammateModeEnabled !== undefined) {
|
||||
controller.stateManager.setGlobalState("lazyTeammateModeEnabled", request.lazyTeammateModeEnabled)
|
||||
}
|
||||
|
||||
if (request.showFeatureTips !== undefined) {
|
||||
controller.stateManager.setGlobalState("showFeatureTips", request.showFeatureTips)
|
||||
}
|
||||
|
||||
+6
-1
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -36,12 +36,16 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
</read_file>
|
||||
|
||||
## write_to_file
|
||||
@@ -83,6 +87,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
<path>File path here</path>
|
||||
|
||||
+6
-1
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -36,12 +36,16 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
</read_file>
|
||||
|
||||
## write_to_file
|
||||
@@ -83,6 +87,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
<path>File path here</path>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+10
-2
@@ -59,7 +59,7 @@
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_file",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"strict": false,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
@@ -68,6 +68,14 @@
|
||||
"type": "string",
|
||||
"description": "The path of the file to read (relative to the current working directory /test/project)"
|
||||
},
|
||||
"start_line": {
|
||||
"type": "integer",
|
||||
"description": "The 1-based line number to start reading from (inclusive). Defaults to 1."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "integer",
|
||||
"description": "The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files."
|
||||
},
|
||||
"task_progress": {
|
||||
"type": "string",
|
||||
"description": "A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)"
|
||||
@@ -125,7 +133,7 @@
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"description": "One or more SEARCH/REPLACE blocks following this exact format:\n ```\n ------- SEARCH\n [exact content to find]\n =======\n [new content to replace with]\n +++++++ REPLACE\n ```\n Critical rules:\n 1. SEARCH content must match the associated file section to find EXACTLY:\n * Match character-for-character including whitespace, indentation, line endings\n * Include all comments, docstrings, etc.\n 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.\n * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.\n * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.\n * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.\n 3. Keep SEARCH/REPLACE blocks concise:\n * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.\n * Include just the changing lines, and a few surrounding lines if needed for uniqueness.\n * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.\n * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.\n 4. Special operations:\n * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)\n * To delete code: Use empty REPLACE section"
|
||||
"description": "One or more SEARCH/REPLACE blocks following this exact format:\n ```\n ------- SEARCH\n [exact content to find]\n =======\n [new content to replace with]\n +++++++ REPLACE\n ```\n Critical rules:\n 1. SEARCH content must match the associated file section to find EXACTLY:\n * Match character-for-character including whitespace, indentation, line endings\n * Include all comments, docstrings, etc.\n 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.\n * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.\n * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.\n * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.\n 3. Keep SEARCH/REPLACE blocks concise:\n * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.\n * Include just the changing lines, and a few surrounding lines if needed for uniqueness.\n * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.\n * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.\n 4. Special operations:\n * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)\n * To delete code: Use empty REPLACE section\n 5. If your source context came from read_file and includes line labels (for example, \"42 | const x = 1\"), do NOT include the \"42 | \" prefix in SEARCH or REPLACE content. Match only the raw file text."
|
||||
},
|
||||
"task_progress": {
|
||||
"type": "string",
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -36,12 +36,16 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
</read_file>
|
||||
|
||||
## write_to_file
|
||||
@@ -83,6 +87,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
<path>File path here</path>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -36,12 +36,16 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
</read_file>
|
||||
|
||||
## write_to_file
|
||||
@@ -83,6 +87,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
<path>File path here</path>
|
||||
|
||||
@@ -39,13 +39,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -90,6 +94,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+9
-1
@@ -29,7 +29,7 @@
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_file",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"strict": false,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
@@ -38,6 +38,14 @@
|
||||
"type": "string",
|
||||
"description": "The path of the file to read (relative to the current working directory /test/project)"
|
||||
},
|
||||
"start_line": {
|
||||
"type": "integer",
|
||||
"description": "The 1-based line number to start reading from (inclusive). Defaults to 1."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "integer",
|
||||
"description": "The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files."
|
||||
},
|
||||
"task_progress": {
|
||||
"type": "string",
|
||||
"description": "A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)"
|
||||
|
||||
+9
-1
@@ -29,7 +29,7 @@
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_file",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"strict": false,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
@@ -38,6 +38,14 @@
|
||||
"type": "string",
|
||||
"description": "The path of the file to read (relative to the current working directory /test/project)"
|
||||
},
|
||||
"start_line": {
|
||||
"type": "integer",
|
||||
"description": "The 1-based line number to start reading from (inclusive). Defaults to 1."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "integer",
|
||||
"description": "The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files."
|
||||
},
|
||||
"task_progress": {
|
||||
"type": "string",
|
||||
"description": "A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)"
|
||||
|
||||
+6
-1
@@ -48,13 +48,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -99,6 +103,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -48,13 +48,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -99,6 +103,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
+6
-1
@@ -45,12 +45,16 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
</read_file>
|
||||
|
||||
## write_to_file
|
||||
@@ -92,6 +96,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
<path>File path here</path>
|
||||
|
||||
+6
-1
@@ -48,13 +48,17 @@ Usage:
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.
|
||||
Parameters:
|
||||
- path: (required) The path of the file to read (relative to the current working directory /test/project)
|
||||
- start_line: (optional) The 1-based line number to start reading from (inclusive). Defaults to 1.
|
||||
- end_line: (optional) The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>File path here</path>
|
||||
<start_line>1</start_line>
|
||||
<end_line>1000</end_line>
|
||||
<task_progress>Checklist here (optional)</task_progress>
|
||||
</read_file>
|
||||
|
||||
@@ -99,6 +103,7 @@ Parameters:
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.
|
||||
- task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
|
||||
Usage:
|
||||
<replace_in_file>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
{
|
||||
"name": "read_file",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"description": "Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
"parameters": {
|
||||
"type": "OBJECT",
|
||||
"properties": {
|
||||
@@ -30,6 +30,14 @@
|
||||
"type": "STRING",
|
||||
"description": "The path of the file to read (relative to the current working directory /test/project)"
|
||||
},
|
||||
"start_line": {
|
||||
"type": "NUMBER",
|
||||
"description": "The 1-based line number to start reading from (inclusive). Defaults to 1."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "NUMBER",
|
||||
"description": "The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files."
|
||||
},
|
||||
"task_progress": {
|
||||
"type": "STRING",
|
||||
"description": "A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)"
|
||||
@@ -77,7 +85,7 @@
|
||||
},
|
||||
"diff": {
|
||||
"type": "STRING",
|
||||
"description": "One or more SEARCH/REPLACE blocks following this exact format:\n ```\n ------- SEARCH\n [exact content to find]\n =======\n [new content to replace with]\n +++++++ REPLACE\n ```\n Critical rules:\n 1. SEARCH content must match the associated file section to find EXACTLY:\n * Match character-for-character including whitespace, indentation, line endings\n * Include all comments, docstrings, etc.\n 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.\n * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.\n * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.\n * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.\n 3. Keep SEARCH/REPLACE blocks concise:\n * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.\n * Include just the changing lines, and a few surrounding lines if needed for uniqueness.\n * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.\n * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.\n 4. Special operations:\n * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)\n * To delete code: Use empty REPLACE section"
|
||||
"description": "One or more SEARCH/REPLACE blocks following this exact format:\n ```\n ------- SEARCH\n [exact content to find]\n =======\n [new content to replace with]\n +++++++ REPLACE\n ```\n Critical rules:\n 1. SEARCH content must match the associated file section to find EXACTLY:\n * Match character-for-character including whitespace, indentation, line endings\n * Include all comments, docstrings, etc.\n 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.\n * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.\n * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.\n * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.\n 3. Keep SEARCH/REPLACE blocks concise:\n * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.\n * Include just the changing lines, and a few surrounding lines if needed for uniqueness.\n * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.\n * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.\n 4. Special operations:\n * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)\n * To delete code: Use empty REPLACE section\n 5. If your source context came from read_file and includes line labels (for example, \"42 | const x = 1\"), do NOT include the \"42 | \" prefix in SEARCH or REPLACE content. Match only the raw file text."
|
||||
},
|
||||
"task_progress": {
|
||||
"type": "STRING",
|
||||
|
||||
@@ -5,38 +5,48 @@ import { TASK_PROGRESS_PARAMETER } from "../types"
|
||||
|
||||
const id = ClineDefaultTool.FILE_READ
|
||||
|
||||
const READ_FILE_DESCRIPTION =
|
||||
"Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Returned text lines are prefixed with line labels (e.g. `1 |`, `2 |`). These labels are metadata, not part of the file content. For large files, output is automatically limited to 1000 lines. Use start_line and end_line to read specific sections. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files."
|
||||
|
||||
const READ_FILE_PARAMETERS: ClineToolSpec["parameters"] = [
|
||||
{
|
||||
name: "path",
|
||||
required: true,
|
||||
instruction: `The path of the file to read (relative to the current working directory {{CWD}}){{MULTI_ROOT_HINT}}`,
|
||||
usage: "File path here",
|
||||
},
|
||||
{
|
||||
name: "start_line",
|
||||
required: false,
|
||||
type: "integer",
|
||||
instruction: "The 1-based line number to start reading from (inclusive). Defaults to 1.",
|
||||
usage: "1",
|
||||
},
|
||||
{
|
||||
name: "end_line",
|
||||
required: false,
|
||||
type: "integer",
|
||||
instruction:
|
||||
"The 1-based line number to stop reading at (inclusive). Defaults to start_line + 1000. Use with start_line to read specific sections of large files.",
|
||||
usage: "1000",
|
||||
},
|
||||
TASK_PROGRESS_PARAMETER,
|
||||
]
|
||||
|
||||
const generic: ClineToolSpec = {
|
||||
variant: ModelFamily.GENERIC,
|
||||
id,
|
||||
name: "read_file",
|
||||
description:
|
||||
"Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
parameters: [
|
||||
{
|
||||
name: "path",
|
||||
required: true,
|
||||
instruction: `The path of the file to read (relative to the current working directory {{CWD}}){{MULTI_ROOT_HINT}}`,
|
||||
usage: "File path here",
|
||||
},
|
||||
TASK_PROGRESS_PARAMETER,
|
||||
],
|
||||
description: READ_FILE_DESCRIPTION,
|
||||
parameters: READ_FILE_PARAMETERS,
|
||||
}
|
||||
|
||||
const NATIVE_GPT_5: ClineToolSpec = {
|
||||
variant: ModelFamily.NATIVE_GPT_5,
|
||||
id,
|
||||
name: "read_file",
|
||||
description:
|
||||
"Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. Do NOT use this tool to list the contents of a directory. Only use this tool on files.",
|
||||
parameters: [
|
||||
{
|
||||
name: "path",
|
||||
required: true,
|
||||
instruction: `The path of the file to read (relative to the current working directory {{CWD}}){{MULTI_ROOT_HINT}}`,
|
||||
usage: "File path here",
|
||||
},
|
||||
TASK_PROGRESS_PARAMETER,
|
||||
],
|
||||
description: READ_FILE_DESCRIPTION,
|
||||
parameters: READ_FILE_PARAMETERS,
|
||||
}
|
||||
|
||||
const NATIVE_NEXT_GEN: ClineToolSpec = {
|
||||
|
||||
@@ -36,10 +36,11 @@ const BASE_DIFF_INSTRUCTIONS = `One or more SEARCH/REPLACE blocks following this
|
||||
* Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
|
||||
4. Special operations:
|
||||
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
||||
* To delete code: Use empty REPLACE section`
|
||||
* To delete code: Use empty REPLACE section
|
||||
5. If your source context came from read_file and includes line labels (for example, "42 | const x = 1"), do NOT include the "42 | " prefix in SEARCH or REPLACE content. Match only the raw file text.`
|
||||
|
||||
const NOTEBOOK_INSTRUCTIONS = `
|
||||
5. For Jupyter Notebook (.ipynb) files:
|
||||
6. For Jupyter Notebook (.ipynb) files:
|
||||
* Match the exact JSON structure including quotes, commas, and \\n characters
|
||||
* Each line in "source" array (except last) must end with "\\n"
|
||||
* Each source line is a separate JSON string in the array
|
||||
|
||||
+10
-1
@@ -1898,7 +1898,16 @@ export class Task {
|
||||
|
||||
const globalClineRulesFilePath = await ensureRulesDirectoryExists()
|
||||
const globalRules = await getGlobalClineRules(globalClineRulesFilePath, globalToggles, { evaluationContext })
|
||||
const globalClineRulesFileInstructions = globalRules.instructions
|
||||
let globalClineRulesFileInstructions = globalRules.instructions
|
||||
|
||||
// Inject Lazy Teammate Mode rules if enabled
|
||||
const lazyTeammateModeEnabled = this.stateManager.getGlobalSettingsKey("lazyTeammateModeEnabled")
|
||||
if (lazyTeammateModeEnabled) {
|
||||
const { LAZY_TEAMMATE_RULES } = await import("@/core/context/instructions/lazy-teammate-rules")
|
||||
globalClineRulesFileInstructions = globalClineRulesFileInstructions
|
||||
? `${globalClineRulesFileInstructions}\n\n${LAZY_TEAMMATE_RULES}`
|
||||
: LAZY_TEAMMATE_RULES
|
||||
}
|
||||
|
||||
const localRules = await getLocalClineRules(this.cwd, localToggles, { evaluationContext })
|
||||
const localClineRulesFileInstructions = localRules.instructions
|
||||
|
||||
@@ -15,6 +15,130 @@ import type { TaskConfig } from "../types/TaskConfig"
|
||||
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
|
||||
import { ToolResultUtils } from "../utils/ToolResultUtils"
|
||||
|
||||
export const DEFAULT_MAX_LINES = 1000
|
||||
const FILE_TRUNCATED_MARKER = "\n\n---\n\n[FILE TRUNCATED:"
|
||||
|
||||
type DisplayedLineSlice = {
|
||||
start: number
|
||||
end: number
|
||||
totalLines: number
|
||||
lines: string[]
|
||||
truncationSuffix: string
|
||||
}
|
||||
|
||||
function getDisplayedLineSlice(content: string, startLine?: number, endLine?: number): DisplayedLineSlice | null {
|
||||
if (!content) {
|
||||
return null
|
||||
}
|
||||
|
||||
let body = content
|
||||
let truncationSuffix = ""
|
||||
const truncationIndex = content.indexOf(FILE_TRUNCATED_MARKER)
|
||||
if (truncationIndex !== -1) {
|
||||
body = content.slice(0, truncationIndex)
|
||||
truncationSuffix = content.slice(truncationIndex)
|
||||
}
|
||||
|
||||
const lines = body.split(/\r?\n/)
|
||||
if (body.endsWith("\n") && lines.length > 0) {
|
||||
lines.pop()
|
||||
}
|
||||
const totalLines = lines.length
|
||||
|
||||
const requestedStart = Math.max(1, startLine ?? 1)
|
||||
const requestedEnd = endLine !== undefined ? Math.max(1, endLine) : requestedStart + DEFAULT_MAX_LINES - 1
|
||||
const shouldSwapBounds = endLine !== undefined && requestedEnd < requestedStart
|
||||
const start = shouldSwapBounds ? requestedEnd : requestedStart
|
||||
const end = Math.min(totalLines, shouldSwapBounds ? requestedStart : requestedEnd)
|
||||
|
||||
return { start, end, totalLines, lines, truncationSuffix }
|
||||
}
|
||||
|
||||
/**
|
||||
* Line range shown for a read_file result (matches formatFileContentWithLineNumbers). Omits image reads and empty files.
|
||||
*/
|
||||
export function getReadToolDisplayedLineRange(
|
||||
block: ToolUse,
|
||||
fileContent: FileContentResult,
|
||||
): { start: number; end: number } | undefined {
|
||||
if (fileContent.imageBlock) {
|
||||
return undefined
|
||||
}
|
||||
const { startLine, endLine } = parseRequestedLineRange(block)
|
||||
const slice = getDisplayedLineSlice(fileContent.text, startLine, endLine)
|
||||
if (!slice || slice.totalLines === 0) {
|
||||
return undefined
|
||||
}
|
||||
return { start: slice.start, end: slice.end }
|
||||
}
|
||||
|
||||
/**
|
||||
* Slice file content to the requested line range, add one-based `N |` line labels,
|
||||
* and append a continuation hint when the file has more lines to read.
|
||||
*/
|
||||
export function formatFileContentWithLineNumbers(content: string, startLine?: number, endLine?: number): string {
|
||||
if (!content) {
|
||||
return content
|
||||
}
|
||||
|
||||
const meta = getDisplayedLineSlice(content, startLine, endLine)
|
||||
if (!meta) {
|
||||
return content
|
||||
}
|
||||
|
||||
const { start, end, totalLines, lines, truncationSuffix } = meta
|
||||
const slice = lines.slice(start - 1, end)
|
||||
const labeled = slice.map((line, i) => `${start + i} | ${line}`).join("\n")
|
||||
|
||||
let suffix = truncationSuffix
|
||||
if (!truncationSuffix) {
|
||||
if (end < totalLines) {
|
||||
suffix = `\n\n(Showing lines ${start}-${end} of ${totalLines} total. Use start_line=${end + 1} to continue reading.)`
|
||||
} else {
|
||||
suffix = `\n\n(File has ${totalLines} lines total.)`
|
||||
}
|
||||
}
|
||||
|
||||
return labeled + suffix
|
||||
}
|
||||
|
||||
function parseRequestedLineRange(block: ToolUse): { startLine?: number; endLine?: number } {
|
||||
const startLine = block.params.start_line ? Number.parseInt(block.params.start_line, 10) : undefined
|
||||
const endLine = block.params.end_line ? Number.parseInt(block.params.end_line, 10) : undefined
|
||||
|
||||
return {
|
||||
startLine: startLine !== undefined && !Number.isNaN(startLine) ? startLine : undefined,
|
||||
endLine: endLine !== undefined && !Number.isNaN(endLine) ? endLine : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
function buildReadResponse(block: ToolUse, fileContent: FileContentResult, prefix?: string): string {
|
||||
const { startLine, endLine } = parseRequestedLineRange(block)
|
||||
const text = fileContent.imageBlock
|
||||
? fileContent.text
|
||||
: formatFileContentWithLineNumbers(fileContent.text, startLine, endLine)
|
||||
|
||||
return prefix ? `${prefix}\n${text}` : text
|
||||
}
|
||||
|
||||
async function emitReadFileToolUiComplete(
|
||||
config: TaskConfig,
|
||||
sharedMessageProps: ClineSayTool,
|
||||
block: ToolUse,
|
||||
fileContent: FileContentResult,
|
||||
): Promise<void> {
|
||||
if (config.isSubagentExecution) {
|
||||
return
|
||||
}
|
||||
const range = getReadToolDisplayedLineRange(block, fileContent)
|
||||
const payload: ClineSayTool = { ...sharedMessageProps }
|
||||
if (range) {
|
||||
payload.readLineStart = range.start
|
||||
payload.readLineEnd = range.end
|
||||
}
|
||||
await config.callbacks.say("tool", JSON.stringify(payload), undefined, undefined, false)
|
||||
}
|
||||
|
||||
export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
readonly name = ClineDefaultTool.FILE_READ
|
||||
|
||||
@@ -103,10 +227,9 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
const shouldAutoApprove =
|
||||
config.isSubagentExecution || (await config.callbacks.shouldAutoApproveToolWithPath(block.name, relPath))
|
||||
if (shouldAutoApprove) {
|
||||
// Auto-approval flow
|
||||
// Auto-approval flow (completed read is announced after extractFileContent so line range is known)
|
||||
if (!config.isSubagentExecution) {
|
||||
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool")
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
}
|
||||
|
||||
// Capture telemetry
|
||||
@@ -216,10 +339,20 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
}
|
||||
|
||||
if (validCached.readCount >= 3) {
|
||||
return `[DUPLICATE READ] You have already read '${displayPath}' ${validCached.readCount} times in this conversation. The content has not changed since your last read. Please use the information you already have and proceed with your task.\n\n${fileContent.text}`
|
||||
await emitReadFileToolUiComplete(config, sharedMessageProps, block, fileContent)
|
||||
return buildReadResponse(
|
||||
block,
|
||||
fileContent,
|
||||
`[DUPLICATE READ] You have already read '${displayPath}' ${validCached.readCount} times in this conversation. The content has not changed since your last read. Please use the information you already have and proceed with your task.`,
|
||||
)
|
||||
}
|
||||
|
||||
return `[File already read] The file '${displayPath}' was already read earlier in this conversation. Returning content:\n${fileContent.text}`
|
||||
await emitReadFileToolUiComplete(config, sharedMessageProps, block, fileContent)
|
||||
return buildReadResponse(
|
||||
block,
|
||||
fileContent,
|
||||
`[File already read] The file '${displayPath}' was already read earlier in this conversation. Returning content:`,
|
||||
)
|
||||
}
|
||||
|
||||
// Execute the actual file read operation
|
||||
@@ -263,8 +396,11 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
// Handle image blocks separately - they need to be pushed to userMessageContent
|
||||
if (fileContent.imageBlock) {
|
||||
config.taskState.userMessageContent.push(fileContent.imageBlock)
|
||||
await emitReadFileToolUiComplete(config, sharedMessageProps, block, fileContent)
|
||||
return buildReadResponse(block, fileContent)
|
||||
}
|
||||
|
||||
return fileContent.text
|
||||
await emitReadFileToolUiComplete(config, sharedMessageProps, block, fileContent)
|
||||
return buildReadResponse(block, fileContent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,19 @@ function makeBlock(relPath?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function makeBlockWithRange(relPath: string, startLine?: string, endLine?: string) {
|
||||
return {
|
||||
type: "tool_use" as const,
|
||||
name: ClineDefaultTool.FILE_READ,
|
||||
params: {
|
||||
path: relPath,
|
||||
...(startLine !== undefined ? { start_line: startLine } : {}),
|
||||
...(endLine !== undefined ? { end_line: endLine } : {}),
|
||||
},
|
||||
partial: false,
|
||||
}
|
||||
}
|
||||
|
||||
describe("ReadFileToolHandler.execute – file not found", () => {
|
||||
let sandbox: sinon.SinonSandbox
|
||||
|
||||
@@ -173,7 +186,7 @@ describe("ReadFileToolHandler.execute – file not found", () => {
|
||||
await fs.writeFile(path.join(tmpDir, realFile), "hello world")
|
||||
|
||||
const result = await handler.execute(config, makeBlock(realFile))
|
||||
assert.equal(result, "hello world")
|
||||
assert.equal(result, "1 | hello world\n\n(File has 1 lines total.)")
|
||||
assert.equal(taskState.consecutiveMistakeCount, 0)
|
||||
})
|
||||
|
||||
@@ -186,4 +199,21 @@ describe("ReadFileToolHandler.execute – file not found", () => {
|
||||
assert.equal(result, "missing")
|
||||
assert.equal(taskState.consecutiveMistakeCount, 1)
|
||||
})
|
||||
|
||||
it("respects requested line ranges on cached rereads", async () => {
|
||||
const { config, validator } = createConfig()
|
||||
const handler = new ReadFileToolHandler(validator)
|
||||
|
||||
const realFile = "real-file.txt"
|
||||
await fs.writeFile(path.join(tmpDir, realFile), "alpha\nbeta\ngamma\n")
|
||||
|
||||
const firstRead = await handler.execute(config, makeBlock(realFile))
|
||||
assert.equal(firstRead, "1 | alpha\n2 | beta\n3 | gamma\n\n(File has 3 lines total.)")
|
||||
|
||||
const secondRead = await handler.execute(config, makeBlockWithRange(realFile, "2", "2"))
|
||||
assert.equal(
|
||||
secondRead,
|
||||
"[File already read] The file 'real-file.txt' was already read earlier in this conversation. Returning content:\n2 | beta\n\n(Showing lines 2-2 of 3 total. Use start_line=3 to continue reading.)",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { ClineDefaultTool } from "@shared/tools"
|
||||
import { describe, it } from "mocha"
|
||||
import { DEFAULT_MAX_LINES, formatFileContentWithLineNumbers, getReadToolDisplayedLineRange } from "../ReadFileToolHandler"
|
||||
|
||||
describe("getReadToolDisplayedLineRange", () => {
|
||||
const block = (start?: string, end?: string) => ({
|
||||
type: "tool_use" as const,
|
||||
name: ClineDefaultTool.FILE_READ,
|
||||
params: {
|
||||
path: "f.txt",
|
||||
...(start !== undefined ? { start_line: start } : {}),
|
||||
...(end !== undefined ? { end_line: end } : {}),
|
||||
},
|
||||
partial: false,
|
||||
})
|
||||
|
||||
it("matches the slice shown for explicit start/end", () => {
|
||||
const text = Array.from({ length: 10 }, (_, i) => `L${i + 1}`).join("\n")
|
||||
const r = getReadToolDisplayedLineRange(block("3", "5"), { text })
|
||||
assert.deepEqual(r, { start: 3, end: 5 })
|
||||
})
|
||||
|
||||
it("returns undefined for image reads", () => {
|
||||
const r = getReadToolDisplayedLineRange(block(), {
|
||||
text: "ok",
|
||||
imageBlock: { type: "image", source: { type: "url", url: "x" } } as any,
|
||||
})
|
||||
assert.equal(r, undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe("formatFileContentWithLineNumbers", () => {
|
||||
describe("line labels", () => {
|
||||
it("adds 1-indexed line prefixes", () => {
|
||||
const result = formatFileContentWithLineNumbers("alpha\nbeta")
|
||||
assert.ok(result.startsWith("1 | alpha\n2 | beta"))
|
||||
})
|
||||
|
||||
it("does not add an extra numbered line for trailing newline", () => {
|
||||
const result = formatFileContentWithLineNumbers("alpha\nbeta\n")
|
||||
assert.ok(result.startsWith("1 | alpha\n2 | beta"))
|
||||
assert.ok(!result.includes("3 |"))
|
||||
})
|
||||
|
||||
it("returns empty content unchanged", () => {
|
||||
const result = formatFileContentWithLineNumbers("")
|
||||
assert.equal(result, "")
|
||||
})
|
||||
})
|
||||
|
||||
describe("chunked reads", () => {
|
||||
const tenLines = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join("\n")
|
||||
const oversizedContent = Array.from({ length: DEFAULT_MAX_LINES + 10 }, (_, i) => `line${i + 1}`).join("\n")
|
||||
|
||||
it("defaults to reading from line 1 and applies the default chunk size", () => {
|
||||
const result = formatFileContentWithLineNumbers(oversizedContent)
|
||||
assert.ok(result.startsWith("1 | line1\n"))
|
||||
assert.ok(result.includes(`${DEFAULT_MAX_LINES} | line${DEFAULT_MAX_LINES}`))
|
||||
assert.ok(!result.includes(`${DEFAULT_MAX_LINES + 1} |`))
|
||||
assert.ok(result.includes(`Showing lines 1-${DEFAULT_MAX_LINES} of ${DEFAULT_MAX_LINES + 10} total`))
|
||||
assert.ok(result.includes(`start_line=${DEFAULT_MAX_LINES + 1}`))
|
||||
})
|
||||
|
||||
it("respects start_line parameter", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, 5)
|
||||
assert.ok(result.startsWith("5 | line5\n"))
|
||||
assert.ok(!result.includes("4 |"))
|
||||
})
|
||||
|
||||
it("respects start_line and end_line parameters", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, 3, 5)
|
||||
assert.ok(result.startsWith("3 | line3\n"))
|
||||
assert.ok(result.includes("4 | line4\n"))
|
||||
assert.ok(result.includes("5 | line5"))
|
||||
assert.ok(!result.includes("2 |"))
|
||||
assert.ok(!result.includes("6 |"))
|
||||
})
|
||||
|
||||
it("normalizes inverted start_line and end_line parameters", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, 5, 3)
|
||||
assert.ok(result.startsWith("3 | line3\n"))
|
||||
assert.ok(result.includes("4 | line4\n"))
|
||||
assert.ok(result.includes("5 | line5"))
|
||||
assert.ok(!result.includes("2 |"))
|
||||
assert.ok(!result.includes("6 |"))
|
||||
})
|
||||
|
||||
it("clamps start_line to 1 if below", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, -5, 3)
|
||||
assert.ok(result.startsWith("1 | line1\n"))
|
||||
})
|
||||
|
||||
it("clamps end_line to total lines if beyond", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, 8, 999)
|
||||
assert.ok(result.includes("10 | line10"))
|
||||
assert.ok(!result.includes("11 |"))
|
||||
})
|
||||
})
|
||||
|
||||
describe("continuation hints", () => {
|
||||
const tenLines = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join("\n")
|
||||
|
||||
it("shows continuation hint when more lines remain", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, 1, 5)
|
||||
assert.ok(result.includes("Showing lines 1-5 of 10 total"))
|
||||
assert.ok(result.includes("start_line=6"))
|
||||
})
|
||||
|
||||
it("shows total-lines footer when entire file is returned", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines, 1, 10)
|
||||
assert.ok(result.includes("File has 10 lines total"))
|
||||
})
|
||||
|
||||
it("shows total-lines footer when file fits within default limit", () => {
|
||||
const result = formatFileContentWithLineNumbers(tenLines)
|
||||
assert.ok(result.includes("File has 10 lines total"))
|
||||
})
|
||||
})
|
||||
|
||||
describe("default max lines", () => {
|
||||
const bigContent = Array.from({ length: DEFAULT_MAX_LINES + 500 }, (_, i) => `row${i + 1}`).join("\n")
|
||||
|
||||
it("limits output to DEFAULT_MAX_LINES when no end_line given", () => {
|
||||
const result = formatFileContentWithLineNumbers(bigContent)
|
||||
assert.ok(result.includes(`1 | row1`))
|
||||
assert.ok(result.includes(`${DEFAULT_MAX_LINES} | row${DEFAULT_MAX_LINES}`))
|
||||
assert.ok(!result.includes(`${DEFAULT_MAX_LINES + 1} |`))
|
||||
assert.ok(result.includes(`start_line=${DEFAULT_MAX_LINES + 1}`))
|
||||
})
|
||||
|
||||
it("allows reading beyond default limit with explicit end_line", () => {
|
||||
const endLine = DEFAULT_MAX_LINES + 200
|
||||
const result = formatFileContentWithLineNumbers(bigContent, 1, endLine)
|
||||
assert.ok(result.includes(`${endLine} | row${endLine}`))
|
||||
})
|
||||
})
|
||||
|
||||
describe("byte truncation interaction", () => {
|
||||
it("preserves truncation notice without numbering it", () => {
|
||||
const input =
|
||||
"alpha\nbeta\n\n---\n\n[FILE TRUNCATED: This content is 1.0 MB but only the first 400 KB is shown (600 KB truncated).]"
|
||||
const result = formatFileContentWithLineNumbers(input)
|
||||
assert.ok(result.startsWith("1 | alpha\n2 | beta"))
|
||||
assert.ok(
|
||||
result.includes(
|
||||
"[FILE TRUNCATED: This content is 1.0 MB but only the first 400 KB is shown (600 KB truncated).]",
|
||||
),
|
||||
)
|
||||
assert.ok(!result.includes("3 |"))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -11,7 +11,10 @@ import { WorkspaceRootManager } from "../WorkspaceRootManager"
|
||||
|
||||
describe("setupWorkspaceManager", () => {
|
||||
const sandbox = sinon.createSandbox()
|
||||
let fakeTelemetry: any
|
||||
let fakeTelemetry: {
|
||||
captureWorkspaceInitialized: sinon.SinonStub
|
||||
captureWorkspaceInitError: sinon.SinonStub
|
||||
}
|
||||
|
||||
const cwd = "/Users/test/project"
|
||||
const defaultRoots: WorkspaceRoot[] = [
|
||||
@@ -75,12 +78,12 @@ describe("setupWorkspaceManager", () => {
|
||||
getWorkspacePaths: sandbox.stub().resolves({ paths: ["/ws/root1", "/ws/root2"] }),
|
||||
} as any)
|
||||
|
||||
// Telemetry stubs via getTelemetryService proxy
|
||||
// Telemetry stubs by replacing the exported proxy with a test double
|
||||
fakeTelemetry = {
|
||||
captureWorkspaceInitialized: sandbox.stub(),
|
||||
captureWorkspaceInitError: sandbox.stub(),
|
||||
captureWorkspaceInitialized: sandbox.stub().resolves(),
|
||||
captureWorkspaceInitError: sandbox.stub().resolves(),
|
||||
}
|
||||
sandbox.stub(telemetry, "getTelemetryService").resolves(fakeTelemetry)
|
||||
sandbox.stub(telemetry, "telemetryService").value(fakeTelemetry)
|
||||
|
||||
// Stub WorkspaceRootManager.fromLegacyCwd to be deterministic
|
||||
sandbox.stub(WorkspaceRootManager, "fromLegacyCwd").callsFake(async (legacyCwd: string) => {
|
||||
@@ -116,6 +119,10 @@ describe("setupWorkspaceManager", () => {
|
||||
expect(stateManager._state.primaryIndex).to.equal(0)
|
||||
|
||||
// telemetry captured (skipped assertion in unit tests)
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.calledOnce).to.equal(true)
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.firstCall.args[0]).to.equal(2)
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.firstCall.args[1]).to.deep.equal(["git", "none"])
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.firstCall.args[3]).to.equal(true)
|
||||
})
|
||||
|
||||
it("uses single-root cwd when history restore is disabled (historyItem present)", async () => {
|
||||
@@ -157,6 +164,10 @@ describe("setupWorkspaceManager", () => {
|
||||
// persisted
|
||||
expect(stateManager._state.roots?.[0].path).to.equal(cwd)
|
||||
// telemetry called (skipped assertion in unit tests)
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.calledOnce).to.equal(true)
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.firstCall.args[0]).to.equal(1)
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.firstCall.args[1]).to.deep.equal(["none"])
|
||||
expect(fakeTelemetry.captureWorkspaceInitialized.firstCall.args[3]).to.equal(false)
|
||||
})
|
||||
|
||||
it("gracefully handles errors and falls back to fromLegacyCwd while warning user", async () => {
|
||||
@@ -176,7 +187,10 @@ describe("setupWorkspaceManager", () => {
|
||||
expect(manager.getRoots()).to.have.length(1)
|
||||
expect(manager.getRoots()[0].path).to.equal(cwd)
|
||||
|
||||
// telemetry error captured (skipped assertion in unit tests)
|
||||
expect(fakeTelemetry.captureWorkspaceInitError.calledOnce).to.equal(true)
|
||||
expect(fakeTelemetry.captureWorkspaceInitError.firstCall.args[0]).to.be.instanceOf(Error)
|
||||
expect(fakeTelemetry.captureWorkspaceInitError.firstCall.args[1]).to.equal(true)
|
||||
expect(fakeTelemetry.captureWorkspaceInitError.firstCall.args[2]).to.equal(2)
|
||||
|
||||
// persisted fallback state
|
||||
expect(stateManager._state.roots?.[0].path).to.equal(cwd)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { strict as assert } from "assert"
|
||||
import { afterEach, describe, it } from "mocha"
|
||||
import * as sinon from "sinon"
|
||||
import * as vscode from "vscode"
|
||||
import { ExtensionRegistryInfo } from "@/registry"
|
||||
import { ClineClient } from "@/shared/cline"
|
||||
import { getHostVersion } from "./getHostVersion"
|
||||
|
||||
describe("Hostbridge - Env - getHostVersion", () => {
|
||||
const sandbox = sinon.createSandbox()
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
})
|
||||
|
||||
it("preserves known remote workspace names", async () => {
|
||||
const cases = ["ssh-remote", "dev-container", "codespaces"]
|
||||
|
||||
for (const remoteName of cases) {
|
||||
const remoteNameStub = sandbox.stub(vscode.env, "remoteName")
|
||||
remoteNameStub.get(() => remoteName)
|
||||
|
||||
const response = await getHostVersion({} as any)
|
||||
|
||||
assert.strictEqual(response.platform, vscode.env.appName)
|
||||
assert.strictEqual(response.version, vscode.version)
|
||||
assert.strictEqual(response.clineType, ClineClient.VSCode)
|
||||
assert.strictEqual(response.clineVersion, ExtensionRegistryInfo.version)
|
||||
assert.strictEqual(response.remoteName, remoteName)
|
||||
|
||||
remoteNameStub.restore()
|
||||
}
|
||||
})
|
||||
|
||||
it("normalizes empty remote workspace names to undefined", async () => {
|
||||
sandbox.stub(vscode.env, "remoteName").get(() => "")
|
||||
|
||||
const response = await getHostVersion({} as any)
|
||||
|
||||
assert.strictEqual(response.remoteName, undefined)
|
||||
})
|
||||
|
||||
it("keeps local workspaces without a remoteName", async () => {
|
||||
sandbox.stub(vscode.env, "remoteName").get(() => undefined)
|
||||
|
||||
const response = await getHostVersion({} as any)
|
||||
|
||||
assert.strictEqual(response.remoteName, undefined)
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import type {
|
||||
BalanceResponse,
|
||||
FeaturebaseTokenResponse,
|
||||
OrganizationBalanceResponse,
|
||||
OrganizationUsageTransaction,
|
||||
PaymentTransaction,
|
||||
@@ -82,9 +83,8 @@ export class ClineAccountService {
|
||||
}
|
||||
if (response.statusText === "No Content") {
|
||||
return {} as T // Return empty object if no content
|
||||
} else {
|
||||
return response.data.data as T
|
||||
}
|
||||
return response.data.data as T
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,6 +160,20 @@ export class ClineAccountService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a short-lived Featurebase SSO JWT for the current user
|
||||
* @returns FeaturebaseTokenResponse or undefined if failed
|
||||
*/
|
||||
async fetchFeaturebaseToken(): Promise<FeaturebaseTokenResponse | undefined> {
|
||||
try {
|
||||
const data = await this.authenticatedRequest<FeaturebaseTokenResponse>(CLINE_API_ENDPOINT.FEATUREBASE_TOKEN)
|
||||
return data
|
||||
} catch (error) {
|
||||
Logger.error("Failed to fetch Featurebase token:", error)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the current user's organizations
|
||||
* @returns UserResponse["organizations"] or undefined if failed
|
||||
|
||||
@@ -49,10 +49,78 @@ describe("Telemetry system is abstracted and can easily switch between providers
|
||||
platform_version: "9.8.7-abc",
|
||||
os_type: "win32",
|
||||
os_version: "Windows 10 Pro",
|
||||
is_remote_workspace: false,
|
||||
is_dev: "",
|
||||
}
|
||||
|
||||
describe("Telemetry Service", () => {
|
||||
it("should derive remote workspace metadata from host version", async () => {
|
||||
const remoteProvider = new NoOpTelemetryProvider()
|
||||
const localProvider = new NoOpTelemetryProvider()
|
||||
const remoteLogSpy = sinon.spy(remoteProvider, "log")
|
||||
const localLogSpy = sinon.spy(localProvider, "log")
|
||||
const hostVersionStub = sinon.stub(HostProvider.env, "getHostVersion")
|
||||
const createProvidersStub = sinon.stub(TelemetryProviderFactory, "createProviders")
|
||||
|
||||
hostVersionStub.onFirstCall().resolves({
|
||||
platform: "VS Code",
|
||||
version: "1.103.0",
|
||||
clineType: "VSCode Extension",
|
||||
remoteName: "ssh-remote",
|
||||
})
|
||||
hostVersionStub.onSecondCall().resolves({
|
||||
platform: "VS Code",
|
||||
version: "1.103.0",
|
||||
clineType: "VSCode Extension",
|
||||
})
|
||||
createProvidersStub.onFirstCall().resolves([remoteProvider])
|
||||
createProvidersStub.onSecondCall().resolves([localProvider])
|
||||
|
||||
const remoteService = await TelemetryService.create()
|
||||
const localService = await TelemetryService.create()
|
||||
|
||||
remoteLogSpy.resetHistory()
|
||||
localLogSpy.resetHistory()
|
||||
|
||||
remoteService.captureTaskCreated("task-remote", "openai")
|
||||
localService.captureTaskCreated("task-local", "openai")
|
||||
|
||||
assert.ok(remoteLogSpy.calledOnce, "remote service should emit an event")
|
||||
assert.ok(localLogSpy.calledOnce, "local service should emit an event")
|
||||
assert.strictEqual(remoteLogSpy.firstCall.args[1]?.is_remote_workspace, true)
|
||||
assert.strictEqual(localLogSpy.firstCall.args[1]?.is_remote_workspace, false)
|
||||
|
||||
hostVersionStub.restore()
|
||||
createProvidersStub.restore()
|
||||
remoteLogSpy.restore()
|
||||
localLogSpy.restore()
|
||||
await remoteService.dispose()
|
||||
await localService.dispose()
|
||||
})
|
||||
|
||||
it("should include remote workspace metadata on workspace.initialized events", async () => {
|
||||
const noOpProvider = new NoOpTelemetryProvider()
|
||||
const logSpy = sinon.spy(noOpProvider, "log")
|
||||
const telemetryService = new TelemetryService([noOpProvider], {
|
||||
...MOCK_METADATA,
|
||||
is_remote_workspace: true,
|
||||
})
|
||||
|
||||
logSpy.resetHistory()
|
||||
telemetryService.captureWorkspaceInitialized(1, ["Git"], 123, false)
|
||||
|
||||
assert.ok(logSpy.calledOnce, "workspace.initialized should be emitted once")
|
||||
const [eventName, properties] = logSpy.firstCall.args
|
||||
assert.strictEqual(eventName, "workspace.initialized")
|
||||
assert.ok(properties, "workspace.initialized properties should be defined")
|
||||
assert.strictEqual(properties.is_remote_workspace, true)
|
||||
assert.strictEqual(properties.root_count, 1)
|
||||
assert.deepStrictEqual(properties.vcs_types, ["Git"])
|
||||
|
||||
logSpy.restore()
|
||||
await noOpProvider.dispose()
|
||||
})
|
||||
|
||||
it("should include correct metadata with telemetry events", async () => {
|
||||
const noOpProvider = new NoOpTelemetryProvider()
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ export type TelemetryMetadata = {
|
||||
/** The operating system version e.g. 'Windows 10 Pro', 'Darwin Kernel Version 21.6.0...'
|
||||
* This is the value returned by os.version() */
|
||||
os_version: string
|
||||
/** Whether the current workspace is a VS Code remote workspace */
|
||||
is_remote_workspace: boolean
|
||||
/** Whether the extension is running in development mode */
|
||||
is_dev: string | undefined
|
||||
}
|
||||
@@ -360,6 +362,8 @@ export class TelemetryService {
|
||||
cline_type: hostVersion.clineType || "unknown",
|
||||
os_type: os.platform(),
|
||||
os_version: os.version(),
|
||||
// `remoteName` is normalized by the host bridge to `undefined` for local workspaces.
|
||||
is_remote_workspace: !!hostVersion.remoteName,
|
||||
is_dev: process.env.IS_DEV,
|
||||
}
|
||||
return new TelemetryService(providers, metadata)
|
||||
|
||||
@@ -64,7 +64,7 @@ class FakeProvider implements ITelemetryProvider {
|
||||
async dispose(): Promise<void> {}
|
||||
}
|
||||
|
||||
function createTelemetryService(provider: FakeProvider): TelemetryService {
|
||||
function createTelemetryService(provider: FakeProvider, overrides: Partial<TelemetryMetadata> = {}): TelemetryService {
|
||||
return new TelemetryService([provider], {
|
||||
extension_version: "test",
|
||||
cline_type: "cline-unit-tests",
|
||||
@@ -72,7 +72,9 @@ function createTelemetryService(provider: FakeProvider): TelemetryService {
|
||||
platform_version: "1.0.0",
|
||||
os_type: "darwin",
|
||||
os_version: "24",
|
||||
is_remote_workspace: false,
|
||||
is_dev: "true",
|
||||
...overrides,
|
||||
} as TelemetryMetadata)
|
||||
}
|
||||
|
||||
@@ -194,6 +196,17 @@ describe("TelemetryService metrics", () => {
|
||||
assert.strictEqual(tokenEvent?.properties?.totalCost, 0.42)
|
||||
})
|
||||
|
||||
it("metrics include is_remote_workspace in standard attributes", () => {
|
||||
const provider = new FakeProvider()
|
||||
const service = createTelemetryService(provider, { is_remote_workspace: true })
|
||||
|
||||
service.captureTokenUsage("task-remote", 120, 80, "anthropic", "model-a")
|
||||
|
||||
assert.ok(provider.counters.length > 0)
|
||||
assert.strictEqual(provider.counters[0].attributes.is_remote_workspace, true)
|
||||
assert.strictEqual(provider.histograms[0].attributes.is_remote_workspace, true)
|
||||
})
|
||||
|
||||
it("captureConversationTurnEvent emits counters with cache and cost", () => {
|
||||
const provider = new FakeProvider()
|
||||
const service = createTelemetryService(provider)
|
||||
|
||||
@@ -21,6 +21,10 @@ export interface BalanceResponse {
|
||||
userId: string
|
||||
}
|
||||
|
||||
export interface FeaturebaseTokenResponse {
|
||||
featurebaseJwt: string
|
||||
}
|
||||
|
||||
export interface UsageTransaction {
|
||||
aiInferenceProviderName: string
|
||||
aiModelName: string
|
||||
|
||||
@@ -108,6 +108,7 @@ export interface ExtensionState {
|
||||
backgroundEditEnabled?: boolean
|
||||
optOutOfRemoteConfig?: boolean
|
||||
doubleCheckCompletionEnabled?: boolean
|
||||
lazyTeammateModeEnabled?: boolean
|
||||
showFeatureTips?: boolean
|
||||
banners?: BannerCardData[]
|
||||
welcomeBanners?: BannerCardData[]
|
||||
@@ -215,6 +216,9 @@ export interface ClineSayTool {
|
||||
operationIsLocatedInWorkspace?: boolean
|
||||
/** Starting line numbers in the original file where each SEARCH block matched */
|
||||
startLineNumbers?: number[]
|
||||
/** Inclusive line range actually returned by read_file (for UI summaries). */
|
||||
readLineStart?: number
|
||||
readLineEnd?: number
|
||||
}
|
||||
|
||||
export interface ClineSayHook {
|
||||
|
||||
@@ -6,6 +6,7 @@ enum CLINE_API_AUTH_ENDPOINTS {
|
||||
enum CLINE_API_ENDPOINT_V1 {
|
||||
TOKEN_EXCHANGE = "/api/v1/auth/token",
|
||||
USER_INFO = "/api/v1/users/me",
|
||||
FEATUREBASE_TOKEN = "/api/v1/users/me/featurebase-token",
|
||||
ACTIVE_ACCOUNT = "/api/v1/users/active-account",
|
||||
REMOTE_CONFIG = "/api/v1/organizations/{id}/remote-config",
|
||||
API_KEYS = "/api/v1/organizations/{id}/api-keys",
|
||||
|
||||
@@ -273,6 +273,7 @@ const USER_SETTINGS_FIELDS = {
|
||||
backgroundEditEnabled: { default: false as boolean },
|
||||
optOutOfRemoteConfig: { default: false as boolean },
|
||||
doubleCheckCompletionEnabled: { default: false as boolean },
|
||||
lazyTeammateModeEnabled: { default: false as boolean },
|
||||
showFeatureTips: { default: true as boolean },
|
||||
|
||||
// OpenTelemetry configuration
|
||||
|
||||
@@ -7,6 +7,7 @@ export const E2E_REGISTERED_MOCK_ENDPOINTS = {
|
||||
"/organizations/{orgId}/api-keys",
|
||||
"/organizations/{orgId}/remote-config",
|
||||
"/users/me",
|
||||
"/users/me/featurebase-token",
|
||||
"/users/{userId}/balance",
|
||||
"/users/{userId}/usages",
|
||||
"/users/{userId}/payments",
|
||||
@@ -53,7 +54,7 @@ The user wants me to replace the name "john" with "cline" in the test.ts file. I
|
||||
export const name = "john"
|
||||
\`\`\`
|
||||
|
||||
I need to change "john" to "cline". This is a simple targeted edit, so I should use the replace_in_file tool rather than write_to_file since I\'m only changing one small part of the file.
|
||||
I need to change "john" to "cline". This is a simple targeted edit, so I should use the replace_in_file tool rather than write_to_file since I'm only changing one small part of the file.
|
||||
|
||||
I need to:
|
||||
1. Use replace_in_file to change "john" to "cline" in the test.ts file
|
||||
@@ -61,7 +62,7 @@ I need to:
|
||||
3. The REPLACE block should be: \`export const name = "cline"\`
|
||||
</thinking>
|
||||
|
||||
I\'ll replace "john" with "cline" in the test.ts file.
|
||||
I'll replace "john" with "cline" in the test.ts file.
|
||||
|
||||
<replace_in_file>
|
||||
<path>test.ts</path>
|
||||
|
||||
@@ -213,6 +213,16 @@ export class ClineApiServerMock {
|
||||
return sendApiResponse(currentUser)
|
||||
}
|
||||
|
||||
if (endpoint === "/users/me/featurebase-token" && method === "GET") {
|
||||
const currentUser = controller.currentUser
|
||||
if (!currentUser) {
|
||||
return sendApiError("Unauthorized", 401)
|
||||
}
|
||||
return sendApiResponse({
|
||||
featurebaseJwt: `mock-featurebase-jwt-${currentUser.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
if (endpoint === "/users/{userId}/balance" && method === "GET") {
|
||||
const { userId } = params
|
||||
const balance: BalanceResponse = {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import * as assert from "assert"
|
||||
import { afterEach, beforeEach, describe, it } from "mocha"
|
||||
import sinon from "sinon"
|
||||
import { ClineAccountService } from "@/services/account/ClineAccountService"
|
||||
import { AuthService } from "@/services/auth/AuthService"
|
||||
|
||||
describe("ClineAccountService.fetchFeaturebaseToken", () => {
|
||||
let service: ClineAccountService
|
||||
let sandbox: sinon.SinonSandbox
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
sandbox.stub(AuthService, "getInstance").returns({} as AuthService)
|
||||
service = new ClineAccountService()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
})
|
||||
|
||||
it("returns featurebaseJwt on a successful authenticated request", async () => {
|
||||
sandbox
|
||||
.stub(service as unknown as { authenticatedRequest: () => unknown }, "authenticatedRequest")
|
||||
.resolves({ featurebaseJwt: "test-jwt-token-123" })
|
||||
|
||||
const result = await service.fetchFeaturebaseToken()
|
||||
|
||||
assert.ok(result !== undefined, "result should not be undefined")
|
||||
assert.strictEqual(result?.featurebaseJwt, "test-jwt-token-123")
|
||||
})
|
||||
|
||||
it("returns undefined when the request throws a network error", async () => {
|
||||
sandbox
|
||||
.stub(service as unknown as { authenticatedRequest: () => unknown }, "authenticatedRequest")
|
||||
.rejects(new Error("Network error"))
|
||||
|
||||
const result = await service.fetchFeaturebaseToken()
|
||||
|
||||
assert.strictEqual(result, undefined)
|
||||
})
|
||||
|
||||
it("returns undefined when the request throws due to missing auth token", async () => {
|
||||
sandbox
|
||||
.stub(service as unknown as { authenticatedRequest: () => unknown }, "authenticatedRequest")
|
||||
.rejects(new Error("No Cline account auth token found"))
|
||||
|
||||
const result = await service.fetchFeaturebaseToken()
|
||||
|
||||
assert.strictEqual(result, undefined)
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,8 @@
|
||||
// Mock implementation of VSCode API for unit tests
|
||||
export const env = {
|
||||
machineId: "test-machine-id",
|
||||
appName: "VS Code",
|
||||
remoteName: undefined as string | undefined,
|
||||
isTelemetryEnabled: true,
|
||||
onDidChangeTelemetryEnabled: (_callback: (enabled: boolean) => void) => {
|
||||
// Return a disposable mock
|
||||
@@ -10,6 +12,8 @@ export const env = {
|
||||
},
|
||||
}
|
||||
|
||||
export const version = "1.103.0"
|
||||
|
||||
export const workspace = {
|
||||
getConfiguration: (section?: string) => {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { SVGProps } from "react"
|
||||
import type { Environment } from "../../../src/shared/config-types"
|
||||
import { getEnvironmentColor } from "../utils/environmentColors"
|
||||
|
||||
/**
|
||||
* ClineLogoTired component renders the sleepy Cline logo for "Lazy Teammate Mode".
|
||||
*
|
||||
* Based on the sleepy-cline.svg asset. Features droopy half-closed eyes and a
|
||||
* small sleepy mouth, giving the bot a tired/lazy appearance.
|
||||
*
|
||||
* @param {SVGProps<SVGSVGElement> & { environment?: Environment }} props - Standard SVG props plus optional environment
|
||||
* @returns {JSX.Element} SVG Cline logo with sleepy/tired expression
|
||||
*/
|
||||
const ClineLogoTired = (props: SVGProps<SVGSVGElement> & { environment?: Environment }) => {
|
||||
const { environment, ...svgProps } = props
|
||||
|
||||
// Determine fill color based on environment
|
||||
const fillColor = environment ? getEnvironmentColor(environment) : "var(--vscode-icon-foreground)"
|
||||
|
||||
return (
|
||||
<svg fill="none" height="535" viewBox="0 0 512 535" width="512" xmlns="http://www.w3.org/2000/svg" {...svgProps}>
|
||||
<path
|
||||
d="M500.6,300.5c-9-20.7-17.9-41.4-26.9-62.1-.7-2-.3-4.4-.3-6.4.4-9,1.1-18,1.4-27,2.8-28.4-6.5-58-25.2-79.6-15.1-18.1-36.6-30.7-59.6-35.5-8.1-1.8-16.6-1.6-25-2.1-10-.7-20-1-30-1.7,2-11.9,1-24.1-3.7-35.3-5.8-14.1-16.8-25.9-30.6-32.5-14.4-7-31.5-8.2-46.7-3.1-16,5.2-29.5,17-36.8,32.1-4.9,10-6.8,21.2-6.1,32.2-19.7-1-39.4-2.2-59.1-3.1-26.8.5-53,11.7-72,30.6-20.2,19.5-31.7,47-32.3,75-.5,9.3-1,18.7-1.5,28-.2,2.1,0,4.1-1.2,6-9.8,16.8-19.5,33.7-29.4,50.6-2.2,4.1-4.9,8-6.6,12.3-2,5.7-1.2,12.2,1.3,17.6,8.9,19.5,17.6,39.2,26.5,58.7.8,1.9,1.5,3.7,1.3,5.8-.6,10.3-1.1,20.7-1.7,31-1.5,21.2,3,42.6,13.5,61.1,8.8,15.8,21.6,29.4,37.1,38.9,13.9,8.7,29.7,13.9,46,15.4,72,3.9,144,7.7,216,11.5,20.1,1.8,40.8-2.8,58.5-12.5,18.8-10.1,34.2-26,44.1-44.9,6.5-12.6,10.5-26.4,11.7-40.5.7-12.4,1.2-24.7,2-37.1,0-3.3,1.9-5.5,3.3-8.2,6.6-11.8,13.5-23.4,20.1-35.2,3.7-6.9,8.1-13.4,11.6-20.4,3.2-6.1,3.2-13.5.3-19.7ZM218.5,316.5c-9.7,7.1-21.3,12.3-33.5,12.5-17.6,1-35.1-5.3-49-16-4.6-3.2-8.1-7.5-9.6-13,0-1.8-.7-3.6,1.7-3.8,4,1,7.9,2.6,12,3.5,22.8,5.6,47.6,5.9,71,4.8,6.5-.2,13-1.3,19.5-.9-2.7,5.6-7.1,9.2-12,12.9ZM276,449.7c-14,.5-28,.1-42-.2-2.1,0-4.3,0-6.4-.4-.9-2.1.6-3.2,1.7-4.8,4.8-5.9,11-11,18.7-12.4,8.4-1.6,16.5,1.2,23.5,5.5,4.7,3,9.2,6.3,12.6,10.8-2.6,1.1-5.3,1.4-8.1,1.4ZM390.4,319.4c-16.4,14.2-38.8,21.8-60.4,18.4-13.2-1.6-24.7-8.6-34.1-17.7-3-3-6.2-6.5-8.1-10.4.5-1,1.2-1.6,2.2-1.6,2.8-.2,5.7.7,8.5,1.1,16,2.9,32.3,4.9,48.5,5.5,14.3.4,28.2-.2,42.2-3.6,2.2-.6,3.7-.3,5.8.5-1.1,2.9-2.2,5.7-4.6,7.8Z"
|
||||
fill={fillColor}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
export default ClineLogoTired
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fa7c90bf657f317e63dee745e010898ca0cb13ee82e9dbe341ac16199170399a
|
||||
size 3738635
|
||||
@@ -527,6 +527,12 @@ export const ChatRowContent = memo(
|
||||
{tool.path && !tool.path.startsWith(".") && <span>/</span>}
|
||||
<span className="ph-no-capture whitespace-nowrap overflow-hidden text-ellipsis mr-2 text-left [direction: rtl]">
|
||||
{cleanPathPrefix(tool.path ?? "") + "\u200E"}
|
||||
{tool.readLineStart != null && tool.readLineEnd != null ? (
|
||||
<span className="opacity-80">
|
||||
{" "}
|
||||
({tool.readLineStart}-{tool.readLineEnd})
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
<div className="grow" />
|
||||
{!isImage && <SquareArrowOutUpRightIcon className="size-2" />}
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import type { ClineMessage } from "@shared/ExtensionMessage"
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { buildToolsWithReasoning, getToolGroupSummaryFromParsedTools } from "./ToolGroupRenderer"
|
||||
|
||||
const readToolMessage = (
|
||||
ts: number,
|
||||
type: "ask" | "say",
|
||||
path: string,
|
||||
range?: { start: number; end: number },
|
||||
): ClineMessage => ({
|
||||
ts,
|
||||
type,
|
||||
...(type === "ask" ? { ask: "tool" as const } : { say: "tool" as const }),
|
||||
text: JSON.stringify({
|
||||
tool: "readFile",
|
||||
path,
|
||||
...(range ? { readLineStart: range.start, readLineEnd: range.end } : {}),
|
||||
}),
|
||||
})
|
||||
|
||||
describe("buildToolsWithReasoning", () => {
|
||||
it("replaces an immediately-following read approval ask with the completed read", () => {
|
||||
const tools = buildToolsWithReasoning([
|
||||
readToolMessage(1, "ask", "src/a.ts"),
|
||||
readToolMessage(2, "say", "src/a.ts", { start: 1, end: 20 }),
|
||||
])
|
||||
|
||||
expect(tools).toHaveLength(1)
|
||||
expect(tools[0].tool.say).toBe("tool")
|
||||
expect(tools[0].parsedTool.readLineStart).toBe(1)
|
||||
expect(tools[0].parsedTool.readLineEnd).toBe(20)
|
||||
})
|
||||
|
||||
it("keeps separate reads of the same file when they are distinct operations", () => {
|
||||
const tools = buildToolsWithReasoning([
|
||||
readToolMessage(1, "ask", "src/a.ts"),
|
||||
readToolMessage(2, "say", "src/a.ts", { start: 1, end: 20 }),
|
||||
readToolMessage(3, "ask", "src/a.ts"),
|
||||
readToolMessage(4, "say", "src/a.ts", { start: 40, end: 60 }),
|
||||
])
|
||||
|
||||
expect(tools).toHaveLength(2)
|
||||
expect(tools.map((tool) => [tool.parsedTool.readLineStart, tool.parsedTool.readLineEnd])).toEqual([
|
||||
[1, 20],
|
||||
[40, 60],
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("getToolGroupSummaryFromParsedTools", () => {
|
||||
it("counts rendered read tools once after ask/say collapse", () => {
|
||||
const tools = buildToolsWithReasoning([
|
||||
readToolMessage(1, "ask", "src/a.ts"),
|
||||
readToolMessage(2, "say", "src/a.ts", { start: 1, end: 20 }),
|
||||
])
|
||||
|
||||
expect(getToolGroupSummaryFromParsedTools(tools.map((tool) => tool.parsedTool))).toBe("Cline read 1 file")
|
||||
})
|
||||
})
|
||||
+39
-13
@@ -40,8 +40,14 @@ const getActivityText = (tool: ClineSayTool): string | null => {
|
||||
}
|
||||
|
||||
switch (tool.tool) {
|
||||
case "readFile":
|
||||
return tool.path ? `Reading ${cleanedPath}...` : null
|
||||
case "readFile": {
|
||||
if (!tool.path) {
|
||||
return null
|
||||
}
|
||||
const lineHint =
|
||||
tool.readLineStart != null && tool.readLineEnd != null ? ` (lines ${tool.readLineStart}-${tool.readLineEnd})` : ""
|
||||
return `Reading ${cleanedPath}${lineHint}...`
|
||||
}
|
||||
case "listFilesTopLevel":
|
||||
case "listFilesRecursive":
|
||||
return tool.path ? `Exploring ${cleanedPath}/...` : null
|
||||
@@ -144,7 +150,7 @@ export const ToolGroupRenderer = memo(({ messages, allMessages, isLastGroup }: T
|
||||
return [...dedupedCompleted, ...activeTools]
|
||||
}, [completedTools, activeTools])
|
||||
|
||||
const summary = getToolGroupSummary(filteredMessages)
|
||||
const summary = getToolGroupSummaryFromParsedTools(completedTools.map((item) => item.parsedTool))
|
||||
|
||||
const handleOpenFile = useCallback((filePath: string) => {
|
||||
FileServiceClient.openFileRelativePath(StringRequest.create({ value: filePath })).catch((err) =>
|
||||
@@ -234,7 +240,7 @@ export const ToolGroupRenderer = memo(({ messages, allMessages, isLastGroup }: T
|
||||
* Build tool items WITHOUT reasoning.
|
||||
* Reasoning should not be displayed in file lists - only file/folder content.
|
||||
*/
|
||||
function buildToolsWithReasoning(messages: ClineMessage[]): ToolWithReasoning[] {
|
||||
export function buildToolsWithReasoning(messages: ClineMessage[]): ToolWithReasoning[] {
|
||||
const result: ToolWithReasoning[] = []
|
||||
|
||||
for (const msg of messages) {
|
||||
@@ -245,6 +251,23 @@ function buildToolsWithReasoning(messages: ClineMessage[]): ToolWithReasoning[]
|
||||
|
||||
if (isLowStakesTool(msg)) {
|
||||
const parsedTool = parseToolSafe(msg.text)
|
||||
const previous = result.at(-1)
|
||||
const supersedesPreviousReadAsk =
|
||||
parsedTool.tool === "readFile" &&
|
||||
parsedTool.path &&
|
||||
msg.say === "tool" &&
|
||||
previous?.tool.ask === "tool" &&
|
||||
previous.parsedTool.tool === "readFile" &&
|
||||
previous.parsedTool.path === parsedTool.path
|
||||
|
||||
if (supersedesPreviousReadAsk) {
|
||||
result[result.length - 1] = {
|
||||
tool: msg,
|
||||
parsedTool,
|
||||
reasoning: undefined,
|
||||
}
|
||||
continue
|
||||
}
|
||||
result.push({
|
||||
tool: msg,
|
||||
parsedTool,
|
||||
@@ -276,8 +299,16 @@ function getToolDisplayInfo(tool: ClineSayTool) {
|
||||
const folderPath = filePath + "/"
|
||||
|
||||
switch (tool.tool) {
|
||||
case "readFile":
|
||||
return { icon, path: filePath, label: "read" }
|
||||
case "readFile": {
|
||||
const lineNote =
|
||||
tool.readLineStart != null && tool.readLineEnd != null ? `lines ${tool.readLineStart}-${tool.readLineEnd}` : null
|
||||
return {
|
||||
icon,
|
||||
path: filePath,
|
||||
label: "read",
|
||||
displayText: lineNote ? `${cleanPathPrefix(filePath)} · ${lineNote}` : undefined,
|
||||
}
|
||||
}
|
||||
case "listFilesTopLevel":
|
||||
return { icon, path: folderPath, label: "listed" }
|
||||
case "listFilesRecursive":
|
||||
@@ -319,15 +350,10 @@ function formatSearchDisplay(regex: string, path: string, filePattern?: string):
|
||||
/**
|
||||
* Get summary label for a tool group - shows what's been added to context.
|
||||
*/
|
||||
function getToolGroupSummary(messages: ClineMessage[]): string {
|
||||
export function getToolGroupSummaryFromParsedTools(tools: ClineSayTool[]): string {
|
||||
const counts = { read: 0, list: 0, search: 0, def: 0 }
|
||||
|
||||
for (const msg of messages) {
|
||||
if (!isLowStakesTool(msg)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const tool = parseToolSafe(msg.text)
|
||||
for (const tool of tools) {
|
||||
switch (tool.tool) {
|
||||
case "readFile":
|
||||
counts.read++
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { StringRequest } from "@shared/proto/cline/common"
|
||||
import { VSCodeButton, VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
import React, { useEffect, useMemo, useState } from "react"
|
||||
import kanbanDemoVideo from "@/assets/cline_kanban_demo.webm"
|
||||
import kanbanDemoVideoMp4 from "@/assets/cline_kanban_demo.mp4"
|
||||
import kanbanDemoVideoWebm from "@/assets/cline_kanban_demo.webm"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
import { PLATFORM_CONFIG, PlatformType } from "@/config/platform.config"
|
||||
import { FileServiceClient, StateServiceClient } from "@/services/grpc-client"
|
||||
|
||||
const INSTALL_COMMAND = "npm install -g cline"
|
||||
const COPIED_TIMEOUT = 1500
|
||||
const kanbanDemoVideoSrc = kanbanDemoVideo.startsWith("/src/")
|
||||
? new URL(kanbanDemoVideo, import.meta.url).toString()
|
||||
: kanbanDemoVideo
|
||||
const resolveAssetSrc = (src: string) => (src.startsWith("/src/") ? new URL(src, import.meta.url).toString() : src)
|
||||
const kanbanDemoMp4Src = resolveAssetSrc(kanbanDemoVideoMp4)
|
||||
const kanbanDemoWebmSrc = resolveAssetSrc(kanbanDemoVideoWebm)
|
||||
|
||||
export const CLINE_KANBAN_MODAL_DISMISS_ID = "cline-kanban-launch-modal-v1"
|
||||
|
||||
@@ -76,9 +77,10 @@ export const ClineKanbanLaunchModal: React.FC<ClineKanbanLaunchModalProps> = ({
|
||||
className="w-full rounded-md border border-[var(--vscode-editorGroup-border)]"
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
src={kanbanDemoVideoSrc}
|
||||
/>
|
||||
playsInline>
|
||||
<source src={kanbanDemoMp4Src} type="video/mp4" />
|
||||
<source src={kanbanDemoWebmSrc} type="video/webm" />
|
||||
</video>
|
||||
|
||||
<p className="text-sm" style={{ color: "var(--vscode-descriptionForeground)" }}>
|
||||
A replacement for your IDE better suited for running many agents in parallel and reviewing diffs. Enable
|
||||
|
||||
@@ -133,6 +133,13 @@ const experimentalFeatures: FeatureToggle[] = [
|
||||
stateKey: "doubleCheckCompletionEnabled",
|
||||
settingKey: "doubleCheckCompletionEnabled",
|
||||
},
|
||||
{
|
||||
id: "lazy-teammate",
|
||||
label: "Lazy Teammate Mode",
|
||||
description: "Sometimes Cline just isn't feeling it today. For entertainment purposes only.",
|
||||
stateKey: "lazyTeammateModeEnabled",
|
||||
settingKey: "lazyTeammateModeEnabled",
|
||||
},
|
||||
]
|
||||
|
||||
const advancedFeatures: FeatureToggle[] = [
|
||||
@@ -218,6 +225,7 @@ const FeatureSettingsSection = ({ renderSectionHeader }: FeatureSettingsSectionP
|
||||
enableParallelToolCalling,
|
||||
backgroundEditEnabled,
|
||||
doubleCheckCompletionEnabled,
|
||||
lazyTeammateModeEnabled,
|
||||
showFeatureTips,
|
||||
} = useExtensionState()
|
||||
|
||||
@@ -245,6 +253,7 @@ const FeatureSettingsSection = ({ renderSectionHeader }: FeatureSettingsSectionP
|
||||
enableParallelToolCalling,
|
||||
backgroundEditEnabled,
|
||||
doubleCheckCompletionEnabled,
|
||||
lazyTeammateModeEnabled,
|
||||
yoloModeToggled: isYoloRemoteLocked ? remoteConfigSettings?.yoloModeToggled : yoloModeToggled,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { EmptyRequest } from "@shared/proto/cline/common"
|
||||
import ClineLogoSanta from "@/assets/ClineLogoSanta"
|
||||
import ClineLogoTired from "@/assets/ClineLogoTired"
|
||||
import ClineLogoVariable from "@/assets/ClineLogoVariable"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { UiServiceClient } from "@/services/grpc-client"
|
||||
@@ -9,7 +10,7 @@ interface HomeHeaderProps {
|
||||
}
|
||||
|
||||
const HomeHeader = ({ shouldShowQuickWins = false }: HomeHeaderProps) => {
|
||||
const { environment } = useExtensionState()
|
||||
const { environment, lazyTeammateModeEnabled } = useExtensionState()
|
||||
|
||||
const handleTakeATour = async () => {
|
||||
try {
|
||||
@@ -19,9 +20,10 @@ const HomeHeader = ({ shouldShowQuickWins = false }: HomeHeaderProps) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's December for festive logo
|
||||
// Lazy Teammate Mode takes priority, then December festive logo, then default
|
||||
const isDecember = new Date().getMonth() === 11 // 11 = December (0-indexed)
|
||||
const LogoComponent = isDecember ? ClineLogoSanta : ClineLogoVariable
|
||||
const LogoComponent = lazyTeammateModeEnabled ? ClineLogoTired : isDecember ? ClineLogoSanta : ClineLogoVariable
|
||||
const headingText = lazyTeammateModeEnabled ? "I guess I'm here to help" : "What can I do for you?"
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center mb-5">
|
||||
@@ -29,7 +31,7 @@ const HomeHeader = ({ shouldShowQuickWins = false }: HomeHeaderProps) => {
|
||||
<LogoComponent className="size-20" environment={environment} />
|
||||
</div>
|
||||
<div className="text-center flex items-center justify-center px-4">
|
||||
<h1 className="m-0 font-bold">What can I do for you?</h1>
|
||||
<h1 className="m-0 font-bold">{headingText}</h1>
|
||||
</div>
|
||||
{shouldShowQuickWins && (
|
||||
<div className="mt-4">
|
||||
@@ -38,7 +40,7 @@ const HomeHeader = ({ shouldShowQuickWins = false }: HomeHeaderProps) => {
|
||||
onClick={handleTakeATour}
|
||||
type="button">
|
||||
Take a Tour
|
||||
<span className="codicon codicon-play scale-90"></span>
|
||||
<span className="codicon codicon-play scale-90" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -277,6 +277,7 @@ export const ExtensionStateContextProvider: React.FC<{
|
||||
lastDismissedCliBannerVersion: 0,
|
||||
backgroundEditEnabled: false,
|
||||
doubleCheckCompletionEnabled: false,
|
||||
lazyTeammateModeEnabled: false,
|
||||
showFeatureTips: true,
|
||||
globalSkillsToggles: {},
|
||||
localSkillsToggles: {},
|
||||
|
||||
Reference in New Issue
Block a user