Fix postinstall patches for hoisted dependencies, add CI publish workflow
- Postinstall now walks up to find node_modules (works when deps are hoisted) - All patches verified: piConfig, process.title, OAuth page, editor theme - Add GitHub Actions workflow to publish on version bump Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
31
.github/workflows/publish.yml
vendored
Normal file
31
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: Publish to npm
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
registry-url: https://registry.npmjs.org
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build
|
||||||
|
- run: npm test
|
||||||
|
- name: Publish if version changed
|
||||||
|
run: |
|
||||||
|
CURRENT=$(npm view @companion-ai/feynman version 2>/dev/null || echo "0.0.0")
|
||||||
|
LOCAL=$(node -p "require('./package.json').version")
|
||||||
|
if [ "$CURRENT" != "$LOCAL" ]; then
|
||||||
|
npm publish --access public
|
||||||
|
else
|
||||||
|
echo "Version $LOCAL already published, skipping"
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@companion-ai/feynman",
|
"name": "@companion-ai/feynman",
|
||||||
"version": "0.2.3",
|
"version": "0.2.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@companion-ai/feynman",
|
"name": "@companion-ai/feynman",
|
||||||
"version": "0.2.3",
|
"version": "0.2.4",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@companion-ai/alpha-hub": "^0.1.2",
|
"@companion-ai/alpha-hub": "^0.1.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@companion-ai/feynman",
|
"name": "@companion-ai/feynman",
|
||||||
"version": "0.2.3",
|
"version": "0.2.4",
|
||||||
"description": "Research-first CLI agent built on Pi and alphaXiv",
|
"description": "Research-first CLI agent built on Pi and alphaXiv",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -5,14 +5,40 @@ import { fileURLToPath } from "node:url";
|
|||||||
|
|
||||||
const here = dirname(fileURLToPath(import.meta.url));
|
const here = dirname(fileURLToPath(import.meta.url));
|
||||||
const appRoot = resolve(here, "..");
|
const appRoot = resolve(here, "..");
|
||||||
const piPackageRoot = resolve(appRoot, "node_modules", "@mariozechner", "pi-coding-agent");
|
|
||||||
|
function findNodeModules() {
|
||||||
|
let dir = appRoot;
|
||||||
|
while (dir !== dirname(dir)) {
|
||||||
|
const nm = resolve(dir, "node_modules");
|
||||||
|
if (existsSync(nm)) return nm;
|
||||||
|
dir = dirname(dir);
|
||||||
|
}
|
||||||
|
return resolve(appRoot, "node_modules");
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeModules = findNodeModules();
|
||||||
|
|
||||||
|
function findPackageRoot(packageName) {
|
||||||
|
const candidate = resolve(nodeModules, packageName);
|
||||||
|
if (existsSync(resolve(candidate, "package.json"))) return candidate;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const piPackageRoot = findPackageRoot("@mariozechner/pi-coding-agent");
|
||||||
|
const piTuiRoot = findPackageRoot("@mariozechner/pi-tui");
|
||||||
|
const piAiRoot = findPackageRoot("@mariozechner/pi-ai");
|
||||||
|
|
||||||
|
if (!piPackageRoot) {
|
||||||
|
console.warn("[feynman] pi-coding-agent not found, skipping patches");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
const packageJsonPath = resolve(piPackageRoot, "package.json");
|
const packageJsonPath = resolve(piPackageRoot, "package.json");
|
||||||
const cliPath = resolve(piPackageRoot, "dist", "cli.js");
|
const cliPath = resolve(piPackageRoot, "dist", "cli.js");
|
||||||
const bunCliPath = resolve(piPackageRoot, "dist", "bun", "cli.js");
|
const bunCliPath = resolve(piPackageRoot, "dist", "bun", "cli.js");
|
||||||
const interactiveModePath = resolve(piPackageRoot, "dist", "modes", "interactive", "interactive-mode.js");
|
const interactiveModePath = resolve(piPackageRoot, "dist", "modes", "interactive", "interactive-mode.js");
|
||||||
const interactiveThemePath = resolve(piPackageRoot, "dist", "modes", "interactive", "theme", "theme.js");
|
const interactiveThemePath = resolve(piPackageRoot, "dist", "modes", "interactive", "theme", "theme.js");
|
||||||
const piTuiRoot = resolve(appRoot, "node_modules", "@mariozechner", "pi-tui");
|
const editorPath = piTuiRoot ? resolve(piTuiRoot, "dist", "components", "editor.js") : null;
|
||||||
const editorPath = resolve(piTuiRoot, "dist", "components", "editor.js");
|
|
||||||
const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules");
|
const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules");
|
||||||
const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts");
|
const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts");
|
||||||
const sessionSearchIndexerPath = resolve(
|
const sessionSearchIndexerPath = resolve(
|
||||||
@@ -85,7 +111,7 @@ if (existsSync(interactiveThemePath)) {
|
|||||||
writeFileSync(interactiveThemePath, themeSource, "utf8");
|
writeFileSync(interactiveThemePath, themeSource, "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existsSync(editorPath)) {
|
if (editorPath && existsSync(editorPath)) {
|
||||||
let editorSource = readFileSync(editorPath, "utf8");
|
let editorSource = readFileSync(editorPath, "utf8");
|
||||||
const importOriginal =
|
const importOriginal =
|
||||||
'import { getSegmenter, isPunctuationChar, isWhitespaceChar, truncateToWidth, visibleWidth } from "../utils.js";';
|
'import { getSegmenter, isPunctuationChar, isWhitespaceChar, truncateToWidth, visibleWidth } from "../utils.js";';
|
||||||
@@ -250,9 +276,9 @@ if (existsSync(sessionSearchIndexerPath)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const oauthPagePath = resolve(appRoot, "node_modules", "@mariozechner", "pi-ai", "dist", "utils", "oauth", "oauth-page.js");
|
const oauthPagePath = piAiRoot ? resolve(piAiRoot, "dist", "utils", "oauth", "oauth-page.js") : null;
|
||||||
|
|
||||||
if (existsSync(oauthPagePath)) {
|
if (oauthPagePath && existsSync(oauthPagePath)) {
|
||||||
let source = readFileSync(oauthPagePath, "utf8");
|
let source = readFileSync(oauthPagePath, "utf8");
|
||||||
const piLogo = 'const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><path fill="#fff" fill-rule="evenodd" d="M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z M282.65 282.65 V400 H400 V282.65 Z"/><path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/></svg>`;';
|
const piLogo = 'const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><path fill="#fff" fill-rule="evenodd" d="M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z M282.65 282.65 V400 H400 V282.65 Z"/><path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/></svg>`;';
|
||||||
if (source.includes(piLogo)) {
|
if (source.includes(piLogo)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user