fix: resolve 25 pre-publish blockers
- postinstall.mjs: fix alias package detection - migrate-legacy-plugin-entry: dedupe + regression tests - task_system: default consistency across runtime paths - task() contract: consistent tool behavior - runtime model selection, tool cap, stale-task cancellation - recovery sanitization, context-limit gating - Ralph semantic DONE hardening, Atlas fallback persistence - native-skill description/content, skill path traversal guard - publish workflow: platform awaited via reusable workflow job - release: version edits reapplied before commit/tag - JSONC plugin migration: top-level plugin key safety - cold-cache: user fallback models skip disconnected providers - docs/version/release framing updates Verified: bun test (4599 pass), tsc --noEmit clean, bun run build clean
This commit is contained in:
@@ -1,8 +1,54 @@
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs"
|
||||
import { applyEdits, modify } from "jsonc-parser"
|
||||
|
||||
import { parseJsoncSafe } from "./jsonc-parser"
|
||||
import { log } from "./logger"
|
||||
import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "./plugin-identity"
|
||||
|
||||
interface OpenCodeConfig {
|
||||
plugin?: string[]
|
||||
}
|
||||
|
||||
function isLegacyEntry(entry: string): boolean {
|
||||
return entry === LEGACY_PLUGIN_NAME || entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)
|
||||
}
|
||||
|
||||
function isCanonicalEntry(entry: string): boolean {
|
||||
return entry === PLUGIN_NAME || entry.startsWith(`${PLUGIN_NAME}@`)
|
||||
}
|
||||
|
||||
function toCanonicalEntry(entry: string): string {
|
||||
if (entry === LEGACY_PLUGIN_NAME) return PLUGIN_NAME
|
||||
if (entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)) {
|
||||
return `${PLUGIN_NAME}${entry.slice(LEGACY_PLUGIN_NAME.length)}`
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
function normalizePluginEntries(entries: string[]): string[] {
|
||||
const hasCanonical = entries.some(isCanonicalEntry)
|
||||
|
||||
if (hasCanonical) {
|
||||
return entries.filter((entry) => !isLegacyEntry(entry))
|
||||
}
|
||||
|
||||
return entries.map((entry) => (isLegacyEntry(entry) ? toCanonicalEntry(entry) : entry))
|
||||
}
|
||||
|
||||
function updateJsoncPluginArray(content: string, pluginEntries: string[]): string | null {
|
||||
const edits = modify(content, ["plugin"], pluginEntries, {
|
||||
formattingOptions: {
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
eol: "\n",
|
||||
},
|
||||
getInsertionIndex: () => 0,
|
||||
})
|
||||
|
||||
if (edits.length === 0) return null
|
||||
return applyEdits(content, edits)
|
||||
}
|
||||
|
||||
export function migrateLegacyPluginEntry(configPath: string): boolean {
|
||||
if (!existsSync(configPath)) return false
|
||||
|
||||
@@ -10,8 +56,15 @@ export function migrateLegacyPluginEntry(configPath: string): boolean {
|
||||
const content = readFileSync(configPath, "utf-8")
|
||||
if (!content.includes(LEGACY_PLUGIN_NAME)) return false
|
||||
|
||||
const updated = content.replaceAll(LEGACY_PLUGIN_NAME, PLUGIN_NAME)
|
||||
if (updated === content) return false
|
||||
const parseResult = parseJsoncSafe<OpenCodeConfig>(content)
|
||||
const pluginEntries = parseResult.data?.plugin
|
||||
if (!pluginEntries || !pluginEntries.some(isLegacyEntry)) return false
|
||||
|
||||
const updatedPluginEntries = normalizePluginEntries(pluginEntries)
|
||||
const updated = configPath.endsWith(".jsonc")
|
||||
? updateJsoncPluginArray(content, updatedPluginEntries)
|
||||
: JSON.stringify({ ...(parseResult.data as OpenCodeConfig), plugin: updatedPluginEntries }, null, 2) + "\n"
|
||||
if (!updated || updated === content) return false
|
||||
|
||||
writeFileSync(configPath, updated, "utf-8")
|
||||
log("[migrateLegacyPluginEntry] Auto-migrated opencode.json plugin entry", {
|
||||
|
||||
Reference in New Issue
Block a user