mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
Merge 60c167d342 into 83397ebde2
This commit is contained in:
commit
06cc7b5b57
4 changed files with 163 additions and 38 deletions
119
packages/opencode/src/cli/cmd/cache.ts
Normal file
119
packages/opencode/src/cli/cmd/cache.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import type { Argv } from "yargs"
|
||||
import { cmd } from "./cmd"
|
||||
import * as prompts from "@clack/prompts"
|
||||
import { Global } from "../../global"
|
||||
import { getDirectorySize, formatSize, shortenPath } from "../util"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
|
||||
const CacheCleanCommand = cmd({
|
||||
command: "clean",
|
||||
describe: "remove cached plugins and packages",
|
||||
builder: (yargs: Argv) =>
|
||||
yargs
|
||||
.option("force", {
|
||||
alias: "f",
|
||||
type: "boolean",
|
||||
describe: "skip confirmation prompt",
|
||||
default: false,
|
||||
})
|
||||
.option("dry-run", {
|
||||
type: "boolean",
|
||||
describe: "show what would be removed without removing",
|
||||
default: false,
|
||||
}),
|
||||
async handler(args) {
|
||||
const exists = await fs
|
||||
.access(Global.Path.cache)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
|
||||
if (!exists) {
|
||||
prompts.log.info("Cache directory does not exist")
|
||||
return
|
||||
}
|
||||
|
||||
const size = await getDirectorySize(Global.Path.cache)
|
||||
|
||||
prompts.log.info(`Cache: ${shortenPath(Global.Path.cache)} (${formatSize(size)})`)
|
||||
|
||||
if (args.dryRun) {
|
||||
prompts.log.warn("Dry run - no changes made")
|
||||
return
|
||||
}
|
||||
|
||||
if (!args.force) {
|
||||
const confirm = await prompts.confirm({
|
||||
message: "Remove cache directory?",
|
||||
initialValue: true,
|
||||
})
|
||||
if (!confirm || prompts.isCancel(confirm)) {
|
||||
prompts.log.warn("Cancelled")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const spinner = prompts.spinner()
|
||||
spinner.start("Removing cache...")
|
||||
|
||||
const err = await fs.rm(Global.Path.cache, { recursive: true, force: true }).catch((e) => e)
|
||||
if (err) {
|
||||
spinner.stop("Failed to remove cache", 1)
|
||||
prompts.log.error(err.message)
|
||||
return
|
||||
}
|
||||
|
||||
spinner.stop("Cache removed")
|
||||
},
|
||||
})
|
||||
|
||||
const CacheInfoCommand = cmd({
|
||||
command: "info",
|
||||
describe: "show cache directory information",
|
||||
async handler() {
|
||||
const exists = await fs
|
||||
.access(Global.Path.cache)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
|
||||
prompts.log.info(`Path: ${shortenPath(Global.Path.cache)}`)
|
||||
|
||||
if (!exists) {
|
||||
prompts.log.info("Status: not created")
|
||||
return
|
||||
}
|
||||
|
||||
const size = await getDirectorySize(Global.Path.cache)
|
||||
prompts.log.info(`Size: ${formatSize(size)}`)
|
||||
|
||||
const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json"))
|
||||
const parsed = await pkgjson.json().catch(() => null)
|
||||
|
||||
if (parsed?.dependencies) {
|
||||
const deps = Object.entries(parsed.dependencies)
|
||||
if (deps.length > 0) {
|
||||
prompts.log.info(`Packages:`)
|
||||
for (const [pkg, version] of deps) {
|
||||
prompts.log.info(` ${pkg}@${version}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const versionFile = Bun.file(path.join(Global.Path.cache, "version"))
|
||||
const version = await versionFile.text().catch(() => null)
|
||||
if (version) {
|
||||
prompts.log.info(`Cache version: ${version.trim()}`)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const CacheCommand = cmd({
|
||||
command: "cache",
|
||||
describe: "manage plugin and package cache",
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.command(CacheCleanCommand)
|
||||
.command(CacheInfoCommand)
|
||||
.demandCommand(1, "Please specify a subcommand: clean or info"),
|
||||
async handler() {},
|
||||
})
|
||||
|
|
@ -3,6 +3,7 @@ import { UI } from "../ui"
|
|||
import * as prompts from "@clack/prompts"
|
||||
import { Installation } from "../../installation"
|
||||
import { Global } from "../../global"
|
||||
import { getDirectorySize, formatSize, shortenPath } from "../util"
|
||||
import { $ } from "bun"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
|
|
@ -304,41 +305,3 @@ async function cleanShellConfig(file: string) {
|
|||
const output = filtered.join("\n") + "\n"
|
||||
await Bun.write(file, output)
|
||||
}
|
||||
|
||||
async function getDirectorySize(dir: string): Promise<number> {
|
||||
let total = 0
|
||||
|
||||
const walk = async (current: string) => {
|
||||
const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])
|
||||
|
||||
for (const entry of entries) {
|
||||
const full = path.join(current, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
await walk(full)
|
||||
continue
|
||||
}
|
||||
if (entry.isFile()) {
|
||||
const stat = await fs.stat(full).catch(() => null)
|
||||
if (stat) total += stat.size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await walk(dir)
|
||||
return total
|
||||
}
|
||||
|
||||
function formatSize(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
||||
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`
|
||||
}
|
||||
|
||||
function shortenPath(p: string): string {
|
||||
const home = os.homedir()
|
||||
if (p.startsWith(home)) {
|
||||
return p.replace(home, "~")
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
|
|
|||
41
packages/opencode/src/cli/util.ts
Normal file
41
packages/opencode/src/cli/util.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
|
||||
export async function getDirectorySize(dir: string): Promise<number> {
|
||||
let total = 0
|
||||
|
||||
const walk = async (current: string) => {
|
||||
const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])
|
||||
|
||||
for (const entry of entries) {
|
||||
const full = path.join(current, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
await walk(full)
|
||||
continue
|
||||
}
|
||||
if (entry.isFile()) {
|
||||
const stat = await fs.stat(full).catch(() => null)
|
||||
if (stat) total += stat.size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await walk(dir)
|
||||
return total
|
||||
}
|
||||
|
||||
export function formatSize(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
||||
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`
|
||||
}
|
||||
|
||||
export function shortenPath(p: string): string {
|
||||
const home = os.homedir()
|
||||
if (p.startsWith(home)) {
|
||||
return p.replace(home, "~")
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import { EOL } from "os"
|
|||
import { WebCommand } from "./cli/cmd/web"
|
||||
import { PrCommand } from "./cli/cmd/pr"
|
||||
import { SessionCommand } from "./cli/cmd/session"
|
||||
import { CacheCommand } from "./cli/cmd/cache"
|
||||
|
||||
process.on("unhandledRejection", (e) => {
|
||||
Log.Default.error("rejection", {
|
||||
|
|
@ -98,6 +99,7 @@ const cli = yargs(hideBin(process.argv))
|
|||
.command(GithubCommand)
|
||||
.command(PrCommand)
|
||||
.command(SessionCommand)
|
||||
.command(CacheCommand)
|
||||
.fail((msg) => {
|
||||
if (
|
||||
msg.startsWith("Unknown argument") ||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue