diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..404f2e7 --- /dev/null +++ b/.github/workflows/publish.yml @@ -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 }} diff --git a/package-lock.json b/package-lock.json index c82ef41..3281d5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@companion-ai/feynman", - "version": "0.2.3", + "version": "0.2.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@companion-ai/feynman", - "version": "0.2.3", + "version": "0.2.4", "hasInstallScript": true, "dependencies": { "@companion-ai/alpha-hub": "^0.1.2", diff --git a/package.json b/package.json index 3a62ce7..4418dc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@companion-ai/feynman", - "version": "0.2.3", + "version": "0.2.4", "description": "Research-first CLI agent built on Pi and alphaXiv", "type": "module", "bin": { diff --git a/scripts/patch-embedded-pi.mjs b/scripts/patch-embedded-pi.mjs index 37ee257..bc8f693 100644 --- a/scripts/patch-embedded-pi.mjs +++ b/scripts/patch-embedded-pi.mjs @@ -5,14 +5,40 @@ import { fileURLToPath } from "node:url"; const here = dirname(fileURLToPath(import.meta.url)); 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 cliPath = resolve(piPackageRoot, "dist", "cli.js"); const bunCliPath = resolve(piPackageRoot, "dist", "bun", "cli.js"); const interactiveModePath = resolve(piPackageRoot, "dist", "modes", "interactive", "interactive-mode.js"); const interactiveThemePath = resolve(piPackageRoot, "dist", "modes", "interactive", "theme", "theme.js"); -const piTuiRoot = resolve(appRoot, "node_modules", "@mariozechner", "pi-tui"); -const editorPath = resolve(piTuiRoot, "dist", "components", "editor.js"); +const editorPath = piTuiRoot ? resolve(piTuiRoot, "dist", "components", "editor.js") : null; const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules"); const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts"); const sessionSearchIndexerPath = resolve( @@ -85,7 +111,7 @@ if (existsSync(interactiveThemePath)) { writeFileSync(interactiveThemePath, themeSource, "utf8"); } -if (existsSync(editorPath)) { +if (editorPath && existsSync(editorPath)) { let editorSource = readFileSync(editorPath, "utf8"); const importOriginal = '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"); const piLogo = 'const LOGO_SVG = ``;'; if (source.includes(piLogo)) {