nemoris 0.1.12 → 0.1.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nemoris",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "type": "module",
5
5
  "description": "Personal AI agent runtime — persistent memory, delivery guarantees, task contracts, self-healing. Local-first, no cloud.",
6
6
  "license": "MIT",
package/src/cli.js CHANGED
@@ -70,6 +70,11 @@ printVersionAndExit();
70
70
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
71
71
  const parentEnvPath = resolveEnvPath(__dirname);
72
72
  loadParentEnv(parentEnvPath);
73
+ // Also load source repo .env as fallback (dev mode: CWD is source, installDir is elsewhere)
74
+ const cwdEnvPath = path.join(process.cwd(), ".env");
75
+ if (cwdEnvPath !== parentEnvPath && fs.existsSync(cwdEnvPath)) {
76
+ loadParentEnv(cwdEnvPath);
77
+ }
73
78
 
74
79
  const { main } = await import("./cli-main.js");
75
80
  const exitCode = await main(process.argv);
@@ -316,9 +316,16 @@ async function buildProviderSelectionOptions(provider, key, { fetchImpl = global
316
316
  const extra = fetchedModels
317
317
  .filter((m) => {
318
318
  if (curatedIds.has(m.id)) return false;
319
- // For large catalogs, only show models from known vendors
319
+ const rawId = m.id.replace(/^openrouter\//, "").replace(/^openai-codex\//, "").replace(/^anthropic\//, "");
320
+ // For direct provider APIs, only show that provider's models
321
+ if (provider === "anthropic") {
322
+ return rawId.startsWith("claude-");
323
+ }
324
+ if (provider === "openai") {
325
+ return rawId.startsWith("gpt-") || rawId.startsWith("o1") || rawId.startsWith("o3") || rawId.startsWith("o4");
326
+ }
327
+ // For large catalogs (OpenRouter), only show models from known vendors
320
328
  if (fetchedModels.length > 50) {
321
- const rawId = m.id.replace(/^openrouter\//, "").replace(/^openai-codex\//, "").replace(/^anthropic\//, "");
322
329
  const vendor = rawId.split("/")[0];
323
330
  return KNOWN_VENDORS.has(vendor);
324
331
  }
@@ -380,7 +387,11 @@ async function promptForProviderModels(provider, key, tui, { fetchImpl = globalT
380
387
  let activeOptions = options;
381
388
  const chosen = [];
382
389
  const manualOptionValue = "__custom__";
383
- const defaultModelValue = options.find((item) => !String(item.value).startsWith("__"))?.value || "";
390
+ // Use first curated model as placeholder for custom entry, not a "new" or extra model
391
+ const defaultModelValue = options.find((item) => {
392
+ const v = String(item.value);
393
+ return !v.startsWith("__") && !v.startsWith("\u2605");
394
+ })?.value || "";
384
395
 
385
396
  console.log(`\n ${cyan(`Choose ${provider === "openrouter" ? "OpenRouter" : provider === "openai" ? "OpenAI" : "Anthropic"} models`)}`);
386
397
  console.log(` ${dim("Pick up to three models. The first is your default. The others are fallbacks when the default is slow or unavailable.")}`);
@@ -743,6 +754,12 @@ export async function runAuthPhase(installDir, options = {}) {
743
754
  if (validatedKeys.openrouter) {
744
755
  envKeys.OPENROUTER_API_KEY = validatedKeys.openrouter;
745
756
  }
757
+ // Enable provider mode when any remote provider is configured
758
+ const hasRemoteProvider = !!(envKeys.NEMORIS_ANTHROPIC_API_KEY || envKeys.OPENROUTER_API_KEY || envKeys.NEMORIS_OPENAI_API_KEY);
759
+ if (hasRemoteProvider) {
760
+ envKeys.NEMORIS_ALLOW_PROVIDER_MODE = "1";
761
+ envKeys.NEMORIS_ALLOW_REMOTE_PROVIDER_MODE = "1";
762
+ }
746
763
  if (Object.keys(envKeys).length > 0) {
747
764
  writeEnvFile(installDir, envKeys);
748
765
  }
@@ -28,9 +28,9 @@ export function stripAnsi(str) {
28
28
  return str.replace(/\x1b\[[0-9;]*m/g, "");
29
29
  }
30
30
 
31
- export function buildTelegramToml({ botTokenEnv, pollingMode, webhookUrl, operatorChatId, authorizedChatIds, defaultAgent }) {
31
+ export function buildTelegramToml({ botTokenEnv, pollingMode, webhookUrl, operatorChatId, authorizedChatIds, defaultAgent, botUsername }) {
32
32
  const authIds = (authorizedChatIds || []).map((id) => `"${id}"`).join(", ");
33
- return [
33
+ const lines = [
34
34
  "",
35
35
  "[telegram]",
36
36
  `bot_token_env = "${botTokenEnv}"`,
@@ -39,8 +39,10 @@ export function buildTelegramToml({ botTokenEnv, pollingMode, webhookUrl, operat
39
39
  `operator_chat_id = "${operatorChatId || ""}"`,
40
40
  `authorized_chat_ids = [${authIds}]`,
41
41
  `default_agent = "${defaultAgent}"`,
42
- "",
43
- ].join("\n");
42
+ ];
43
+ if (botUsername) lines.push(`bot_username = "${botUsername}"`);
44
+ lines.push("");
45
+ return lines.join("\n");
44
46
  }
45
47
 
46
48
  export function patchRuntimeToml(installDir, telegramToml) {
@@ -227,6 +229,7 @@ export async function runTelegramPhase({ installDir, agentId, nonInteractive = f
227
229
  patchRuntimeToml(installDir, buildTelegramToml({
228
230
  botTokenEnv, pollingMode: mode === "polling", webhookUrl,
229
231
  operatorChatId: chatId, authorizedChatIds, defaultAgent: agentId,
232
+ botUsername: me.username,
230
233
  }));
231
234
 
232
235
  return { configured: true, verified: false, botUsername: me.username, botToken: token, operatorChatId: chatId };
@@ -323,6 +326,7 @@ export async function runTelegramPhase({ installDir, agentId, nonInteractive = f
323
326
  patchRuntimeToml(installDir, buildTelegramToml({
324
327
  botTokenEnv, pollingMode, webhookUrl,
325
328
  operatorChatId: chatId || "", authorizedChatIds, defaultAgent: agentId,
329
+ botUsername,
326
330
  }));
327
331
 
328
332
  // Wire delivery.toml so the telegram profile is enabled
@@ -332,21 +336,6 @@ export async function runTelegramPhase({ installDir, agentId, nonInteractive = f
332
336
  chatIdPending: !chatId,
333
337
  });
334
338
 
335
- // Persist bot_username to runtime.toml for finish screen / status
336
- if (botUsername) {
337
- const runtimePath = path.join(installDir, "config", "runtime.toml");
338
- try {
339
- let runtime = fs.readFileSync(runtimePath, "utf8");
340
- if (runtime.includes("[telegram]") && !runtime.includes("bot_username")) {
341
- runtime = runtime.replace(
342
- /(\[telegram\][^\[]*)/s,
343
- (section) => section.trimEnd() + `\nbot_username = "${botUsername}"\n`
344
- );
345
- fs.writeFileSync(runtimePath, runtime);
346
- }
347
- } catch { /* non-fatal */ }
348
- }
349
-
350
339
  // Store chat_id in state for later phases (e.g. hatch)
351
340
  const result = { configured: true, verified: false, botUsername, botToken: token, operatorChatId: chatId || "" };
352
341