@companion-ai/feynman 0.5.19 → 0.5.20
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.
- package/RELEASES.md +4 -0
- package/dist/config/json-file.js +9 -0
- package/dist/model/catalog.js +2 -2
- package/dist/model/service-tier.js +3 -2
- package/dist/pi/settings.js +6 -4
- package/dist/pi/web-access.js +3 -2
- package/package.json +1 -1
package/RELEASES.md
CHANGED
|
@@ -6,6 +6,10 @@ GitHub release notes are generated from the matching `## vX.Y.Z` section in this
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## v0.5.20 - 2026-10-01
|
|
10
|
+
|
|
11
|
+
- **Settings saved by Windows Notepad or PowerShell no longer stop Feynman.** Both can save UTF-8 with a byte-order mark, which JSON parsing rejects, so Feynman refused to start with "Invalid Feynman settings ... expected a JSON object", and other commands read the file as empty. Feynman now ignores the mark in `settings.json`, `auth.json`, and `web-search.json`, as Pi does. A settings file with a real JSON error now names the error, for example a trailing comma, instead of the generic message.
|
|
12
|
+
|
|
9
13
|
## v0.5.19 - 2026-10-01
|
|
10
14
|
|
|
11
15
|
- **Word drafts open without LibreOffice.** `document_parse` needs LibreOffice for `.docx` files, which most machines lack, so reviewing a thesis or draft in Word format failed. When LibreOffice is missing, Feynman now reads the document's paragraph text directly from the `.docx` and says so; install LibreOffice for page layout, tables, footnotes, and images.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
// Windows Notepad and PowerShell 5.1 save UTF-8 with a byte-order mark, which
|
|
3
|
+
// JSON.parse rejects. Pi strips it when it reads the same files.
|
|
4
|
+
export function parseJsonText(source) {
|
|
5
|
+
return JSON.parse(source.replace(/^/, ""));
|
|
6
|
+
}
|
|
7
|
+
export function readJsonFile(path) {
|
|
8
|
+
return parseJsonText(readFileSync(path, "utf8"));
|
|
9
|
+
}
|
package/dist/model/catalog.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { getEnvApiKey } from "@earendil-works/pi-ai/compat";
|
|
2
|
+
import { readJsonFile } from "../config/json-file.js";
|
|
3
3
|
import { createModelRuntime } from "./registry.js";
|
|
4
4
|
const PRO_CLASS_MODEL_PATTERN = /(?:^|[-_.:/])pro(?:$|[-_.:/])/i;
|
|
5
5
|
// Pi catalogs these exact DeepSeek V4 Pro model IDs as ordinary open-weight
|
|
@@ -334,7 +334,7 @@ export async function getSupportedModelRecords(authPath) {
|
|
|
334
334
|
function readExpiredOAuthProviders(authPath) {
|
|
335
335
|
const expired = new Set();
|
|
336
336
|
try {
|
|
337
|
-
const parsed =
|
|
337
|
+
const parsed = readJsonFile(authPath);
|
|
338
338
|
for (const [provider, credential] of Object.entries(parsed)) {
|
|
339
339
|
if (!credential || typeof credential !== "object")
|
|
340
340
|
continue;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { mkdirSync,
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
+
import { readJsonFile } from "../config/json-file.js";
|
|
3
4
|
export const FEYNMAN_SERVICE_TIERS = [
|
|
4
5
|
"auto",
|
|
5
6
|
"default",
|
|
@@ -12,7 +13,7 @@ const OPENAI_SERVICE_TIERS = new Set(["auto", "default", "flex", "priority"]);
|
|
|
12
13
|
const ANTHROPIC_SERVICE_TIERS = new Set(["auto", "standard_only"]);
|
|
13
14
|
function readSettings(settingsPath) {
|
|
14
15
|
try {
|
|
15
|
-
return
|
|
16
|
+
return readJsonFile(settingsPath);
|
|
16
17
|
}
|
|
17
18
|
catch {
|
|
18
19
|
return {};
|
package/dist/pi/settings.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { parseJsonText, readJsonFile } from "../config/json-file.js";
|
|
3
4
|
import { BUNDLED_PI_PACKAGES, getFeynmanPackageSources, resolvePackageRoot } from "./runtime.js";
|
|
4
5
|
import { choosePreferredModelRecord, getAvailableModelRecords } from "../model/catalog.js";
|
|
5
6
|
// Written by Feynman <= 0.4.0 next to a subagent extension path it managed.
|
|
@@ -50,7 +51,7 @@ export function readJson(path) {
|
|
|
50
51
|
return {};
|
|
51
52
|
}
|
|
52
53
|
try {
|
|
53
|
-
return
|
|
54
|
+
return readJsonFile(path);
|
|
54
55
|
}
|
|
55
56
|
catch (error) {
|
|
56
57
|
if (process.env.FEYNMAN_DEBUG === "1") {
|
|
@@ -66,10 +67,11 @@ function readConfigObject(path, label) {
|
|
|
66
67
|
const source = readFileSync(path, "utf8");
|
|
67
68
|
let value;
|
|
68
69
|
try {
|
|
69
|
-
value =
|
|
70
|
+
value = parseJsonText(source);
|
|
70
71
|
}
|
|
71
|
-
catch {
|
|
72
|
-
|
|
72
|
+
catch (error) {
|
|
73
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
74
|
+
throw new Error(`Invalid ${label} at ${path}: ${reason}. Fix the JSON or delete the file. The file was not changed.`);
|
|
73
75
|
}
|
|
74
76
|
if (!isRecord(value)) {
|
|
75
77
|
throw new Error(`Invalid ${label} at ${path}: expected a JSON object. The file was not changed.`);
|
package/dist/pi/web-access.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync,
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { readJsonFile } from "../config/json-file.js";
|
|
3
4
|
import { getFeynmanAgentDir, getFeynmanHome } from "../config/paths.js";
|
|
4
5
|
// pi-web-access reads web-search.json from PI_CODING_AGENT_DIR.
|
|
5
6
|
export function getPiWebSearchConfigPath(home) {
|
|
@@ -20,7 +21,7 @@ export function loadPiWebAccessConfig(configPath = getPiWebSearchConfigPath()) {
|
|
|
20
21
|
return {};
|
|
21
22
|
}
|
|
22
23
|
try {
|
|
23
|
-
const parsed =
|
|
24
|
+
const parsed = readJsonFile(configPath);
|
|
24
25
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
25
26
|
}
|
|
26
27
|
catch {
|