Repository navigation
Expand file tree
/
Copy pathsync-builtin-extensions.mjs
More file actions
80 lines (72 loc) · 3.59 KB
/
Copy pathsync-builtin-extensions.mjs
File metadata and controls
80 lines (72 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const scriptDir = dirname(fileURLToPath(import.meta.url));
const packageDir = resolve(scriptDir, "..");
const workspaceRoot = resolve(packageDir, "..", "..");
const defaultSourceRoot = resolve(workspaceRoot, "..", "pi-extensions");
const sourceRoot = resolve(process.env.SENPI_BUILTIN_EXTENSIONS_SOURCE ?? defaultSourceRoot);
const builtinRoot = join(packageDir, "src", "core", "extensions", "builtin");
const FILES = [
{
source: "pi-bash-timeout/src/index.ts",
target: "bash-timeout/index.ts",
transform: (content) =>
content.replace(
'import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";',
'import type { ExtensionAPI } from "../../types.js";',
),
},
{ source: "pi-bash-timeout/src/timeout.ts", target: "bash-timeout/timeout.ts" },
// pi-apply-patch has diverged: senpi maintains a refactored multi-file version under
// gpt-apply-patch/ (apply.ts, constants.ts, errors.ts, extension.ts, parser.ts, tool.ts, ...)
// while pi-apply-patch upstream is still a single src/index.ts monolith. Re-enabling the old
// monolithic sync would overwrite senpi's barrel index.ts and lose the refactor. Port
// behavior changes manually until the upstream package is restructured to match.
//
// pi-todotools has also diverged: senpi customizes SENPI_SYSTEM_PREFIX to "[system:senpi]"
// (pi-todotools uses "[system:senpi]") and `reportContinuationError` is wired into the
// unified `senpi:conversation` event surface. Regular file-copy sync overwrites those
// customizations and breaks `test/suite/senpi-conversation.test.ts`,
// `test/suite/todotools-continuation-runtime-unit.test.ts`, and
// `test/suite/todotools-continuation-chain-cap.test.ts`. Port improvements manually.
];
// PACKAGES records upstream package versions in external-versions.json even when the FILES sync
// is intentionally skipped for a package, so downstream consumers (and the
// builtin-extension-sync test) still see the source-of-truth metadata for every vendored
// builtin without us auto-overwriting the diverged files above.
const PACKAGES = [
{ id: "bash-timeout", packageDir: "pi-bash-timeout" },
{ id: "gpt-apply-patch", packageDir: "pi-apply-patch" },
{ id: "todowrite", packageDir: "pi-todotools" },
];
function readPackageMetadata(packageName) {
const packageJsonPath = join(sourceRoot, packageName, "package.json");
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
return {
packageName: packageJson.name,
version: packageJson.version,
source: `../pi-extensions/${packageName}`,
};
}
if (!existsSync(sourceRoot)) {
console.log(`[sync-builtin-extensions] source not found, keeping vendored snapshot: ${sourceRoot}`);
process.exit(0);
}
for (const entry of FILES) {
const sourcePath = join(sourceRoot, entry.source);
const targetPath = join(builtinRoot, entry.target);
if (!existsSync(sourcePath)) {
throw new Error(`missing source file: ${sourcePath}`);
}
mkdirSync(dirname(targetPath), { recursive: true });
const content = readFileSync(sourcePath, "utf-8");
writeFileSync(targetPath, entry.transform ? entry.transform(content) : content, "utf-8");
}
const manifest = { extensions: {} };
for (const packageEntry of PACKAGES) {
manifest.extensions[packageEntry.id] = readPackageMetadata(packageEntry.packageDir);
}
writeFileSync(join(builtinRoot, "external-versions.json"), `${JSON.stringify(manifest, null, "\t")}\n`, "utf-8");
console.log(`[sync-builtin-extensions] synced from ${sourceRoot}`);