@companion-ai/feynman 0.5.35 → 0.5.36
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 +10 -0
- package/dist/cli.js +15 -10
- package/dist/model/commands.js +14 -18
- package/dist/setup/prompts.js +12 -1
- package/dist/setup/setup.js +13 -6
- package/package.json +1 -1
package/RELEASES.md
CHANGED
|
@@ -6,6 +6,16 @@ GitHub release notes are generated from the matching `## vX.Y.Z` section in this
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## v0.5.36 - 2026-10-12
|
|
10
|
+
|
|
11
|
+
- **A new user gets to a working model instead of a dead end.** Launching `feynman` with no model opens a menu to set one up.
|
|
12
|
+
- Typing a question there moved the selection onto Cancel: the menu treated `h`, `j`, `k` and `l` as arrow keys. Only the arrow keys move it now.
|
|
13
|
+
- Cancel used to go on to optional packages, an alphaXiv sign-in that defaulted to Yes, and pandoc, then said "Feynman is ready" with no model. It now exits and says how to add a model, and that your question was not sent.
|
|
14
|
+
- The first launch asks only for the model. Packages, alphaXiv and pandoc stay in `feynman setup`, where alphaXiv now defaults to No.
|
|
15
|
+
- Esc in a provider list goes back to the previous menu instead of ending setup.
|
|
16
|
+
- `feynman -p "…"` with no model now says how to add one, instead of pointing at Pi's `/login` and files inside `node_modules`.
|
|
17
|
+
- `feynman help` drops the duplicate "Getting Started" list and calls the flag section "Options".
|
|
18
|
+
|
|
9
19
|
## v0.5.35 - 2026-10-11
|
|
10
20
|
|
|
11
21
|
- **PubMed group authors keep their affiliations.** Consortium and study-group authors came back with no affiliations; they now keep them, as individual authors do. Thanks to @KennyMcSimpson (#335).
|
package/dist/cli.js
CHANGED
|
@@ -29,6 +29,7 @@ import { fetchLatestFeynmanVersion, getFeynmanUpgradeLines, isNewerVersion } fro
|
|
|
29
29
|
import { runDoctor, runStatus } from "./setup/doctor.js";
|
|
30
30
|
import { setupPreviewDependencies } from "./setup/preview.js";
|
|
31
31
|
import { runSetup } from "./setup/setup.js";
|
|
32
|
+
import { noModelMessage } from "./setup/prompts.js";
|
|
32
33
|
import { captureTelemetryEvent, captureTelemetryException, getCliTelemetryMetadata, initializePostHogTelemetry, shutdownPostHogTelemetry, telemetryErrorProperties, telemetryFirstRunNotice, } from "./telemetry/posthog.js";
|
|
33
34
|
import { ASH, printAsciiHeader, printInfo, printPanel, printSection, RESET, SAGE } from "./ui/terminal.js";
|
|
34
35
|
import { createModelRuntime } from "./model/registry.js";
|
|
@@ -57,12 +58,6 @@ function printHelp(appRoot) {
|
|
|
57
58
|
"The open source AI research agent.",
|
|
58
59
|
"Use `feynman setup` first if this is a new machine.",
|
|
59
60
|
]);
|
|
60
|
-
printSection("Getting Started");
|
|
61
|
-
printInfo("feynman");
|
|
62
|
-
printInfo("feynman setup");
|
|
63
|
-
printInfo("feynman doctor");
|
|
64
|
-
printInfo("feynman model");
|
|
65
|
-
printInfo("feynman search status");
|
|
66
61
|
printSection("Commands");
|
|
67
62
|
for (const section of cliCommandSections) {
|
|
68
63
|
for (const command of section.commands) {
|
|
@@ -73,7 +68,7 @@ function printHelp(appRoot) {
|
|
|
73
68
|
for (const command of workflowCommands) {
|
|
74
69
|
printHelpLine(formatCliWorkflowUsage(command), command.description);
|
|
75
70
|
}
|
|
76
|
-
printSection("
|
|
71
|
+
printSection("Options");
|
|
77
72
|
for (const flag of legacyFlags) {
|
|
78
73
|
printHelpLine(flag.usage, flag.description);
|
|
79
74
|
}
|
|
@@ -652,6 +647,10 @@ async function runMain(input) {
|
|
|
652
647
|
}
|
|
653
648
|
explicitModelSpec = canonicalModelSpec;
|
|
654
649
|
}
|
|
650
|
+
const workflowCommandNames = new Set(readPromptSpecs(appRoot).filter((s) => s.topLevelCli).map((s) => s.name));
|
|
651
|
+
const workflowRest = appendWorkflowFlagPositionals(command, rest, values);
|
|
652
|
+
const promptOptions = resolvePiPromptOptions(command, workflowRest, values.prompt, workflowCommandNames);
|
|
653
|
+
const promptGiven = Boolean(promptOptions.oneShotPrompt || promptOptions.initialPrompt);
|
|
655
654
|
const currentModelSpec = getCurrentModelSpec(feynmanSettingsPath);
|
|
656
655
|
if (await shouldRunInteractiveSetup(explicitModelSpec, currentModelSpec, Boolean(process.stdin.isTTY && process.stdout.isTTY), feynmanAuthPath)) {
|
|
657
656
|
await runSetup({
|
|
@@ -662,15 +661,21 @@ async function runMain(input) {
|
|
|
662
661
|
sessionDir,
|
|
663
662
|
appRoot,
|
|
664
663
|
defaultThinkingLevel,
|
|
664
|
+
modelOnly: true,
|
|
665
665
|
});
|
|
666
666
|
if (!getCurrentModelSpec(feynmanSettingsPath)) {
|
|
667
|
+
console.error(noModelMessage(promptGiven));
|
|
668
|
+
process.exitCode = 1;
|
|
667
669
|
return;
|
|
668
670
|
}
|
|
669
671
|
await ensureFeynmanSettings(feynmanSettingsPath, bundledSettingsPath, appRoot, defaultThinkingLevel, feynmanAuthPath);
|
|
670
672
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
673
|
+
if (!explicitModelSpec && mode !== "rpc" && !(process.stdin.isTTY && process.stdout.isTTY)
|
|
674
|
+
&& (await getAuthenticatedModelRecords(feynmanAuthPath)).length === 0) {
|
|
675
|
+
console.error(noModelMessage(promptGiven));
|
|
676
|
+
process.exitCode = 1;
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
674
679
|
// Pi's own session flags pass through; Feynman continues the latest
|
|
675
680
|
// session only when none of them is given.
|
|
676
681
|
const piArgs = [
|
package/dist/model/commands.js
CHANGED
|
@@ -4,7 +4,7 @@ import { randomUUID } from "node:crypto";
|
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { readJson } from "../pi/settings.js";
|
|
7
|
-
import { promptChoice, promptSecret, promptSelect, promptText, validateApiKeyInput } from "../setup/prompts.js";
|
|
7
|
+
import { promptChoice, promptSecret, promptSelect, promptText, SetupCancelledError, validateApiKeyInput } from "../setup/prompts.js";
|
|
8
8
|
import { openUrl } from "../system/open-url.js";
|
|
9
9
|
import { printInfo, printSection, printSuccess, printWarning } from "../ui/terminal.js";
|
|
10
10
|
import { buildModelStatusSnapshotFromRecords, chooseRecommendedModel, getAuthenticatedModelRecords, getAvailableModelRecords, getSupportedModelRecords, isProClassModelSpec, } from "./catalog.js";
|
|
@@ -911,23 +911,19 @@ export async function runModelSetup(settingsPath, authPath) {
|
|
|
911
911
|
"Cancel",
|
|
912
912
|
];
|
|
913
913
|
const selection = await promptChoice("Choose how to configure model access:", choices, 0);
|
|
914
|
-
if (selection ===
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
}
|
|
928
|
-
else {
|
|
929
|
-
printInfo("Setup cancelled.");
|
|
930
|
-
return;
|
|
914
|
+
if (selection === 2)
|
|
915
|
+
throw new SetupCancelledError();
|
|
916
|
+
// Esc inside a provider list goes back to this menu instead of ending setup.
|
|
917
|
+
const done = await (selection === 0
|
|
918
|
+
? loginModelProvider(authPath, undefined, settingsPath)
|
|
919
|
+
: configureApiKeyProvider(authPath)).catch((error) => {
|
|
920
|
+
if (error instanceof SetupCancelledError)
|
|
921
|
+
return false;
|
|
922
|
+
throw error;
|
|
923
|
+
});
|
|
924
|
+
if (!done) {
|
|
925
|
+
status = await collectModelStatus(settingsPath, authPath);
|
|
926
|
+
continue;
|
|
931
927
|
}
|
|
932
928
|
status = await collectModelStatus(settingsPath, authPath);
|
|
933
929
|
if (status.availableModels.length === 0) {
|
package/dist/setup/prompts.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { confirm as clackConfirm, intro as clackIntro, isCancel, multiselect as clackMultiselect, outro as clackOutro, password as clackPassword, select as clackSelect, text as clackText, } from "@clack/prompts";
|
|
1
|
+
import { confirm as clackConfirm, intro as clackIntro, isCancel, multiselect as clackMultiselect, outro as clackOutro, password as clackPassword, select as clackSelect, text as clackText, settings as clackSettings, } from "@clack/prompts";
|
|
2
|
+
// clack treats h/j/k/l as arrow keys, so a question typed into a setup menu
|
|
3
|
+
// moved the selection (often onto Cancel). Only the arrow keys move it.
|
|
4
|
+
for (const key of ["h", "j", "k", "l"])
|
|
5
|
+
clackSettings.aliases.delete(key);
|
|
2
6
|
export class SetupCancelledError extends Error {
|
|
3
7
|
constructor(message = "setup cancelled") {
|
|
4
8
|
super(message);
|
|
@@ -14,6 +18,13 @@ export function nonInteractiveTerminalMessage(env = process.env, platform = proc
|
|
|
14
18
|
"To skip the prompts, set your provider's API key variable (for example OPENAI_API_KEY or ANTHROPIC_API_KEY) and run `feynman model set <provider/model>`.",
|
|
15
19
|
].join("\n");
|
|
16
20
|
}
|
|
21
|
+
export function noModelMessage(promptGiven = false) {
|
|
22
|
+
return [
|
|
23
|
+
"No model is set up yet, so Feynman can't answer.",
|
|
24
|
+
"Sign in with `feynman model login`, or set ANTHROPIC_API_KEY or OPENAI_API_KEY, then run feynman again.",
|
|
25
|
+
...(promptGiven ? ["Your question was not sent."] : []),
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
17
28
|
function ensureInteractiveTerminal() {
|
|
18
29
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
19
30
|
throw new Error(nonInteractiveTerminalMessage());
|
package/dist/setup/setup.js
CHANGED
|
@@ -8,7 +8,7 @@ import { buildModelStatusSnapshotFromRecords, getAvailableModelRecords, getSuppo
|
|
|
8
8
|
import { PANDOC_FALLBACK_PATHS, resolveExecutable } from "../system/executables.js";
|
|
9
9
|
import { setupPreviewDependencies } from "./preview.js";
|
|
10
10
|
import { printInfo, printSection, printSuccess } from "../ui/terminal.js";
|
|
11
|
-
import { isInteractiveTerminal, promptConfirm, promptIntro, promptMultiSelect, promptOutro, SetupCancelledError, } from "./prompts.js";
|
|
11
|
+
import { isInteractiveTerminal, noModelMessage, promptConfirm, promptIntro, promptMultiSelect, promptOutro, SetupCancelledError, } from "./prompts.js";
|
|
12
12
|
function printNonInteractiveSetupGuidance() {
|
|
13
13
|
printInfo("Non-interactive terminal. Use explicit commands:");
|
|
14
14
|
printInfo(" feynman model login <provider>");
|
|
@@ -49,7 +49,7 @@ async function maybeLoginAlpha() {
|
|
|
49
49
|
printInfo("alphaXiv already configured.");
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
-
const shouldLogin = await promptConfirm("Connect alphaXiv now?",
|
|
52
|
+
const shouldLogin = await promptConfirm("Connect alphaXiv now?", false);
|
|
53
53
|
if (!shouldLogin) {
|
|
54
54
|
printInfo("Skipping alphaXiv login for now.");
|
|
55
55
|
return;
|
|
@@ -88,9 +88,11 @@ export async function runSetup(options) {
|
|
|
88
88
|
try {
|
|
89
89
|
await promptIntro("Feynman setup");
|
|
90
90
|
await runModelSetup(options.settingsPath, options.authPath);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
if (!options.modelOnly) {
|
|
92
|
+
await maybeInstallOptionalPackages(options);
|
|
93
|
+
await maybeLoginAlpha();
|
|
94
|
+
await maybeInstallPreviewDependencies();
|
|
95
|
+
}
|
|
94
96
|
await ensureFeynmanSettings(options.settingsPath, options.bundledSettingsPath, options.appRoot, options.defaultThinkingLevel ?? "medium", options.authPath);
|
|
95
97
|
const modelStatus = buildModelStatusSnapshotFromRecords(await getSupportedModelRecords(options.authPath), await getAvailableModelRecords(options.authPath), getCurrentModelSpec(options.settingsPath));
|
|
96
98
|
printSection("Ready");
|
|
@@ -105,7 +107,12 @@ export async function runSetup(options) {
|
|
|
105
107
|
}
|
|
106
108
|
catch (error) {
|
|
107
109
|
if (error instanceof SetupCancelledError) {
|
|
108
|
-
|
|
110
|
+
// The first launch reports the missing model itself.
|
|
111
|
+
if (!options.modelOnly) {
|
|
112
|
+
printInfo("Setup cancelled.");
|
|
113
|
+
if (!getCurrentModelSpec(options.settingsPath))
|
|
114
|
+
printInfo(noModelMessage());
|
|
115
|
+
}
|
|
109
116
|
return;
|
|
110
117
|
}
|
|
111
118
|
throw error;
|