fix startup packaging and content guardrails
This commit is contained in:
@@ -275,7 +275,8 @@ function writeLauncher(bundleRoot, target) {
|
||||
"@echo off",
|
||||
"setlocal",
|
||||
'set "ROOT=%~dp0"',
|
||||
'"%ROOT%node\\node.exe" "%ROOT%app\\bin\\feynman.js" %*',
|
||||
'if "%ROOT:~-1%"=="\\" set "ROOT=%ROOT:~0,-1%"',
|
||||
'"%ROOT%\\node\\node.exe" "%ROOT%\\app\\bin\\feynman.js" %*',
|
||||
"",
|
||||
].join("\r\n"),
|
||||
"utf8",
|
||||
|
||||
@@ -92,8 +92,9 @@ try {
|
||||
}
|
||||
|
||||
$skillsSource = Join-Path $sourceRoot.FullName "skills"
|
||||
if (-not (Test-Path $skillsSource)) {
|
||||
throw "Could not find skills/ in downloaded archive."
|
||||
$promptsSource = Join-Path $sourceRoot.FullName "prompts"
|
||||
if (-not (Test-Path $skillsSource) -or -not (Test-Path $promptsSource)) {
|
||||
throw "Could not find the bundled skills resources in the downloaded archive."
|
||||
}
|
||||
|
||||
$installParent = Split-Path $installDir -Parent
|
||||
@@ -107,6 +108,10 @@ try {
|
||||
|
||||
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $skillsSource "*") -Destination $installDir -Recurse -Force
|
||||
New-Item -ItemType Directory -Path (Join-Path $installDir "prompts") -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $promptsSource "*") -Destination (Join-Path $installDir "prompts") -Recurse -Force
|
||||
Copy-Item -Path (Join-Path $sourceRoot.FullName "AGENTS.md") -Destination (Join-Path $installDir "AGENTS.md") -Force
|
||||
Copy-Item -Path (Join-Path $sourceRoot.FullName "CONTRIBUTING.md") -Destination (Join-Path $installDir "CONTRIBUTING.md") -Force
|
||||
|
||||
Write-Host "==> Installed skills to $installDir"
|
||||
if ($Scope -eq "Repo") {
|
||||
|
||||
@@ -181,8 +181,8 @@ step "Extracting skills"
|
||||
tar -xzf "$archive_path" -C "$extract_dir"
|
||||
|
||||
source_root="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
|
||||
if [ -z "$source_root" ] || [ ! -d "$source_root/skills" ]; then
|
||||
echo "Could not find skills/ in downloaded archive." >&2
|
||||
if [ -z "$source_root" ] || [ ! -d "$source_root/skills" ] || [ ! -d "$source_root/prompts" ]; then
|
||||
echo "Could not find the bundled skills resources in the downloaded archive." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -190,6 +190,10 @@ mkdir -p "$(dirname "$install_dir")"
|
||||
rm -rf "$install_dir"
|
||||
mkdir -p "$install_dir"
|
||||
cp -R "$source_root/skills/." "$install_dir/"
|
||||
mkdir -p "$install_dir/prompts"
|
||||
cp -R "$source_root/prompts/." "$install_dir/prompts/"
|
||||
cp "$source_root/AGENTS.md" "$install_dir/AGENTS.md"
|
||||
cp "$source_root/CONTRIBUTING.md" "$install_dir/CONTRIBUTING.md"
|
||||
|
||||
step "Installed skills to $install_dir"
|
||||
case "$SCOPE" in
|
||||
|
||||
@@ -125,12 +125,18 @@ Workarounds:
|
||||
New-Item -ItemType Directory -Path $installBinDir -Force | Out-Null
|
||||
|
||||
$shimPath = Join-Path $installBinDir "feynman.cmd"
|
||||
$shimPs1Path = Join-Path $installBinDir "feynman.ps1"
|
||||
Write-Host "==> Linking feynman into $installBinDir"
|
||||
@"
|
||||
@echo off
|
||||
"$bundleDir\feynman.cmd" %*
|
||||
CALL "$bundleDir\feynman.cmd" %*
|
||||
"@ | Set-Content -Path $shimPath -Encoding ASCII
|
||||
|
||||
@"
|
||||
`$BundleDir = "$bundleDir"
|
||||
& "`$BundleDir\node\node.exe" "`$BundleDir\app\bin\feynman.js" @args
|
||||
"@ | Set-Content -Path $shimPs1Path -Encoding UTF8
|
||||
|
||||
$currentUserPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
$alreadyOnPath = $false
|
||||
if ($currentUserPath) {
|
||||
|
||||
2
scripts/lib/pi-web-access-patch.d.mts
Normal file
2
scripts/lib/pi-web-access-patch.d.mts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const PI_WEB_ACCESS_PATCH_TARGETS: string[];
|
||||
export function patchPiWebAccessSource(relativePath: string, source: string): string;
|
||||
32
scripts/lib/pi-web-access-patch.mjs
Normal file
32
scripts/lib/pi-web-access-patch.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
export const PI_WEB_ACCESS_PATCH_TARGETS = [
|
||||
"index.ts",
|
||||
"exa.ts",
|
||||
"gemini-api.ts",
|
||||
"gemini-search.ts",
|
||||
"gemini-web.ts",
|
||||
"github-extract.ts",
|
||||
"perplexity.ts",
|
||||
"video-extract.ts",
|
||||
"youtube-extract.ts",
|
||||
];
|
||||
|
||||
const LEGACY_CONFIG_EXPR = 'join(homedir(), ".pi", "web-search.json")';
|
||||
const PATCHED_CONFIG_EXPR =
|
||||
'process.env.FEYNMAN_WEB_SEARCH_CONFIG ?? process.env.PI_WEB_SEARCH_CONFIG ?? join(homedir(), ".pi", "web-search.json")';
|
||||
|
||||
export function patchPiWebAccessSource(relativePath, source) {
|
||||
let patched = source;
|
||||
|
||||
if (patched.includes(PATCHED_CONFIG_EXPR)) {
|
||||
return patched;
|
||||
}
|
||||
|
||||
patched = patched.split(LEGACY_CONFIG_EXPR).join(PATCHED_CONFIG_EXPR);
|
||||
|
||||
if (relativePath === "index.ts" && patched !== source) {
|
||||
patched = patched.replace('import { join } from "node:path";', 'import { dirname, join } from "node:path";');
|
||||
patched = patched.replace('const dir = join(homedir(), ".pi");', "const dir = dirname(WEB_SEARCH_CONFIG_PATH);");
|
||||
}
|
||||
|
||||
return patched;
|
||||
}
|
||||
@@ -1,14 +1,21 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { homedir } from "node:os";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { FEYNMAN_LOGO_HTML } from "../logo.mjs";
|
||||
import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs";
|
||||
import { PI_WEB_ACCESS_PATCH_TARGETS, patchPiWebAccessSource } from "./lib/pi-web-access-patch.mjs";
|
||||
import { PI_SUBAGENTS_PATCH_TARGETS, patchPiSubagentsSource } from "./lib/pi-subagents-patch.mjs";
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const appRoot = resolve(here, "..");
|
||||
const feynmanHome = resolve(process.env.FEYNMAN_HOME ?? homedir(), ".feynman");
|
||||
const feynmanNpmPrefix = resolve(feynmanHome, "npm-global");
|
||||
process.env.FEYNMAN_NPM_PREFIX = feynmanNpmPrefix;
|
||||
process.env.NPM_CONFIG_PREFIX = feynmanNpmPrefix;
|
||||
process.env.npm_config_prefix = feynmanNpmPrefix;
|
||||
const appRequire = createRequire(resolve(appRoot, "package.json"));
|
||||
const isGlobalInstall = process.env.npm_config_global === "true" || process.env.npm_config_location === "global";
|
||||
|
||||
@@ -57,6 +64,15 @@ const extensionLoaderPath = piPackageRoot ? resolve(piPackageRoot, "dist", "core
|
||||
const terminalPath = piTuiRoot ? resolve(piTuiRoot, "dist", "terminal.js") : null;
|
||||
const editorPath = piTuiRoot ? resolve(piTuiRoot, "dist", "components", "editor.js") : null;
|
||||
const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules");
|
||||
const workspaceExtensionLoaderPath = resolve(
|
||||
workspaceRoot,
|
||||
"@mariozechner",
|
||||
"pi-coding-agent",
|
||||
"dist",
|
||||
"core",
|
||||
"extensions",
|
||||
"loader.js",
|
||||
);
|
||||
const vendorOverrideRoot = resolve(appRoot, ".feynman", "vendor-overrides");
|
||||
const piSubagentsRoot = resolve(workspaceRoot, "pi-subagents");
|
||||
const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts");
|
||||
@@ -76,7 +92,17 @@ const workspaceArchivePath = resolve(appRoot, ".feynman", "runtime-workspace.tgz
|
||||
function createInstallCommand(packageManager, packageSpecs) {
|
||||
switch (packageManager) {
|
||||
case "npm":
|
||||
return ["install", "--prefer-offline", "--no-audit", "--no-fund", "--loglevel", "error", ...packageSpecs];
|
||||
return [
|
||||
"install",
|
||||
"--global=false",
|
||||
"--location=project",
|
||||
"--prefer-offline",
|
||||
"--no-audit",
|
||||
"--no-fund",
|
||||
"--loglevel",
|
||||
"error",
|
||||
...packageSpecs,
|
||||
];
|
||||
case "pnpm":
|
||||
return ["add", "--prefer-offline", "--reporter", "silent", ...packageSpecs];
|
||||
case "bun":
|
||||
@@ -367,11 +393,15 @@ if (interactiveModePath && existsSync(interactiveModePath)) {
|
||||
}
|
||||
}
|
||||
|
||||
if (extensionLoaderPath && existsSync(extensionLoaderPath)) {
|
||||
const source = readFileSync(extensionLoaderPath, "utf8");
|
||||
for (const loaderPath of [extensionLoaderPath, workspaceExtensionLoaderPath].filter(Boolean)) {
|
||||
if (!existsSync(loaderPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const source = readFileSync(loaderPath, "utf8");
|
||||
const patched = patchPiExtensionLoaderSource(source);
|
||||
if (patched !== source) {
|
||||
writeFileSync(extensionLoaderPath, patched, "utf8");
|
||||
writeFileSync(loaderPath, patched, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,6 +590,21 @@ if (existsSync(webAccessPath)) {
|
||||
}
|
||||
}
|
||||
|
||||
const piWebAccessRoot = resolve(workspaceRoot, "pi-web-access");
|
||||
|
||||
if (existsSync(piWebAccessRoot)) {
|
||||
for (const relativePath of PI_WEB_ACCESS_PATCH_TARGETS) {
|
||||
const entryPath = resolve(piWebAccessRoot, relativePath);
|
||||
if (!existsSync(entryPath)) continue;
|
||||
|
||||
const source = readFileSync(entryPath, "utf8");
|
||||
const patched = patchPiWebAccessSource(relativePath, source);
|
||||
if (patched !== source) {
|
||||
writeFileSync(entryPath, patched, "utf8");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (existsSync(sessionSearchIndexerPath)) {
|
||||
const source = readFileSync(sessionSearchIndexerPath, "utf8");
|
||||
const original = 'const sessionsDir = path.join(os.homedir(), ".pi", "agent", "sessions");';
|
||||
|
||||
Reference in New Issue
Block a user