f1f6516056
- Removed export leakage by demoting many helper and const symbols to module-local scope. - Renamed underscore-prefixed internals and cache fields, then updated related references and `satisfies never` checks. - Deleted obsolete logic branches and helpers, including harmony-stream interruption flow and unused benchmark runtime helpers. - Updated Biome config and manifests by broadening lint coverage and removing an unused `@napi-rs/cli` dev dependency. - Adjusted tests and utilities to use renamed test helpers and remove redundant private test-only helpers/locals.
81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
/**
|
|
* Protocol handler for artifact:// URLs.
|
|
*
|
|
* Resolves artifact IDs against the artifacts directories of every active
|
|
* session. Unlike agent://, artifacts are raw text with no JSON extraction.
|
|
*
|
|
* URL form:
|
|
* - artifact://<id> - Full artifact content
|
|
*
|
|
* Pagination is handled by the read tool via offset/limit parameters.
|
|
*/
|
|
import * as fs from "node:fs/promises";
|
|
import * as path from "node:path";
|
|
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
import { artifactsDirsFromRegistry } from "./registry-helpers";
|
|
import type { InternalResource, InternalUrl, ProtocolHandler } from "./types";
|
|
|
|
export class ArtifactProtocolHandler implements ProtocolHandler {
|
|
readonly scheme = "artifact";
|
|
readonly immutable = true;
|
|
|
|
async resolve(url: InternalUrl): Promise<InternalResource> {
|
|
const id = url.rawHost || url.hostname;
|
|
if (!id) {
|
|
throw new Error("artifact:// URL requires a numeric ID: artifact://0");
|
|
}
|
|
if (!/^\d+$/.test(id)) {
|
|
throw new Error(`artifact:// ID must be numeric, got: ${id}`);
|
|
}
|
|
|
|
const dirs = artifactsDirsFromRegistry();
|
|
|
|
if (dirs.length === 0) {
|
|
throw new Error("No session - artifacts unavailable");
|
|
}
|
|
|
|
let foundPath: string | undefined;
|
|
let anyDirExists = false;
|
|
const availableIds = new Set<string>();
|
|
|
|
for (const dir of dirs) {
|
|
let files: string[];
|
|
try {
|
|
files = await fs.readdir(dir);
|
|
anyDirExists = true;
|
|
} catch (err) {
|
|
if (isEnoent(err)) continue;
|
|
throw err;
|
|
}
|
|
const match = files.find(f => f.startsWith(`${id}.`));
|
|
if (match) {
|
|
foundPath = path.join(dir, match);
|
|
break;
|
|
}
|
|
for (const f of files) {
|
|
const m = f.match(/^(\d+)\./);
|
|
if (m) availableIds.add(m[1]);
|
|
}
|
|
}
|
|
|
|
if (!anyDirExists) {
|
|
throw new Error("No artifacts directory found");
|
|
}
|
|
|
|
if (!foundPath) {
|
|
const sorted = [...availableIds].sort((a, b) => Number(a) - Number(b));
|
|
const availableStr = sorted.length > 0 ? sorted.join(", ") : "none";
|
|
throw new Error(`Artifact ${id} not found. Available: ${availableStr}`);
|
|
}
|
|
|
|
const content = await Bun.file(foundPath).text();
|
|
return {
|
|
url: url.href,
|
|
content,
|
|
contentType: "text/plain",
|
|
size: Buffer.byteLength(content, "utf-8"),
|
|
sourcePath: foundPath,
|
|
};
|
|
}
|
|
}
|