opencode-agent-skill 13.0.0-beta.2 → 14.2.0-beta.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/README.md +1556 -607
- package/bin/ocskill.mjs +172 -24
- package/docs/OPENCODE-COMPAT.md +34 -97
- package/docs/PI-COMPAT.md +188 -0
- package/docs/V14-CONTEXT-MEMORY-FABRIC.md +70 -0
- package/docs/V14.1-QUALITY-PERFORMANCE-FABRIC.md +114 -0
- package/docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md +448 -0
- package/evals/v14/tasks.json +46 -0
- package/global-config/agents/executor.md +7 -0
- package/global-config/agents/visual-verifier.md +22 -3
- package/global-config/plugins/ues-router/index.js +13 -8
- package/global-config/plugins/ues-router/policy-runtime.js +7 -0
- package/global-config/plugins/ues-router/router.js +12 -2
- package/global-config/skills/ecommerce-engineering/SKILL.md +1 -1
- package/global-config/skills/file-upload-engineering/SKILL.md +1 -1
- package/global-config/skills/git-safety/SKILL.md +1 -1
- package/global-config/skills/nestjs-engineering/SKILL.md +1 -1
- package/global-config/skills/performance-engineering/SKILL.md +1 -1
- package/global-config/skills/react-native-engineering/SKILL.md +1 -1
- package/global-config/skills/rest-api-design/SKILL.md +1 -1
- package/global-config/skills/ui-ux-engineering/SKILL.md +1 -1
- package/lib/adaptive-context-budget.mjs +97 -0
- package/lib/affected-tests.mjs +260 -0
- package/lib/benchmark-confidence.mjs +41 -2
- package/lib/browser-mcp-routing.mjs +166 -0
- package/lib/capability-fabric.mjs +336 -0
- package/lib/capability-registry.mjs +9 -0
- package/lib/context-engine-v11.mjs +65 -1
- package/lib/context-graph-rank.mjs +118 -0
- package/lib/context-manifest.mjs +97 -18
- package/lib/control-center.mjs +19 -1
- package/lib/dynamic-workflow.mjs +3 -1
- package/lib/evidence-store.mjs +82 -1
- package/lib/hierarchical-context.mjs +215 -0
- package/lib/memory-engine.mjs +465 -0
- package/lib/model-performance.mjs +33 -8
- package/lib/model-policy.mjs +3 -3
- package/lib/orchestrator-policy.mjs +5 -209
- package/lib/performance-fabric.mjs +229 -0
- package/lib/pi-rpc-pool.mjs +433 -0
- package/lib/process-hang-detector.mjs +83 -0
- package/lib/process-supervisor.mjs +193 -0
- package/lib/prompt-cache.mjs +2 -0
- package/lib/repo-graph.mjs +53 -2
- package/lib/runtime-config.mjs +31 -0
- package/lib/safety.mjs +132 -0
- package/lib/semantic-index.mjs +52 -3
- package/lib/skill-compiler.mjs +128 -0
- package/lib/skill-quality.mjs +48 -2
- package/lib/task-engine.mjs +66 -5
- package/lib/task-policy.mjs +235 -0
- package/lib/verification-broker.mjs +284 -0
- package/lib/verification-command.mjs +111 -0
- package/lib/windows-shim.mjs +35 -0
- package/lib/workspace-fingerprint.mjs +198 -0
- package/package.json +52 -42
- package/pi/extensions/ues-child-runtime.ts +238 -0
- package/pi/extensions/ues.ts +3200 -0
- package/pi/prompts/ues-audit.md +9 -0
- package/pi/prompts/ues-critique.md +9 -0
- package/pi/prompts/ues-debug.md +9 -0
- package/pi/prompts/ues-feature.md +9 -0
- package/pi/prompts/ues-fix.md +9 -0
- package/pi/prompts/ues-plan.md +9 -0
- package/pi/prompts/ues-research.md +9 -0
- package/pi/prompts/ues-resume.md +9 -0
- package/pi/prompts/ues-review.md +7 -0
- package/pi/prompts/ues-run.md +17 -0
- package/pi/prompts/ues-verify.md +9 -0
- package/scripts/check-release-consistency.mjs +119 -185
- package/scripts/check-runtime-exports.mjs +66 -0
- package/scripts/check-source-integrity.mjs +184 -0
- package/scripts/eval-pi.mjs +492 -0
- package/scripts/install.mjs +16 -0
- package/scripts/smoke-package-closure.mjs +110 -0
- package/scripts/smoke-packed-install.mjs +24 -11
- package/scripts/smoke-pi-extension.mjs +144 -0
- package/scripts/uninstall.mjs +44 -0
- package/CHANGELOG.md +0 -415
- package/docs/DETERMINISTIC-TOOLS.md +0 -105
- package/docs/ENGINEERING-DESIGN.md +0 -194
- package/docs/EVALS.md +0 -158
- package/docs/GITHUB-RULESET.md +0 -50
- package/docs/NPM-PUBLISH.md +0 -116
- package/docs/RESEARCH-SOURCES.md +0 -37
- package/docs/TRACE-SCHEMA.md +0 -122
- package/docs/V11-PERCEPTION-ADAPTIVE-EXECUTION.md +0 -75
- package/docs/V11-PERCEPTION-ADAPTIVE.md +0 -220
- package/docs/V12-WEAK-MODEL-INTELLIGENCE.md +0 -27
- package/docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md +0 -86
- package/docs/V7-INTELLIGENCE-RUNTIME.md +0 -166
- package/docs/V8-INTELLIGENCE-RELIABILITY.md +0 -206
- package/docs/V9-SPEED-INTELLIGENCE.md +0 -102
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import { spawnSync } from "node:child_process"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
import { resolveWindowsCommand } from "../lib/windows-shim.mjs"
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
9
|
+
|
|
10
|
+
function run(executable, args, options = {}) {
|
|
11
|
+
if (process.platform !== "win32") return spawnSync(executable, args, options)
|
|
12
|
+
const resolved = resolveWindowsCommand(executable)
|
|
13
|
+
if (!resolved) {
|
|
14
|
+
return { status: 127, stdout: "", stderr: "Unable to resolve Windows command: " + executable }
|
|
15
|
+
}
|
|
16
|
+
return spawnSync(resolved.executable, [...resolved.argsPrefix, ...args], options)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseJsonOutput(result, label) {
|
|
20
|
+
assert.equal(result.status, 0, label + " failed: " + String(result.stderr || result.stdout || ""))
|
|
21
|
+
return JSON.parse(String(result.stdout || "").trim())
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const packed = parseJsonOutput(
|
|
25
|
+
run("npm", ["pack", "--dry-run", "--json", "--ignore-scripts"], {
|
|
26
|
+
cwd: root,
|
|
27
|
+
encoding: "utf8",
|
|
28
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
29
|
+
}),
|
|
30
|
+
"npm pack --dry-run",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
assert.ok(Array.isArray(packed) && packed.length >= 1, "npm pack did not return package metadata")
|
|
34
|
+
const files = new Set((packed[0].files || []).map((entry) => String(entry.path).replaceAll("\\", "/")))
|
|
35
|
+
|
|
36
|
+
for (const required of [
|
|
37
|
+
"bin/ocskill.mjs",
|
|
38
|
+
"pi/extensions/ues.ts",
|
|
39
|
+
"pi/extensions/ues-child-runtime.ts",
|
|
40
|
+
"docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md",
|
|
41
|
+
"lib/process-supervisor.mjs",
|
|
42
|
+
"lib/pi-rpc-pool.mjs",
|
|
43
|
+
"lib/adaptive-context-budget.mjs",
|
|
44
|
+
"lib/skill-compiler.mjs",
|
|
45
|
+
"lib/affected-tests.mjs",
|
|
46
|
+
"lib/verification-broker.mjs",
|
|
47
|
+
"lib/verification-command.mjs",
|
|
48
|
+
"lib/task-policy.mjs",
|
|
49
|
+
"lib/model-policy.mjs",
|
|
50
|
+
"lib/context-engine-v11.mjs",
|
|
51
|
+
"lib/runtime-config.mjs",
|
|
52
|
+
"scripts/eval-pi.mjs",
|
|
53
|
+
"scripts/eval-report.mjs",
|
|
54
|
+
"evals/live/tasks.json",
|
|
55
|
+
"global-config/AGENTS.md",
|
|
56
|
+
"global-config/commands/run.md",
|
|
57
|
+
"global-config/plugins/ues-router/index.js",
|
|
58
|
+
]) {
|
|
59
|
+
assert.ok(files.has(required), "packed package is missing required runtime file: " + required)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const controllerStat = (packed[0].files || []).find((entry) => String(entry.path).replaceAll("\\", "/") === "pi/extensions/ues.ts")
|
|
63
|
+
assert.ok(Number(controllerStat?.size || 0) > 80_000, "packed UES controller appears truncated")
|
|
64
|
+
|
|
65
|
+
const childRuntimeStat = (packed[0].files || []).find((entry) => String(entry.path).replaceAll("\\", "/") === "pi/extensions/ues-child-runtime.ts")
|
|
66
|
+
assert.ok(Number(childRuntimeStat?.size || 0) > 6_000, "packed UES child runtime appears truncated")
|
|
67
|
+
|
|
68
|
+
const codeFiles = [...files].filter((file) => /\.(?:mjs|js|ts)$/.test(file))
|
|
69
|
+
const missingRelativeImports = []
|
|
70
|
+
|
|
71
|
+
function resolvePackedImport(fromFile, specifier) {
|
|
72
|
+
const base = path.posix.normalize(path.posix.join(path.posix.dirname(fromFile), specifier))
|
|
73
|
+
const candidates = path.posix.extname(base)
|
|
74
|
+
? [base]
|
|
75
|
+
: [base, base + ".mjs", base + ".js", base + ".ts", path.posix.join(base, "index.mjs"), path.posix.join(base, "index.js")]
|
|
76
|
+
return candidates.find((candidate) => existsSync(path.join(root, ...candidate.split("/")))) || null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (const file of codeFiles) {
|
|
80
|
+
const absolute = path.join(root, ...file.split("/"))
|
|
81
|
+
if (!existsSync(absolute)) continue
|
|
82
|
+
const source = readFileSync(absolute, "utf8")
|
|
83
|
+
const regex = /(?:\bfrom\s+|\bimport\s*\(\s*|\bimport\s+)[\"'](\.{1,2}\/[^\"']+)[\"']/g
|
|
84
|
+
let match
|
|
85
|
+
while ((match = regex.exec(source))) {
|
|
86
|
+
const resolved = resolvePackedImport(file, match[1])
|
|
87
|
+
if (resolved && !files.has(resolved)) {
|
|
88
|
+
missingRelativeImports.push({ from: file, import: match[1], resolved })
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
assert.deepEqual(
|
|
94
|
+
missingRelativeImports,
|
|
95
|
+
[],
|
|
96
|
+
"packed runtime has relative imports to files excluded from npm package: " + JSON.stringify(missingRelativeImports),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const taskPolicy = parseJsonOutput(
|
|
100
|
+
run(process.execPath, [path.join(root, "bin", "ocskill.mjs"), "task-policy", "fix a high-risk authentication bug", "--json"], {
|
|
101
|
+
cwd: root,
|
|
102
|
+
encoding: "utf8",
|
|
103
|
+
maxBuffer: 1024 * 1024,
|
|
104
|
+
}),
|
|
105
|
+
"packaged task-policy smoke",
|
|
106
|
+
)
|
|
107
|
+
assert.equal(taskPolicy.risk, "high")
|
|
108
|
+
assert.equal(taskPolicy.modelTier, "heavy")
|
|
109
|
+
|
|
110
|
+
console.log(`Package closure smoke passed: ${files.size} packed file(s), ${codeFiles.length} code file(s) checked`)
|
|
@@ -38,6 +38,7 @@ const temp = await mkdtemp(path.join(os.tmpdir(), "ocskill-pack-smoke-"))
|
|
|
38
38
|
const packDir = path.join(temp, "pack")
|
|
39
39
|
const prefix = path.join(temp, "prefix")
|
|
40
40
|
const configDir = path.join(temp, "opencode")
|
|
41
|
+
const uesConfigDir = path.join(temp, "ues-config")
|
|
41
42
|
|
|
42
43
|
try {
|
|
43
44
|
await mkdir(packDir, { recursive: true })
|
|
@@ -49,19 +50,13 @@ try {
|
|
|
49
50
|
assert.equal(tarballs.length, 1, "expected exactly one packed tarball")
|
|
50
51
|
const tarball = path.join(packDir, tarballs[0])
|
|
51
52
|
|
|
52
|
-
const
|
|
53
|
-
requireSuccess(npmVersion, "npm --version")
|
|
54
|
-
const npmMajor = Number.parseInt(npmVersion.stdout.trim().split(".")[0], 10)
|
|
55
|
-
const installArgs = ["install", "-g", tarball, "--prefix", prefix]
|
|
56
|
-
if (Number.isFinite(npmMajor) && npmMajor >= 11) {
|
|
57
|
-
installArgs.push(`--allow-scripts=${packageName}`)
|
|
58
|
-
}
|
|
53
|
+
const installArgs = ["install", "-g", tarball, "--prefix", prefix, "--ignore-scripts"]
|
|
59
54
|
|
|
60
55
|
const install = runNpm(installArgs, {
|
|
61
56
|
cwd: temp,
|
|
62
|
-
env:
|
|
57
|
+
env: process.env,
|
|
63
58
|
})
|
|
64
|
-
requireSuccess(install, "packed global install
|
|
59
|
+
requireSuccess(install, "packed global install")
|
|
65
60
|
|
|
66
61
|
const root = runNpm(["root", "-g", "--prefix", prefix], { cwd: temp })
|
|
67
62
|
requireSuccess(root, "npm root -g")
|
|
@@ -81,7 +76,19 @@ try {
|
|
|
81
76
|
assert.equal(packageJson.name, packageName)
|
|
82
77
|
|
|
83
78
|
const cli = path.join(packageDir, "bin", "ocskill.mjs")
|
|
84
|
-
const env = {
|
|
79
|
+
const env = {
|
|
80
|
+
...process.env,
|
|
81
|
+
OPENCODE_CONFIG_DIR: configDir,
|
|
82
|
+
UES_CONFIG_DIR: uesConfigDir,
|
|
83
|
+
UES_OPENCODE_MAJOR: "2",
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const sync = spawnSync(process.execPath, [cli, "install"], {
|
|
87
|
+
cwd: temp,
|
|
88
|
+
env,
|
|
89
|
+
encoding: "utf8",
|
|
90
|
+
})
|
|
91
|
+
requireSuccess(sync, "explicit legacy OpenCode sync from packed copy")
|
|
85
92
|
|
|
86
93
|
const status = spawnSync(process.execPath, [cli, "status"], {
|
|
87
94
|
cwd: temp,
|
|
@@ -470,7 +477,13 @@ try {
|
|
|
470
477
|
encoding: "utf8",
|
|
471
478
|
})
|
|
472
479
|
requireSuccess(modelStatus, "ocskill models status from packed copy")
|
|
473
|
-
|
|
480
|
+
const initialModelStatus = JSON.parse(modelStatus.stdout)
|
|
481
|
+
assert.equal(initialModelStatus.enabled, false)
|
|
482
|
+
assert.equal(
|
|
483
|
+
path.resolve(initialModelStatus.file),
|
|
484
|
+
path.resolve(uesConfigDir, ".ues", "model-policy.json"),
|
|
485
|
+
"packed smoke must not read the user's real UES model policy",
|
|
486
|
+
)
|
|
474
487
|
|
|
475
488
|
const modelSet = spawnSync(process.execPath, [cli, "models", "set", "standard", "provider/mid"], {
|
|
476
489
|
cwd: temp,
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import { existsSync } from "node:fs"
|
|
3
|
+
import { mkdtemp, rm } from "node:fs/promises"
|
|
4
|
+
import os from "node:os"
|
|
5
|
+
import path from "node:path"
|
|
6
|
+
import { spawnSync } from "node:child_process"
|
|
7
|
+
import { pathToFileURL, fileURLToPath } from "node:url"
|
|
8
|
+
import { resolveWindowsCommand } from "../lib/windows-shim.mjs"
|
|
9
|
+
|
|
10
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
11
|
+
const extensionPath = path.join(root, "pi", "extensions", "ues.ts")
|
|
12
|
+
const childRuntimeExtensionPath = path.join(root, "pi", "extensions", "ues-child-runtime.ts")
|
|
13
|
+
const skillsPath = path.join(root, "global-config", "skills")
|
|
14
|
+
const promptsPath = path.join(root, "pi", "prompts")
|
|
15
|
+
const agentDir = path.join(root, ".tmp-pi-agent")
|
|
16
|
+
const PI_SMOKE_VERSION = process.env.UES_PI_SMOKE_VERSION || "0.87.1"
|
|
17
|
+
const TYPEBOX_SMOKE_VERSION = process.env.UES_TYPEBOX_SMOKE_VERSION || "1.3.27"
|
|
18
|
+
|
|
19
|
+
function sanitizedNpmChildEnv(base = process.env) {
|
|
20
|
+
return Object.fromEntries(
|
|
21
|
+
Object.entries(base).filter(([key]) => key.toLowerCase() !== "npm_config_allow_scripts"),
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function run(executable, args, options = {}) {
|
|
26
|
+
const spawnOptions = executable === "npm"
|
|
27
|
+
? { ...options, env: sanitizedNpmChildEnv(options.env || process.env) }
|
|
28
|
+
: options
|
|
29
|
+
|
|
30
|
+
if (process.platform !== "win32") return spawnSync(executable, args, spawnOptions)
|
|
31
|
+
const resolved = resolveWindowsCommand(executable)
|
|
32
|
+
if (!resolved) return { status: 127, stdout: "", stderr: "Unable to resolve command: " + executable }
|
|
33
|
+
return spawnSync(resolved.executable, [...resolved.argsPrefix, ...args], spawnOptions)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function importSdkFromDir(nodeModulesRoot) {
|
|
37
|
+
const entry = path.join(
|
|
38
|
+
nodeModulesRoot,
|
|
39
|
+
"@earendil-works",
|
|
40
|
+
"pi-coding-agent",
|
|
41
|
+
"dist",
|
|
42
|
+
"index.js",
|
|
43
|
+
)
|
|
44
|
+
if (!existsSync(entry)) return null
|
|
45
|
+
return import(pathToFileURL(entry).href)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function loadPiSdk() {
|
|
49
|
+
try {
|
|
50
|
+
return {
|
|
51
|
+
sdk: await import("@earendil-works/pi-coding-agent"),
|
|
52
|
+
source: "local-node-modules",
|
|
53
|
+
tempDir: null,
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error?.code !== "ERR_MODULE_NOT_FOUND") throw error
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const globalRoot = run("npm", ["root", "-g"], { encoding: "utf8" })
|
|
60
|
+
if (globalRoot.status === 0) {
|
|
61
|
+
const sdk = await importSdkFromDir(String(globalRoot.stdout || "").trim())
|
|
62
|
+
if (sdk) return { sdk, source: "global-npm", tempDir: null }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const tempDir = await mkdtemp(path.join(os.tmpdir(), "ues-pi-smoke-host-"))
|
|
66
|
+
const installed = run(
|
|
67
|
+
"npm",
|
|
68
|
+
[
|
|
69
|
+
"install",
|
|
70
|
+
"--ignore-scripts",
|
|
71
|
+
"--no-package-lock",
|
|
72
|
+
"--no-save",
|
|
73
|
+
`@earendil-works/pi-coding-agent@${PI_SMOKE_VERSION}`,
|
|
74
|
+
`typebox@${TYPEBOX_SMOKE_VERSION}`,
|
|
75
|
+
],
|
|
76
|
+
{
|
|
77
|
+
cwd: tempDir,
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if (installed.status !== 0) {
|
|
84
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {})
|
|
85
|
+
throw new Error(
|
|
86
|
+
"Unable to provision Pi SDK for smoke test:\n" +
|
|
87
|
+
String(installed.stderr || installed.stdout || "npm install failed"),
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const sdk = await importSdkFromDir(path.join(tempDir, "node_modules"))
|
|
92
|
+
if (!sdk) {
|
|
93
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {})
|
|
94
|
+
throw new Error("Provisioned Pi SDK is missing dist/index.js")
|
|
95
|
+
}
|
|
96
|
+
return { sdk, source: "isolated-temp-install", tempDir }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const loaded = await loadPiSdk()
|
|
100
|
+
const { DefaultResourceLoader } = loaded.sdk
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const loader = new DefaultResourceLoader({
|
|
104
|
+
cwd: root,
|
|
105
|
+
agentDir,
|
|
106
|
+
additionalExtensionPaths: [extensionPath, childRuntimeExtensionPath],
|
|
107
|
+
additionalSkillPaths: [skillsPath],
|
|
108
|
+
additionalPromptTemplatePaths: [promptsPath],
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
await loader.reload()
|
|
112
|
+
const result = loader.getExtensions()
|
|
113
|
+
|
|
114
|
+
assert.equal(
|
|
115
|
+
result.errors.length,
|
|
116
|
+
0,
|
|
117
|
+
result.errors.map((entry) => `${entry.path}: ${entry.error}`).join("\n"),
|
|
118
|
+
)
|
|
119
|
+
assert.ok(result.extensions.length >= 2, "Pi did not load the UES controller + child runtime extensions")
|
|
120
|
+
|
|
121
|
+
const skillResult = loader.getSkills()
|
|
122
|
+
assert.equal(
|
|
123
|
+
skillResult.diagnostics.length,
|
|
124
|
+
0,
|
|
125
|
+
skillResult.diagnostics.map((entry) => `${entry.path || entry.filePath || "skill"}: ${entry.message || entry.error || JSON.stringify(entry)}`).join("\n"),
|
|
126
|
+
)
|
|
127
|
+
assert.ok(skillResult.skills.length >= 40, "Pi did not load the bundled UES skills")
|
|
128
|
+
|
|
129
|
+
const promptResult = loader.getPrompts()
|
|
130
|
+
assert.equal(
|
|
131
|
+
promptResult.diagnostics.length,
|
|
132
|
+
0,
|
|
133
|
+
promptResult.diagnostics.map((entry) => `${entry.path || entry.filePath || "prompt"}: ${entry.message || entry.error || JSON.stringify(entry)}`).join("\n"),
|
|
134
|
+
)
|
|
135
|
+
assert.ok(promptResult.prompts.length >= 11, "Pi did not load the bundled UES prompts")
|
|
136
|
+
|
|
137
|
+
console.log(
|
|
138
|
+
`Pi package smoke passed via ${loaded.source}: ${result.extensions.length} extension(s), ${skillResult.skills.length} skill(s), ${promptResult.prompts.length} prompt(s) loaded`,
|
|
139
|
+
)
|
|
140
|
+
} finally {
|
|
141
|
+
if (loaded.tempDir) {
|
|
142
|
+
await rm(loaded.tempDir, { recursive: true, force: true }).catch(() => {})
|
|
143
|
+
}
|
|
144
|
+
}
|
package/scripts/uninstall.mjs
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
1
4
|
import { removeResources } from "../lib/installer.mjs"
|
|
2
5
|
|
|
6
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
7
|
+
const normalizedRoot = packageRoot.replaceAll("\\", "/").toLowerCase()
|
|
8
|
+
|
|
9
|
+
function isPiPackageInstall() {
|
|
10
|
+
return [
|
|
11
|
+
"/.pi/agent/git/",
|
|
12
|
+
"/.pi/agent/npm/",
|
|
13
|
+
"/.pi/git/",
|
|
14
|
+
"/.pi/npm/",
|
|
15
|
+
].some((marker) => normalizedRoot.includes(marker))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function npmGlobalPrefix() {
|
|
19
|
+
if (process.platform === "win32") {
|
|
20
|
+
const result = spawnSync(
|
|
21
|
+
process.env.ComSpec || "cmd.exe",
|
|
22
|
+
["/d", "/s", "/c", "npm prefix -g"],
|
|
23
|
+
{ encoding: "utf8" },
|
|
24
|
+
)
|
|
25
|
+
return result.status === 0 ? result.stdout?.trim() : null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const result = spawnSync("npm", ["prefix", "-g"], { encoding: "utf8" })
|
|
29
|
+
return result.status === 0 ? result.stdout?.trim() : null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isGlobalInstall() {
|
|
33
|
+
if (process.env.npm_config_global === "true" || process.env.npm_config_global === "1") {
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const prefix = npmGlobalPrefix()
|
|
38
|
+
if (!prefix) return false
|
|
39
|
+
return packageRoot.toLowerCase().startsWith(path.resolve(prefix).toLowerCase())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (isPiPackageInstall() || !isGlobalInstall()) {
|
|
43
|
+
console.log("[ocskill] Non-global/Pi package uninstall detected; leaving OpenCode resources untouched.")
|
|
44
|
+
process.exit(0)
|
|
45
|
+
}
|
|
46
|
+
|
|
3
47
|
try {
|
|
4
48
|
const result = await removeResources()
|
|
5
49
|
for (const warning of result.warnings || []) {
|