Hmbown/CodeWhale · error · Error
Restore points require the runtime bearer token.
Error message
Restore points require the runtime bearer token.
What it means
stage_local_copy validates the source directory before copying anything into staging: resolve_manifest_path must find plugin.json, kimi.plugin.json, or plugin.toml directly at the source root. This also rejects symlinked roots/manifests. The error means the directory you passed simply has no supported manifest at its top level, so it is not recognizable as a plugin bundle.
Source
Thrown at extensions/vscode/src/runtime.ts:133
if (response.statusCode === 401) {
throw new Error("Thread summaries require the runtime bearer token.");
}
if (response.statusCode !== 200) {
throw new Error(`Thread summary returned HTTP ${response.statusCode}.`);
}
return readThreadSummaries(response.body);
}
export async function listSnapshots(config: RuntimeConfig, limit = 8): Promise<SnapshotEntry[]> {
const baseUrl = runtimeBaseUrl(config);
const response = await requestJson(
`${baseUrl}/v1/snapshots?limit=${encodeURIComponent(String(limit))}`,
config.token,
);
if (response.statusCode === 401) {
throw new Error("Restore points require the runtime bearer token.");
}
if (response.statusCode !== 200) {
throw new Error(`Restore points returned HTTP ${response.statusCode}.`);
}
return readSnapshots(response.body);
}
export function startRuntimeTerminal(config: RuntimeConfig): vscode.Terminal {
const terminal = vscode.window.createTerminal("CodeWhale Runtime");
const args = [
"serve",
"--http",
"--host",
shellQuote(config.host),
"--port",
String(config.port),
];View on GitHub (pinned to 8880682c63)
Solutions
- cd into the extracted/cloned tree and locate the directory that directly contains plugin.json (or kimi.plugin.json/plugin.toml); install that directory.
- If the archive added a wrapper folder, pass <extract-dir>/<wrapper>/ as the source.
- If you maintain the bundle, name the manifest one of the three supported files and place it at the bundle root.
Example fix
# before plugin install ./my-plugin-main # wrapper folder, no manifest at root # after plugin install ./my-plugin-main/my-plugin # directory holding plugin.json
Defensive patterns
Strategy: validation
Validate before calling
if crate::plugins::agent_plugin::resolve_manifest_path(source).is_none() {
anyhow::bail!("{} has no plugin.json/kimi.plugin.json/plugin.toml at its root — pass the bundle directory itself", source.display());
}
stage_local_copy(source, user_plugins_dir, max_size)?; Type guard
fn is_plugin_bundle(dir: &Path) -> bool {
crate::plugins::agent_plugin::resolve_manifest_path(dir).is_some()
} Try / catch
match stage_local_copy(source, plugins_dir, max_size) {
Ok(staged) => staged,
Err(e) if e.to_string().contains("no plugin.json, kimi.plugin.json, or plugin.toml") => {
// search one level down for the actual bundle root and retry
let child = std::fs::read_dir(source)?.find_map(|d| {
let d = d.ok()?.path();
is_plugin_bundle(&d).then_some(d)
}).context("no nested bundle found")?;
stage_local_copy(&child, plugins_dir, max_size)?
}
Err(e) => return Err(e),
} Prevention
- Always pass the directory that directly contains the manifest, not a checkout or archive root.
- After cloning/unzipping, ls for plugin.json before installing.
- Name the manifest one of the three supported filenames at the bundle root.
When it happens
Trigger: Pointing the local-install API at a repository checkout root where the plugin lives in a subdirectory; pointing at the parent of the bundle; pointing at a file instead of a directory; a bundle shipping only an unsupported manifest filename.
Common situations: git clone of a plugin monorepo and installing the repo root instead of plugins/<name>; unzipping an archive that adds a wrapper folder (my-plugin-main/...) and passing the extraction dir; bundles that renamed their manifest (e.g. manifest.json) which is not in the supported set.
Related errors
- Thread summaries require the runtime bearer token.
- Restore points returned HTTP ${response.statusCode}.
- parallel(): max ${MAX_ITEMS} items per call
- pipeline(): expected an array of items
- pipeline(): max ${MAX_ITEMS} items per call
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/68854f567422a110.
Report an issue: GitHub.