@nanocollective/nanocoder 1.13.2 → 1.13.3

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/README.md CHANGED
@@ -164,6 +164,15 @@ Nanocoder supports any OpenAI-compatible API through a unified provider configur
164
164
  - `apiKey`: API key (optional, may not be required)
165
165
  - `models`: Available model list for `/model` command
166
166
 
167
+ **Environment Variables:**
168
+
169
+ Keep API keys out of version control using environment variables. Variables are loaded from shell environment (`.bashrc`, `.zshrc`) or `.env` file in your working directory.
170
+
171
+ **Syntax:** `$VAR_NAME`, `${VAR_NAME}`, or `${VAR_NAME:-default}`
172
+ **Supported in:** `baseUrl`, `apiKey`, `models`, MCP server `command`, `args`, `env`
173
+
174
+ See `.env.example` for setup instructions
175
+
167
176
  **Timeout Configuration:**
168
177
 
169
178
  Nanocoder allows you to configure timeouts for your AI providers to handle long-running requests.
@@ -236,6 +245,13 @@ Nanocoder supports connecting to MCP servers to extend its capabilities with add
236
245
  }
237
246
  ```
238
247
 
248
+ **MCP Server Configuration:**
249
+
250
+ - `name`: Display name for the MCP server
251
+ - `command`: Executable command to start the server
252
+ - `args`: Array of command-line arguments
253
+ - `env`: Environment variables for the server process
254
+
239
255
  When MCP servers are configured, Nanocoder will:
240
256
 
241
257
  - Automatically connect to all configured servers on startup
@@ -0,0 +1,4 @@
1
+ export declare function isEnvVarReference(str: string): boolean;
2
+ export declare function expandEnvVar(str: string): string;
3
+ export declare function substituteEnvVars(value: any): any;
4
+ //# sourceMappingURL=env-substitution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-substitution.d.ts","sourceRoot":"","sources":["../../source/config/env-substitution.ts"],"names":[],"mappings":"AAIA,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMtD;AAGD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA8BhD;AAGD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAuBjD"}
@@ -0,0 +1,51 @@
1
+ import { shouldLog } from './logging.js';
2
+ import { logError } from '../utils/message-queue.js';
3
+ // Check if a string contains environment variable references
4
+ export function isEnvVarReference(str) {
5
+ if (typeof str !== 'string') {
6
+ return false;
7
+ }
8
+ return /\$\{[A-Z_][A-Z0-9_]*(?::-[^}]*)?\}|\$[A-Z_][A-Z0-9_]*/g.test(str);
9
+ }
10
+ // Expand environment variable references in a string
11
+ export function expandEnvVar(str) {
12
+ if (typeof str !== 'string') {
13
+ return str;
14
+ }
15
+ const regex = /\$\{([A-Z_][A-Z0-9_]*)(?::-(.*?))?\}|\$([A-Z_][A-Z0-9_]*)/g;
16
+ return str.replace(regex, (match, bracedVarName, defaultValue, unbracedVarName) => {
17
+ const varName = bracedVarName || unbracedVarName;
18
+ const envValue = process.env[varName];
19
+ if (envValue !== undefined) {
20
+ return envValue;
21
+ }
22
+ if (defaultValue !== undefined) {
23
+ return defaultValue;
24
+ }
25
+ if (shouldLog('warn')) {
26
+ logError(`Environment variable ${varName} not found in config, using empty string`);
27
+ }
28
+ return '';
29
+ });
30
+ }
31
+ // Recursively substitute environment variables in objects, arrays, and strings
32
+ export function substituteEnvVars(value) {
33
+ if (value === null || value === undefined) {
34
+ return value;
35
+ }
36
+ if (typeof value === 'string') {
37
+ return expandEnvVar(value);
38
+ }
39
+ if (Array.isArray(value)) {
40
+ return value.map(item => substituteEnvVars(item));
41
+ }
42
+ if (typeof value === 'object') {
43
+ const result = {};
44
+ for (const [key, val] of Object.entries(value)) {
45
+ result[key] = substituteEnvVars(val);
46
+ }
47
+ return result;
48
+ }
49
+ return value;
50
+ }
51
+ //# sourceMappingURL=env-substitution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-substitution.js","sourceRoot":"","sources":["../../source/config/env-substitution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AACvC,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AAEnD,6DAA6D;AAC7D,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,wDAAwD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,YAAY,CAAC,GAAW;IACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,4DAA4D,CAAC;IAE3E,OAAO,GAAG,CAAC,OAAO,CACjB,KAAK,EACL,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE;QACvD,MAAM,OAAO,GAAG,aAAa,IAAI,eAAe,CAAC;QACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,YAAY,CAAC;QACrB,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,QAAQ,CACP,wBAAwB,OAAO,0CAA0C,CACzE,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACX,CAAC,CACD,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB,CAAC,KAAU;IAC3C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAQ,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,mBAAmB,CAAC;AA8BzD,eAAO,MAAM,SAAS,WAAkB,CAAC;AAGzC,eAAO,MAAM,YAAY;;;CAGxB,CAAC;AAEF,wBAAgB,SAAS,IAAI,MAAM,CAIlC;AAGD,eAAO,MAAM,MAAM,EAAE,MAAoB,CAAC;AAM1C,eAAO,MAAM,UAAU,QAGtB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAuCzD,eAAO,MAAM,SAAS,WAAkB,CAAC;AAGzC,eAAO,MAAM,YAAY;;;CAGxB,CAAC;AAEF,wBAAgB,SAAS,IAAI,MAAM,CAIlC;AAGD,eAAO,MAAM,MAAM,EAAE,MAAoB,CAAC;AAM1C,eAAO,MAAM,UAAU,QAGtB,CAAC"}
@@ -1,19 +1,26 @@
1
1
  import { existsSync, readFileSync } from 'fs';
2
2
  import { join, dirname } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { config as loadEnv } from 'dotenv';
4
5
  import { logError } from '../utils/message-queue.js';
5
6
  import { loadPreferences } from './preferences.js';
6
7
  import { getThemeColors, defaultTheme } from './themes.js';
8
+ import { substituteEnvVars } from './env-substitution.js';
9
+ // Load .env file from working directory (shell environment takes precedence)
10
+ loadEnv({ path: join(process.cwd(), '.env') });
7
11
  // Function to load app configuration from agents.config.json if it exists
8
12
  function loadAppConfig() {
9
13
  const agentsJsonPath = join(process.cwd(), 'agents.config.json');
10
14
  if (existsSync(agentsJsonPath)) {
11
15
  try {
12
- const agentsData = JSON.parse(readFileSync(agentsJsonPath, 'utf-8'));
13
- if (agentsData.nanocoder) {
16
+ const rawData = readFileSync(agentsJsonPath, 'utf-8');
17
+ const agentsData = JSON.parse(rawData);
18
+ // Apply environment variable substitution
19
+ const processedData = substituteEnvVars(agentsData);
20
+ if (processedData.nanocoder) {
14
21
  return {
15
- providers: agentsData.nanocoder.providers,
16
- mcpServers: agentsData.nanocoder.mcpServers,
22
+ providers: processedData.nanocoder.providers,
23
+ mcpServers: processedData.nanocoder.mcpServers,
17
24
  };
18
25
  }
19
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,MAAM,IAAI,CAAC;AAC5C,OAAO,EAAC,IAAI,EAAE,OAAO,EAAC,MAAM,MAAM,CAAC;AACnC,OAAO,EAAC,aAAa,EAAC,MAAM,KAAK,CAAC;AAClC,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,aAAa,CAAC;AAEzD,0EAA0E;AAC1E,SAAS,aAAa;IACrB,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAEjE,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;YAErE,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;gBAC1B,OAAO;oBACN,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS;oBACzC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,UAAU;iBAC3C,CAAC;YACH,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,uCAAuC,KAAK,EAAE,CAAC,CAAC;QAC1D,CAAC;IACF,CAAC;IAED,OAAO,EAAE,CAAC;AACX,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;AAEzC,iFAAiF;AACjF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC3B,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,IAAI;CACjB,CAAC;AAEF,MAAM,UAAU,SAAS;IACxB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,aAAa,GAAG,WAAW,CAAC,aAAa,IAAI,YAAY,CAAC;IAChE,OAAO,cAAc,CAAC,aAAa,CAAC,CAAC;AACtC,CAAC;AAED,4CAA4C;AAC5C,MAAM,CAAC,MAAM,MAAM,GAAW,SAAS,EAAE,CAAC;AAE1C,kEAAkE;AAClE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,oFAAoF;AACpF,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAC7B,SAAS,EACT,yCAAyC,CACzC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,MAAM,IAAI,CAAC;AAC5C,OAAO,EAAC,IAAI,EAAE,OAAO,EAAC,MAAM,MAAM,CAAC;AACnC,OAAO,EAAC,aAAa,EAAC,MAAM,KAAK,CAAC;AAClC,OAAO,EAAC,MAAM,IAAI,OAAO,EAAC,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,aAAa,CAAC;AACzD,OAAO,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAExD,6EAA6E;AAC7E,OAAO,CAAC,EAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,EAAC,CAAC,CAAC;AAE7C,0EAA0E;AAC1E,SAAS,aAAa;IACrB,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAEjE,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAEvC,0CAA0C;YAC1C,MAAM,aAAa,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAEpD,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;gBAC7B,OAAO;oBACN,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,SAAS;oBAC5C,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,UAAU;iBAC9C,CAAC;YACH,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,uCAAuC,KAAK,EAAE,CAAC,CAAC;QAC1D,CAAC;IACF,CAAC;IAED,OAAO,EAAE,CAAC;AACX,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;AAEzC,iFAAiF;AACjF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC3B,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,IAAI;CACjB,CAAC;AAEF,MAAM,UAAU,SAAS;IACxB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,aAAa,GAAG,WAAW,CAAC,aAAa,IAAI,YAAY,CAAC;IAChE,OAAO,cAAc,CAAC,aAAa,CAAC,CAAC;AACtC,CAAC;AAED,4CAA4C;AAC5C,MAAM,CAAC,MAAM,MAAM,GAAW,SAAS,EAAE,CAAC;AAE1C,kEAAkE;AAClE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,oFAAoF;AACpF,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAC7B,SAAS,EACT,yCAAyC,CACzC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  export const DEVELOPMENT_MODE_LABELS = {
2
- normal: '▶ normal model on',
2
+ normal: '▶ normal mode on',
3
3
  'auto-accept': '⏵⏵ auto-accept mode on',
4
4
  plan: '⏸ plan mode on',
5
5
  };
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AA0EA,MAAM,CAAC,MAAM,uBAAuB,GAAoC;IACvE,MAAM,EAAE,mBAAmB;IAC3B,aAAa,EAAE,wBAAwB;IACvC,IAAI,EAAE,gBAAgB;CACtB,CAAC"}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AA0EA,MAAM,CAAC,MAAM,uBAAuB,GAAoC;IACvE,MAAM,EAAE,kBAAkB;IAC1B,aAAa,EAAE,wBAAwB;IACvC,IAAI,EAAE,gBAAgB;CACtB,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nanocollective/nanocoder",
3
3
  "main": "dist/cli.js",
4
- "version": "1.13.2",
4
+ "version": "1.13.3",
5
5
  "description": "A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter",
6
6
  "keywords": [
7
7
  "cli",
@@ -50,6 +50,7 @@
50
50
  "@nanostores/react": "^1.0.0",
51
51
  "cheerio": "^1.1.2",
52
52
  "cli-highlight": "^2.1.11",
53
+ "dotenv": "^17.2.3",
53
54
  "ink": "^6.3.1",
54
55
  "ink-big-text": "^2.0.0",
55
56
  "ink-gradient": "^3.0.0",