pluidr 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.md +365 -357
- package/bin/pluidr.js +3 -3
- package/package.json +45 -45
- package/src/cli/commands/doctor.js +101 -99
- package/src/cli/commands/init.js +43 -43
- package/src/cli/commands/launch.js +46 -0
- package/src/cli/commands/uninstall.js +63 -67
- package/src/cli/commands/update.js +6 -22
- package/src/cli/index.js +57 -53
- package/src/cli/wizard/selectModelTier.js +40 -39
- package/src/core/agentPromptWriter.js +32 -32
- package/src/core/agentPromptWriter.test.js +56 -56
- package/src/core/backup.js +40 -38
- package/src/core/configBuilder.js +32 -32
- package/src/core/configBuilder.test.js +93 -47
- package/src/core/configWriter.js +10 -10
- package/src/core/identityHeader.js +8 -8
- package/src/core/paths.js +9 -9
- package/src/core/paths.test.js +21 -21
- package/src/core/pluginWriter.js +29 -29
- package/src/core/squeezeInstaller.js +161 -161
- package/src/core/squeezeInstaller.test.js +75 -75
- package/src/core/version.js +8 -0
- package/src/core/versionCheck.js +44 -0
- package/src/core/versionCheck.test.js +34 -0
- package/src/plugins/README.md +68 -68
- package/src/plugins/pluidr-squeeze.js +77 -77
- package/src/templates/agent-prompts/auditor.txt +20 -20
- package/src/templates/agent-prompts/coder.txt +87 -87
- package/src/templates/agent-prompts/compose-reporter.txt +55 -55
- package/src/templates/agent-prompts/composer.txt +430 -430
- package/src/templates/agent-prompts/debug-reporter.txt +65 -65
- package/src/templates/agent-prompts/debugger.txt +151 -151
- package/src/templates/agent-prompts/fixer.txt +66 -66
- package/src/templates/agent-prompts/hierarchy.txt +96 -96
- package/src/templates/agent-prompts/inspector.txt +79 -79
- package/src/templates/agent-prompts/patcher.txt +20 -20
- package/src/templates/agent-prompts/plan-checker.txt +45 -45
- package/src/templates/agent-prompts/plan-writer.txt +57 -57
- package/src/templates/agent-prompts/probe-reporter.txt +62 -62
- package/src/templates/agent-prompts/prober.txt +90 -90
- package/src/templates/agent-prompts/researcher.txt +48 -48
- package/src/templates/agent-prompts/reviewer.txt +57 -57
- package/src/templates/agent-prompts/tester.txt +66 -66
- package/src/templates/agent-prompts/tracer.txt +33 -33
- package/src/templates/model-defaults.json +73 -55
- package/src/templates/opencode.config.json +481 -481
package/bin/pluidr.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { run } from "../src/cli/index.js"
|
|
3
|
-
|
|
4
|
-
run(process.argv)
|
|
2
|
+
import { run } from "../src/cli/index.js"
|
|
3
|
+
|
|
4
|
+
run(process.argv)
|
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pluidr",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Opinionated Engineering Workflow for OpenCode — Explore, Plan, Build, Debug, and Security-Audit.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"opencode",
|
|
7
|
-
"workflow",
|
|
8
|
-
"engineering",
|
|
9
|
-
"pipeline",
|
|
10
|
-
"ai-agents",
|
|
11
|
-
"code-review",
|
|
12
|
-
"debugging",
|
|
13
|
-
"security-audit",
|
|
14
|
-
"security",
|
|
15
|
-
"planner",
|
|
16
|
-
"builder",
|
|
17
|
-
"cli"
|
|
18
|
-
],
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"type": "module",
|
|
21
|
-
"scripts": {
|
|
22
|
-
"test": "node --test"
|
|
23
|
-
},
|
|
24
|
-
"bin": {
|
|
25
|
-
"pluidr": "bin/pluidr.js"
|
|
26
|
-
},
|
|
27
|
-
"repository": {
|
|
28
|
-
"type": "git",
|
|
29
|
-
"url": "git+https://github.com/funara/pluidr.git"
|
|
30
|
-
},
|
|
31
|
-
"homepage": "https://github.com/funara/pluidr#readme",
|
|
32
|
-
"bugs": {
|
|
33
|
-
"url": "https://github.com/funara/pluidr/issues"
|
|
34
|
-
},
|
|
35
|
-
"engines": {
|
|
36
|
-
"node": ">=18"
|
|
37
|
-
},
|
|
38
|
-
"files": [
|
|
39
|
-
"bin",
|
|
40
|
-
"src"
|
|
41
|
-
],
|
|
42
|
-
"dependencies": {
|
|
43
|
-
"@clack/prompts": "^0.9"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pluidr",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "Opinionated Engineering Workflow for OpenCode — Explore, Plan, Build, Debug, and Security-Audit.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"opencode",
|
|
7
|
+
"workflow",
|
|
8
|
+
"engineering",
|
|
9
|
+
"pipeline",
|
|
10
|
+
"ai-agents",
|
|
11
|
+
"code-review",
|
|
12
|
+
"debugging",
|
|
13
|
+
"security-audit",
|
|
14
|
+
"security",
|
|
15
|
+
"planner",
|
|
16
|
+
"builder",
|
|
17
|
+
"cli"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "node --test"
|
|
23
|
+
},
|
|
24
|
+
"bin": {
|
|
25
|
+
"pluidr": "bin/pluidr.js"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/funara/pluidr.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/funara/pluidr#readme",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/funara/pluidr/issues"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"bin",
|
|
40
|
+
"src"
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@clack/prompts": "^0.9"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,99 +1,101 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from "node:fs"
|
|
2
|
-
import { join
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
squeezeFound =
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
console.log("
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { getConfigDir, getConfigPath, getPromptsDir } from "../../core/paths.js"
|
|
4
|
+
import { findSqueezePath } from "../../core/squeezeInstaller.js"
|
|
5
|
+
|
|
6
|
+
const EXPECTED_PROMPT_COUNT = 18
|
|
7
|
+
const PLUGIN_FILES = ["pluidr-flow.js", "pluidr-squeeze.js"]
|
|
8
|
+
|
|
9
|
+
export function collectChecks() {
|
|
10
|
+
const configDir = getConfigDir()
|
|
11
|
+
const configPath = getConfigPath()
|
|
12
|
+
const promptsDir = getPromptsDir()
|
|
13
|
+
const pluginsDir = join(configDir, "plugins")
|
|
14
|
+
const packageJsonPath = join(configDir, "package.json")
|
|
15
|
+
const binDir = join(configDir, "bin")
|
|
16
|
+
|
|
17
|
+
const checks = []
|
|
18
|
+
|
|
19
|
+
// 1. opencode.jsonc exists
|
|
20
|
+
const configExists = existsSync(configPath)
|
|
21
|
+
checks.push({ component: "opencode.jsonc", pass: configExists })
|
|
22
|
+
|
|
23
|
+
// 2. All 18 prompt files exist
|
|
24
|
+
let promptCount = 0
|
|
25
|
+
if (existsSync(promptsDir)) {
|
|
26
|
+
try {
|
|
27
|
+
const files = readdirSync(promptsDir).filter((f) => f.endsWith(".txt"))
|
|
28
|
+
promptCount = files.length
|
|
29
|
+
} catch {
|
|
30
|
+
promptCount = 0
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
checks.push({ component: "18 prompt files", pass: promptCount === EXPECTED_PROMPT_COUNT, detail: `${promptCount}/${EXPECTED_PROMPT_COUNT}` })
|
|
34
|
+
|
|
35
|
+
// 3. Both plugin files exist
|
|
36
|
+
let pluginsFound = 0
|
|
37
|
+
for (const f of PLUGIN_FILES) {
|
|
38
|
+
if (existsSync(join(pluginsDir, f))) pluginsFound++
|
|
39
|
+
}
|
|
40
|
+
checks.push({ component: "plugin files", pass: pluginsFound === PLUGIN_FILES.length, detail: `${pluginsFound}/${PLUGIN_FILES.length}` })
|
|
41
|
+
|
|
42
|
+
// 4. package.json with @opencode-ai/plugin dependency
|
|
43
|
+
let pkgValid = false
|
|
44
|
+
if (existsSync(packageJsonPath)) {
|
|
45
|
+
try {
|
|
46
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"))
|
|
47
|
+
pkgValid = !!(pkg.dependencies && pkg.dependencies["@opencode-ai/plugin"])
|
|
48
|
+
} catch {
|
|
49
|
+
pkgValid = false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
checks.push({ component: "package.json + plugin dep", pass: pkgValid })
|
|
53
|
+
|
|
54
|
+
// 5. Squeeze binary exists
|
|
55
|
+
let squeezeFound = false
|
|
56
|
+
const squeezeOnPath = findSqueezePath()
|
|
57
|
+
if (squeezeOnPath) {
|
|
58
|
+
squeezeFound = true
|
|
59
|
+
} else {
|
|
60
|
+
const binName = process.platform === "win32" ? "squeeze.exe" : "squeeze"
|
|
61
|
+
squeezeFound = existsSync(join(binDir, binName))
|
|
62
|
+
}
|
|
63
|
+
checks.push({ component: "squeeze binary tested", pass: squeezeFound })
|
|
64
|
+
|
|
65
|
+
// 6. Config is valid JSON/JSONC
|
|
66
|
+
let configValid = false
|
|
67
|
+
if (configExists) {
|
|
68
|
+
try {
|
|
69
|
+
const content = readFileSync(configPath, "utf-8")
|
|
70
|
+
const cleaned = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m)
|
|
71
|
+
JSON.parse(cleaned)
|
|
72
|
+
configValid = true
|
|
73
|
+
} catch {
|
|
74
|
+
configValid = false
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
checks.push({ component: "config JSON validity", pass: configValid })
|
|
78
|
+
|
|
79
|
+
return checks
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function runDoctor() {
|
|
83
|
+
const checks = collectChecks()
|
|
84
|
+
const allPass = checks.every((c) => c.pass)
|
|
85
|
+
|
|
86
|
+
console.log("\nPluidr Doctor — Installation Health Check\n")
|
|
87
|
+
for (const c of checks) {
|
|
88
|
+
const icon = c.pass ? "\u2713" : "\u2717"
|
|
89
|
+
const detail = c.detail ? ` (${c.detail})` : ""
|
|
90
|
+
console.log(` ${icon} ${c.component}${detail}`)
|
|
91
|
+
}
|
|
92
|
+
console.log("")
|
|
93
|
+
|
|
94
|
+
if (allPass) {
|
|
95
|
+
console.log("All checks passed.")
|
|
96
|
+
} else {
|
|
97
|
+
console.log("Some checks failed. Re-run `pluidr init` to repair.")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
process.exit(allPass ? 0 : 1)
|
|
101
|
+
}
|
package/src/cli/commands/init.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs"
|
|
2
|
-
import { resolve, dirname } from "node:path"
|
|
3
|
-
import { fileURLToPath } from "node:url"
|
|
4
|
-
import { confirm, isCancel } from "@clack/prompts"
|
|
5
|
-
import { selectModelTier } from "../wizard/selectModelTier.js"
|
|
6
|
-
import { backupExistingConfig } from "../../core/backup.js"
|
|
7
|
-
import { buildConfig } from "../../core/configBuilder.js"
|
|
8
|
-
import { writeConfig } from "../../core/configWriter.js"
|
|
9
|
-
import { writeAgentPrompts } from "../../core/agentPromptWriter.js"
|
|
10
|
-
import { writePluginBundle, writePluginPackageJson } from "../../core/pluginWriter.js"
|
|
11
|
-
import { installSqueeze } from "../../core/squeezeInstaller.js"
|
|
12
|
-
import { getConfigPath } from "../../core/paths.js"
|
|
13
|
-
|
|
14
|
-
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
15
|
-
const TEMPLATES_DIR = resolve(__dirname, "../../templates")
|
|
16
|
-
|
|
17
|
-
export async function runInit() {
|
|
18
|
-
const defaultsPath = resolve(TEMPLATES_DIR, "model-defaults.json")
|
|
19
|
-
const modelDefaults = JSON.parse(readFileSync(defaultsPath, "utf-8"))
|
|
20
|
-
|
|
21
|
-
const tierChoices = await selectModelTier(modelDefaults)
|
|
22
|
-
|
|
23
|
-
const squeezeAnswer = await confirm({
|
|
24
|
-
message: "Install pluidr-squeeze plugin? Reduces bash output tokens by 60-90%.",
|
|
25
|
-
initialValue: true,
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const installSqueezePlugin = isCancel(squeezeAnswer) ?
|
|
29
|
-
|
|
30
|
-
backupExistingConfig()
|
|
31
|
-
|
|
32
|
-
const configObject = buildConfig(tierChoices, TEMPLATES_DIR)
|
|
33
|
-
writeConfig(configObject)
|
|
34
|
-
writeAgentPrompts(TEMPLATES_DIR)
|
|
35
|
-
writePluginBundle()
|
|
36
|
-
writePluginPackageJson()
|
|
37
|
-
if (installSqueezePlugin) {
|
|
38
|
-
await installSqueeze()
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const path = getConfigPath().replace(/\\/g, "/").replace(/^\//, "")
|
|
42
|
-
console.log(`Pluidr setup complete!\nYou can update your agent model settings later in \x1b]8;;file:///${path}\x1b\\opencode.jsonc\x1b]8;;\x1b\\`)
|
|
43
|
-
}
|
|
1
|
+
import { readFileSync } from "node:fs"
|
|
2
|
+
import { resolve, dirname } from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
import { confirm, isCancel } from "@clack/prompts"
|
|
5
|
+
import { selectModelTier } from "../wizard/selectModelTier.js"
|
|
6
|
+
import { backupExistingConfig } from "../../core/backup.js"
|
|
7
|
+
import { buildConfig } from "../../core/configBuilder.js"
|
|
8
|
+
import { writeConfig } from "../../core/configWriter.js"
|
|
9
|
+
import { writeAgentPrompts } from "../../core/agentPromptWriter.js"
|
|
10
|
+
import { writePluginBundle, writePluginPackageJson } from "../../core/pluginWriter.js"
|
|
11
|
+
import { installSqueeze } from "../../core/squeezeInstaller.js"
|
|
12
|
+
import { getConfigPath } from "../../core/paths.js"
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
15
|
+
const TEMPLATES_DIR = resolve(__dirname, "../../templates")
|
|
16
|
+
|
|
17
|
+
export async function runInit() {
|
|
18
|
+
const defaultsPath = resolve(TEMPLATES_DIR, "model-defaults.json")
|
|
19
|
+
const modelDefaults = JSON.parse(readFileSync(defaultsPath, "utf-8"))
|
|
20
|
+
|
|
21
|
+
const tierChoices = await selectModelTier(modelDefaults)
|
|
22
|
+
|
|
23
|
+
const squeezeAnswer = await confirm({
|
|
24
|
+
message: "Install pluidr-squeeze plugin? Reduces bash output tokens by 60-90%.",
|
|
25
|
+
initialValue: true,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const installSqueezePlugin = isCancel(squeezeAnswer) ? false : squeezeAnswer
|
|
29
|
+
|
|
30
|
+
backupExistingConfig()
|
|
31
|
+
|
|
32
|
+
const configObject = buildConfig(tierChoices, TEMPLATES_DIR)
|
|
33
|
+
writeConfig(configObject)
|
|
34
|
+
writeAgentPrompts(TEMPLATES_DIR)
|
|
35
|
+
writePluginBundle()
|
|
36
|
+
writePluginPackageJson()
|
|
37
|
+
if (installSqueezePlugin) {
|
|
38
|
+
await installSqueeze()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const path = getConfigPath().replace(/\\/g, "/").replace(/^\//, "")
|
|
42
|
+
console.log(`Pluidr setup complete!\nYou can update your agent model settings later in \x1b]8;;file:///${path}\x1b\\opencode.jsonc\x1b]8;;\x1b\\`)
|
|
43
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { spawn } from "node:child_process"
|
|
2
|
+
import { confirm, isCancel } from "@clack/prompts"
|
|
3
|
+
import { checkAndPromptUpdate } from "../../core/versionCheck.js"
|
|
4
|
+
import { version } from "../../core/version.js"
|
|
5
|
+
import { collectChecks } from "./doctor.js"
|
|
6
|
+
import { runInit } from "./init.js"
|
|
7
|
+
|
|
8
|
+
export async function runLaunch() {
|
|
9
|
+
// 1. Update check
|
|
10
|
+
await checkAndPromptUpdate(version)
|
|
11
|
+
|
|
12
|
+
// 2. Doctor check
|
|
13
|
+
process.stdout.write("Running doctor... ")
|
|
14
|
+
const checks = collectChecks()
|
|
15
|
+
const allPass = checks.every((c) => c.pass)
|
|
16
|
+
|
|
17
|
+
if (allPass) {
|
|
18
|
+
console.log("✓ All checks passed")
|
|
19
|
+
} else {
|
|
20
|
+
const failed = checks.filter((c) => !c.pass)
|
|
21
|
+
console.log(`✗ ${failed.length} check${failed.length > 1 ? "s" : ""} failed`)
|
|
22
|
+
for (const c of failed) {
|
|
23
|
+
const detail = c.detail ? ` (${c.detail})` : ""
|
|
24
|
+
console.log(` ✗ ${c.component}${detail}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const answer = await confirm({ message: "Repair with pluidr init?", initialValue: true })
|
|
28
|
+
if (!isCancel(answer) && answer) {
|
|
29
|
+
await runInit()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 3. Launch opencode
|
|
34
|
+
console.log("Launching opencode...")
|
|
35
|
+
const child = process.platform === "win32"
|
|
36
|
+
? spawn("opencode", { stdio: "inherit", shell: true })
|
|
37
|
+
: spawn("opencode", [], { stdio: "inherit" })
|
|
38
|
+
child.on("error", (err) => {
|
|
39
|
+
if (err.code === "ENOENT") {
|
|
40
|
+
console.error("Error: opencode not found on PATH. Install it from https://opencode.ai")
|
|
41
|
+
} else {
|
|
42
|
+
console.error(`Error launching opencode: ${err.message}`)
|
|
43
|
+
}
|
|
44
|
+
process.exit(1)
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -1,67 +1,63 @@
|
|
|
1
|
-
import { existsSync, copyFileSync, rmSync, readdirSync } from "node:fs"
|
|
2
|
-
import { join
|
|
3
|
-
import { getConfigDir, getConfigPath } from "../../core/paths.js"
|
|
4
|
-
|
|
5
|
-
function findLatestBackup() {
|
|
6
|
-
const dir = getConfigDir()
|
|
7
|
-
let backups = []
|
|
8
|
-
try {
|
|
9
|
-
backups = readdirSync(dir)
|
|
10
|
-
.filter((f) => f.startsWith("opencode.jsonc.bak."))
|
|
11
|
-
.sort()
|
|
12
|
-
.reverse()
|
|
13
|
-
} catch {
|
|
14
|
-
return null
|
|
15
|
-
}
|
|
16
|
-
return backups.length > 0 ? join(dir, backups[0]) : null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function runUninstall() {
|
|
20
|
-
const configDir = getConfigDir()
|
|
21
|
-
const configPath = getConfigPath()
|
|
22
|
-
const promptsDir = join(configDir, "prompts")
|
|
23
|
-
const pluginsDir = join(configDir, "plugins")
|
|
24
|
-
const binDir = join(configDir, "bin")
|
|
25
|
-
|
|
26
|
-
const summary = { restored: null, removed: [] }
|
|
27
|
-
|
|
28
|
-
// Restore latest backup
|
|
29
|
-
const latestBackup = findLatestBackup()
|
|
30
|
-
if (latestBackup
|
|
31
|
-
copyFileSync(latestBackup, configPath)
|
|
32
|
-
summary.restored = latestBackup
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (existsSync(
|
|
41
|
-
rmSync(
|
|
42
|
-
summary.removed.push("
|
|
43
|
-
}
|
|
44
|
-
if (existsSync(
|
|
45
|
-
rmSync(
|
|
46
|
-
summary.removed.push("
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
console.log(" - Kept opencode.jsonc (preserves user customizations)")
|
|
66
|
-
console.log(" - Kept package.json (may be used by other plugins)")
|
|
67
|
-
}
|
|
1
|
+
import { existsSync, copyFileSync, rmSync, readdirSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { getConfigDir, getConfigPath } from "../../core/paths.js"
|
|
4
|
+
|
|
5
|
+
function findLatestBackup() {
|
|
6
|
+
const dir = getConfigDir()
|
|
7
|
+
let backups = []
|
|
8
|
+
try {
|
|
9
|
+
backups = readdirSync(dir)
|
|
10
|
+
.filter((f) => f.startsWith("opencode.jsonc.bak."))
|
|
11
|
+
.sort()
|
|
12
|
+
.reverse()
|
|
13
|
+
} catch {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
return backups.length > 0 ? join(dir, backups[0]) : null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function runUninstall() {
|
|
20
|
+
const configDir = getConfigDir()
|
|
21
|
+
const configPath = getConfigPath()
|
|
22
|
+
const promptsDir = join(configDir, "prompts")
|
|
23
|
+
const pluginsDir = join(configDir, "plugins")
|
|
24
|
+
const binDir = join(configDir, "bin")
|
|
25
|
+
|
|
26
|
+
const summary = { restored: null, removed: [] }
|
|
27
|
+
|
|
28
|
+
// Restore latest backup
|
|
29
|
+
const latestBackup = findLatestBackup()
|
|
30
|
+
if (latestBackup) {
|
|
31
|
+
copyFileSync(latestBackup, configPath)
|
|
32
|
+
summary.restored = latestBackup
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Remove Pluidr-installed artifacts
|
|
36
|
+
if (existsSync(promptsDir)) {
|
|
37
|
+
rmSync(promptsDir, { recursive: true, force: true })
|
|
38
|
+
summary.removed.push("prompts/")
|
|
39
|
+
}
|
|
40
|
+
if (existsSync(pluginsDir)) {
|
|
41
|
+
rmSync(pluginsDir, { recursive: true, force: true })
|
|
42
|
+
summary.removed.push("plugins/")
|
|
43
|
+
}
|
|
44
|
+
if (existsSync(binDir)) {
|
|
45
|
+
rmSync(binDir, { recursive: true, force: true })
|
|
46
|
+
summary.removed.push("bin/")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Print summary
|
|
50
|
+
console.log("Uninstall complete:")
|
|
51
|
+
if (summary.restored) {
|
|
52
|
+
console.log(` ✓ Restored ${summary.restored}`)
|
|
53
|
+
} else {
|
|
54
|
+
console.log(" - No backup found to restore")
|
|
55
|
+
}
|
|
56
|
+
if (summary.removed.length > 0) {
|
|
57
|
+
console.log(` ✓ Removed: ${summary.removed.join(", ")}`)
|
|
58
|
+
} else {
|
|
59
|
+
console.log(" - No Pluidr artifacts found to remove")
|
|
60
|
+
}
|
|
61
|
+
console.log(" - Kept opencode.jsonc (preserves user customizations)")
|
|
62
|
+
console.log(" - Kept package.json (may be used by other plugins)")
|
|
63
|
+
}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const configPath = getConfigPath()
|
|
8
|
-
|
|
9
|
-
if (existsSync(configPath)) {
|
|
10
|
-
const answer = await confirm({
|
|
11
|
-
message: "Existing Pluidr config found. Overwrite? (Y/n)",
|
|
12
|
-
initialValue: true,
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
if (isCancel(answer) || !answer) {
|
|
16
|
-
console.log("Update cancelled.")
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
await runInit()
|
|
22
|
-
}
|
|
1
|
+
import { checkAndPromptUpdate } from "../../core/versionCheck.js"
|
|
2
|
+
import { version } from "../../core/version.js"
|
|
3
|
+
|
|
4
|
+
export async function runUpdate() {
|
|
5
|
+
await checkAndPromptUpdate(version)
|
|
6
|
+
}
|