@companion-ai/feynman 0.2.60 → 0.2.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
Binary file
|
package/RELEASES.md
CHANGED
|
@@ -4,6 +4,20 @@ This file is the public release history for Feynman. Keep entries user-facing: w
|
|
|
4
4
|
|
|
5
5
|
GitHub release notes are generated from the matching `## vX.Y.Z` section in this file.
|
|
6
6
|
|
|
7
|
+
## v0.2.61 - 2026-06-11
|
|
8
|
+
|
|
9
|
+
### Windows
|
|
10
|
+
|
|
11
|
+
- Fixed bundled-package setup failing on every launch (#177, #170). Two root causes found by running the published package on real Windows runners: GNU tar (Git for Windows) treats the workspace archive's absolute `C:\...` path as a remote host spec ("Cannot connect ... resolve failed"), and the npm fallback spawned bare `npm` without a shell, which Windows rejects with EINVAL. The archive now extracts with relative paths, and npm is invoked through `npm-cli.js` with the running Node executable.
|
|
12
|
+
|
|
13
|
+
### Runtime Reliability
|
|
14
|
+
|
|
15
|
+
- The bundled workspace's alpha-hub copy now receives the same launch-time patches as the package-local copy, so the #167 search fix applies regardless of which copy resolves.
|
|
16
|
+
|
|
17
|
+
### Validation
|
|
18
|
+
|
|
19
|
+
- The multi-OS end-to-end workflow now verifies install, update, patch application, and live model + subagent smokes on Windows, Linux, and macOS at Node 24 and 25.
|
|
20
|
+
|
|
7
21
|
## v0.2.60 - 2026-06-11
|
|
8
22
|
|
|
9
23
|
### Node Support
|
package/dist/pi/package-ops.js
CHANGED
|
@@ -3,7 +3,9 @@ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, re
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
5
|
import { DefaultPackageManager, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { resolveAdjacentNpmCommand } from "../../scripts/lib/npm-command.mjs";
|
|
6
7
|
import { NATIVE_PACKAGE_SOURCES, supportsNativePackageSources } from "./package-presets.js";
|
|
8
|
+
export { resolveAdjacentNpmCommand };
|
|
7
9
|
import { applyFeynmanPackageManagerEnv, getFeynmanNpmPrefixPath } from "./runtime.js";
|
|
8
10
|
import { getPathWithCurrentNode, resolveExecutable } from "../system/executables.js";
|
|
9
11
|
const FILTERED_INSTALL_OUTPUT_PATTERNS = [
|
|
@@ -160,19 +162,6 @@ function ensureProjectInstallRoot(workingDir) {
|
|
|
160
162
|
}
|
|
161
163
|
return installRoot;
|
|
162
164
|
}
|
|
163
|
-
export function resolveAdjacentNpmCommand(nodeExecutablePath = process.execPath, platform = process.platform) {
|
|
164
|
-
const executableDir = dirname(nodeExecutablePath);
|
|
165
|
-
if (platform === "win32") {
|
|
166
|
-
const npmCliPath = resolve(executableDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
167
|
-
if (existsSync(npmCliPath)) {
|
|
168
|
-
return { command: nodeExecutablePath, args: [npmCliPath] };
|
|
169
|
-
}
|
|
170
|
-
const npmCmdPath = resolve(executableDir, "npm.cmd");
|
|
171
|
-
return existsSync(npmCmdPath) ? { command: npmCmdPath, args: [], shell: true } : undefined;
|
|
172
|
-
}
|
|
173
|
-
const candidate = resolve(executableDir, "npm");
|
|
174
|
-
return existsSync(candidate) ? { command: candidate, args: [] } : undefined;
|
|
175
|
-
}
|
|
176
165
|
function resolvePackageManagerCommand(settingsManager) {
|
|
177
166
|
const configured = settingsManager.getNpmCommand();
|
|
178
167
|
if (!configured || configured.length === 0) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
// Windows cannot spawn `npm`/`npm.cmd` without a shell (EINVAL since the
|
|
5
|
+
// CVE-2024-27980 hardening), and shell spawns with an args array trip
|
|
6
|
+
// DEP0190. Preferring the npm-cli.js entry point next to the running Node
|
|
7
|
+
// executable avoids both: it is a plain Node script spawn on every platform.
|
|
8
|
+
export function resolveAdjacentNpmCommand(nodeExecutablePath = process.execPath, platform = process.platform) {
|
|
9
|
+
const executableDir = dirname(nodeExecutablePath);
|
|
10
|
+
if (platform === "win32") {
|
|
11
|
+
const npmCliPath = resolve(executableDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
12
|
+
if (existsSync(npmCliPath)) {
|
|
13
|
+
return { command: nodeExecutablePath, args: [npmCliPath] };
|
|
14
|
+
}
|
|
15
|
+
const npmCmdPath = resolve(executableDir, "npm.cmd");
|
|
16
|
+
return existsSync(npmCmdPath) ? { command: npmCmdPath, args: [], shell: true } : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const candidate = resolve(executableDir, "npm");
|
|
20
|
+
return existsSync(candidate) ? { command: candidate, args: [] } : undefined;
|
|
21
|
+
}
|
|
@@ -9,6 +9,7 @@ import { patchAlphaHubAuthSource } from "./lib/alpha-hub-auth-patch.mjs";
|
|
|
9
9
|
import { patchAlphaHubSearchResultsSource, patchAlphaHubSearchSource } from "./lib/alpha-hub-search-patch.mjs";
|
|
10
10
|
import { patchPiAgentCoreSource } from "./lib/pi-agent-core-patch.mjs";
|
|
11
11
|
import { patchPiExtensionLoaderSource } from "./lib/pi-extension-loader-patch.mjs";
|
|
12
|
+
import { resolveAdjacentNpmCommand } from "./lib/npm-command.mjs";
|
|
12
13
|
import { patchPiModelRegistrySource } from "./lib/pi-model-registry-patch.mjs";
|
|
13
14
|
import { patchPiPackageManagerSource } from "./lib/pi-package-manager-patch.mjs";
|
|
14
15
|
import { patchPiEditorSource, patchPiInteractiveThemeSource, patchPiTuiSource } from "./lib/pi-tui-patch.mjs";
|
|
@@ -192,6 +193,18 @@ function resolvePackageManager() {
|
|
|
192
193
|
return null;
|
|
193
194
|
}
|
|
194
195
|
|
|
196
|
+
function resolvePackageManagerInvocation(packageManager) {
|
|
197
|
+
if (packageManager === "npm") {
|
|
198
|
+
const adjacent = resolveAdjacentNpmCommand();
|
|
199
|
+
if (adjacent) return adjacent;
|
|
200
|
+
}
|
|
201
|
+
const resolved = resolveExecutable(packageManager);
|
|
202
|
+
if (!resolved) return null;
|
|
203
|
+
// Windows cannot spawn .cmd/.bat shims without a shell (EINVAL).
|
|
204
|
+
const needsShell = process.platform === "win32" && /\.(cmd|bat)$/i.test(resolved);
|
|
205
|
+
return { command: resolved, args: [], shell: needsShell };
|
|
206
|
+
}
|
|
207
|
+
|
|
195
208
|
function installWorkspacePackages(packageSpecs) {
|
|
196
209
|
const packageManager = resolvePackageManager();
|
|
197
210
|
if (!packageManager) {
|
|
@@ -201,8 +214,14 @@ function installWorkspacePackages(packageSpecs) {
|
|
|
201
214
|
return false;
|
|
202
215
|
}
|
|
203
216
|
|
|
204
|
-
const
|
|
217
|
+
const invocation = resolvePackageManagerInvocation(packageManager);
|
|
218
|
+
if (!invocation) {
|
|
219
|
+
process.stderr.write(`[feynman] could not resolve ${packageManager} executable for bundled package setup.\n`);
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
const result = spawnSync(invocation.command, [...invocation.args, ...createInstallCommand(packageManager, packageSpecs)], {
|
|
205
223
|
cwd: workspaceDir,
|
|
224
|
+
shell: invocation.shell,
|
|
206
225
|
stdio: ["ignore", "pipe", "pipe"],
|
|
207
226
|
timeout: 300000,
|
|
208
227
|
env: {
|
|
@@ -419,7 +438,11 @@ function restorePackagedWorkspace(packageSpecs) {
|
|
|
419
438
|
rmSync(workspaceDir, { recursive: true, force: true });
|
|
420
439
|
mkdirSync(resolve(appRoot, ".feynman"), { recursive: true });
|
|
421
440
|
|
|
422
|
-
|
|
441
|
+
// Run tar from .feynman with relative paths: GNU tar (Git for Windows)
|
|
442
|
+
// treats absolute paths with a drive-letter colon ("C:\...") as remote
|
|
443
|
+
// host specs and fails with "Cannot connect ... resolve failed".
|
|
444
|
+
const result = spawnSync("tar", ["-xzf", "runtime-workspace.tgz", "-C", "."], {
|
|
445
|
+
cwd: resolve(appRoot, ".feynman"),
|
|
423
446
|
stdio: ["ignore", "ignore", "pipe"],
|
|
424
447
|
timeout: 300000,
|
|
425
448
|
});
|
|
@@ -855,6 +878,23 @@ if (alphaHubIndexPath && existsSync(alphaHubIndexPath)) {
|
|
|
855
878
|
}
|
|
856
879
|
}
|
|
857
880
|
|
|
881
|
+
// The bundled workspace carries its own alpha-hub copy; patch it the same way
|
|
882
|
+
// so search fixes apply regardless of which copy resolves at runtime.
|
|
883
|
+
const workspaceAlphaHubLib = resolve(workspaceRoot, "@companion-ai", "alpha-hub", "src", "lib");
|
|
884
|
+
for (const [fileName, patchFn] of [
|
|
885
|
+
["auth.js", patchAlphaHubAuthSource],
|
|
886
|
+
["alphaxiv.js", patchAlphaHubSearchSource],
|
|
887
|
+
["index.js", patchAlphaHubSearchResultsSource],
|
|
888
|
+
]) {
|
|
889
|
+
const filePath = resolve(workspaceAlphaHubLib, fileName);
|
|
890
|
+
if (!existsSync(filePath)) continue;
|
|
891
|
+
const source = readFileSync(filePath, "utf8");
|
|
892
|
+
const patched = patchFn(source);
|
|
893
|
+
if (patched !== source) {
|
|
894
|
+
writeFileSync(filePath, patched, "utf8");
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
858
898
|
if (existsSync(piMemoryPath)) {
|
|
859
899
|
let source = readFileSync(piMemoryPath, "utf8");
|
|
860
900
|
const memoryOriginal = 'const MEMORY_DIR = join(homedir(), ".pi", "memory");';
|