- #3124: Session tools now merge SDK and file-backed sessions for SQLite backend - #3125: Cache priming fixed for OpenCode >=1.3.14 empty workspace - #3127: Activity-based progress detection prevents infinite compaction on Kimi/Minimax All 29 new tests pass, 4885 total tests passing.
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, test, expect, beforeEach, afterEach } from "bun:test"
|
||||
import * as fs from "node:fs"
|
||||
import * as path from "node:path"
|
||||
import * as os from "node:os"
|
||||
import { PACKAGE_NAME } from "../constants"
|
||||
import { updatePinnedVersion, revertPinnedVersion } from "./pinned-version-updater"
|
||||
|
||||
describe("pinned-version-updater", () => {
|
||||
@@ -21,18 +22,18 @@ describe("pinned-version-updater", () => {
|
||||
test("updates pinned version in config", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-openagent@3.1.8"],
|
||||
plugin: [`${PACKAGE_NAME}@3.1.8`],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
const result = updatePinnedVersion(configPath, `${PACKAGE_NAME}@3.1.8`, "3.4.0")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(true)
|
||||
const updated = fs.readFileSync(configPath, "utf-8")
|
||||
expect(updated).toContain("oh-my-openagent@3.4.0")
|
||||
expect(updated).not.toContain("oh-my-openagent@3.1.8")
|
||||
expect(updated).toContain(`${PACKAGE_NAME}@3.4.0`)
|
||||
expect(updated).not.toContain(`${PACKAGE_NAME}@3.1.8`)
|
||||
})
|
||||
|
||||
test("returns false when entry not found", () => {
|
||||
@@ -43,7 +44,7 @@ describe("pinned-version-updater", () => {
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
const result = updatePinnedVersion(configPath, `${PACKAGE_NAME}@3.1.8`, "3.4.0")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(false)
|
||||
@@ -55,7 +56,7 @@ describe("pinned-version-updater", () => {
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
const result = updatePinnedVersion(configPath, `${PACKAGE_NAME}@3.1.8`, "3.4.0")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(false)
|
||||
@@ -66,46 +67,46 @@ describe("pinned-version-updater", () => {
|
||||
test("reverts from failed version back to original entry", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-openagent@3.4.0"],
|
||||
plugin: [`${PACKAGE_NAME}@3.4.0`],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent@3.1.8")
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", `${PACKAGE_NAME}@3.1.8`)
|
||||
|
||||
//#then
|
||||
expect(result).toBe(true)
|
||||
const reverted = fs.readFileSync(configPath, "utf-8")
|
||||
expect(reverted).toContain("oh-my-openagent@3.1.8")
|
||||
expect(reverted).not.toContain("oh-my-openagent@3.4.0")
|
||||
expect(reverted).toContain(`${PACKAGE_NAME}@3.1.8`)
|
||||
expect(reverted).not.toContain(`${PACKAGE_NAME}@3.4.0`)
|
||||
})
|
||||
|
||||
test("reverts to unpinned entry", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-openagent@3.4.0"],
|
||||
plugin: [`${PACKAGE_NAME}@3.4.0`],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent")
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", PACKAGE_NAME)
|
||||
|
||||
//#then
|
||||
expect(result).toBe(true)
|
||||
const reverted = fs.readFileSync(configPath, "utf-8")
|
||||
expect(reverted).toContain('"oh-my-openagent"')
|
||||
expect(reverted).not.toContain("oh-my-openagent@3.4.0")
|
||||
expect(reverted).toContain(`"${PACKAGE_NAME}"`)
|
||||
expect(reverted).not.toContain(`${PACKAGE_NAME}@3.4.0`)
|
||||
})
|
||||
|
||||
test("returns false when failed version not found", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-openagent@3.1.8"],
|
||||
plugin: [`${PACKAGE_NAME}@3.1.8`],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent@3.1.8")
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", `${PACKAGE_NAME}@3.1.8`)
|
||||
|
||||
//#then
|
||||
expect(result).toBe(false)
|
||||
@@ -116,18 +117,18 @@ describe("pinned-version-updater", () => {
|
||||
test("config returns to original state after update + revert", () => {
|
||||
//#given
|
||||
const originalConfig = JSON.stringify({
|
||||
plugin: ["oh-my-openagent@3.1.8"],
|
||||
plugin: [`${PACKAGE_NAME}@3.1.8`],
|
||||
})
|
||||
fs.writeFileSync(configPath, originalConfig)
|
||||
|
||||
//#when
|
||||
updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent@3.1.8")
|
||||
updatePinnedVersion(configPath, `${PACKAGE_NAME}@3.1.8`, "3.4.0")
|
||||
revertPinnedVersion(configPath, "3.4.0", `${PACKAGE_NAME}@3.1.8`)
|
||||
|
||||
//#then
|
||||
const finalConfig = fs.readFileSync(configPath, "utf-8")
|
||||
expect(finalConfig).toContain("oh-my-openagent@3.1.8")
|
||||
expect(finalConfig).not.toContain("oh-my-openagent@3.4.0")
|
||||
expect(finalConfig).toContain(`${PACKAGE_NAME}@3.1.8`)
|
||||
expect(finalConfig).not.toContain(`${PACKAGE_NAME}@3.4.0`)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
||||
import * as fs from "node:fs"
|
||||
import * as os from "node:os"
|
||||
import * as path from "node:path"
|
||||
import { PACKAGE_NAME } from "../constants"
|
||||
import { findPluginEntry } from "./plugin-entry"
|
||||
|
||||
describe("findPluginEntry", () => {
|
||||
@@ -21,7 +22,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns unpinned for bare package name", () => {
|
||||
// #given plugin is configured without a tag
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: [PACKAGE_NAME] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
@@ -34,7 +35,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns unpinned for latest dist-tag", () => {
|
||||
// #given plugin is configured with latest dist-tag
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent@latest"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: [`${PACKAGE_NAME}@latest`] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
@@ -47,7 +48,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns unpinned for beta dist-tag", () => {
|
||||
// #given plugin is configured with beta dist-tag
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent@beta"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: [`${PACKAGE_NAME}@beta`] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
@@ -60,7 +61,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns pinned for explicit semver", () => {
|
||||
// #given plugin is configured with explicit version
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent@3.5.2"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: [`${PACKAGE_NAME}@3.5.2`] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
|
||||
@@ -11,7 +11,7 @@ interface CachePackageJson {
|
||||
|
||||
export interface SyncResult {
|
||||
synced: boolean
|
||||
error: "file_not_found" | "plugin_not_in_deps" | "parse_error" | "write_error" | null
|
||||
error: "parse_error" | "write_error" | null
|
||||
message?: string
|
||||
}
|
||||
|
||||
@@ -32,12 +32,33 @@ function getIntentVersion(pluginInfo: PluginEntryInfo): string {
|
||||
return pluginInfo.pinnedVersion
|
||||
}
|
||||
|
||||
function writeCachePackageJson(
|
||||
cachePackageJsonPath: string,
|
||||
pkgJson: CachePackageJson,
|
||||
): SyncResult {
|
||||
const tmpPath = `${cachePackageJsonPath}.${crypto.randomUUID()}`
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(cachePackageJsonPath), { recursive: true })
|
||||
fs.writeFileSync(tmpPath, JSON.stringify(pkgJson, null, 2))
|
||||
fs.renameSync(tmpPath, cachePackageJsonPath)
|
||||
return { synced: true, error: null }
|
||||
} catch (err) {
|
||||
log("[auto-update-checker] Failed to write cache package.json:", err)
|
||||
safeUnlink(tmpPath)
|
||||
return { synced: false, error: "write_error", message: "Failed to write cache package.json" }
|
||||
}
|
||||
}
|
||||
|
||||
export function syncCachePackageJsonToIntent(pluginInfo: PluginEntryInfo): SyncResult {
|
||||
const cachePackageJsonPath = path.join(CACHE_DIR, "package.json")
|
||||
const intentVersion = getIntentVersion(pluginInfo)
|
||||
|
||||
if (!fs.existsSync(cachePackageJsonPath)) {
|
||||
log("[auto-update-checker] Cache package.json not found, nothing to sync")
|
||||
return { synced: false, error: "file_not_found", message: "Cache package.json not found" }
|
||||
log("[auto-update-checker] Cache package.json missing, creating workspace package.json", { intentVersion })
|
||||
return {
|
||||
...writeCachePackageJson(cachePackageJsonPath, { dependencies: { [PACKAGE_NAME]: intentVersion } }),
|
||||
message: `Created cache package.json with: ${intentVersion}`,
|
||||
}
|
||||
}
|
||||
|
||||
let content: string
|
||||
@@ -58,12 +79,21 @@ export function syncCachePackageJsonToIntent(pluginInfo: PluginEntryInfo): SyncR
|
||||
}
|
||||
|
||||
if (!pkgJson || !pkgJson.dependencies?.[PACKAGE_NAME]) {
|
||||
log("[auto-update-checker] Plugin not in cache package.json dependencies, nothing to sync")
|
||||
return { synced: false, error: "plugin_not_in_deps", message: "Plugin not in cache package.json dependencies" }
|
||||
log("[auto-update-checker] Plugin missing from cache package.json dependencies, adding dependency", { intentVersion })
|
||||
const nextPkgJson = {
|
||||
...(pkgJson ?? {}),
|
||||
dependencies: {
|
||||
...(pkgJson?.dependencies ?? {}),
|
||||
[PACKAGE_NAME]: intentVersion,
|
||||
},
|
||||
}
|
||||
return {
|
||||
...writeCachePackageJson(cachePackageJsonPath, nextPkgJson),
|
||||
message: `Added ${PACKAGE_NAME}: ${intentVersion}`,
|
||||
}
|
||||
}
|
||||
|
||||
const currentVersion = pkgJson.dependencies[PACKAGE_NAME]
|
||||
const intentVersion = getIntentVersion(pluginInfo)
|
||||
|
||||
if (currentVersion === intentVersion) {
|
||||
log("[auto-update-checker] Cache package.json already matches intent:", intentVersion)
|
||||
@@ -84,15 +114,8 @@ export function syncCachePackageJsonToIntent(pluginInfo: PluginEntryInfo): SyncR
|
||||
}
|
||||
|
||||
pkgJson.dependencies[PACKAGE_NAME] = intentVersion
|
||||
|
||||
const tmpPath = `${cachePackageJsonPath}.${crypto.randomUUID()}`
|
||||
try {
|
||||
fs.writeFileSync(tmpPath, JSON.stringify(pkgJson, null, 2))
|
||||
fs.renameSync(tmpPath, cachePackageJsonPath)
|
||||
return { synced: true, error: null, message: `Updated: "${currentVersion}" → "${intentVersion}"` }
|
||||
} catch (err) {
|
||||
log("[auto-update-checker] Failed to write cache package.json:", err)
|
||||
safeUnlink(tmpPath)
|
||||
return { synced: false, error: "write_error", message: "Failed to write cache package.json" }
|
||||
return {
|
||||
...writeCachePackageJson(cachePackageJsonPath, pkgJson),
|
||||
message: `Updated: "${currentVersion}" → "${intentVersion}"`,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user