@octocodeai/config 17.0.0

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/home.ts", "../src/config/types.ts", "../src/config/defaults.ts", "../src/config/runtimeSurface.ts", "../src/config/validator.ts", "../src/config/loader.ts", "../src/config/resolverSections.ts", "../src/config/resolverCache.ts", "../src/config/resolver.ts", "../src/tokens/envTokens.ts"],
4
+ "sourcesContent": ["// @octocodeai/config \u2014 single source of truth for ALL Octocode config + token env logic.\n//\n// Surfaces: MCP server \u00B7 CLI \u00B7 VS Code extension \u00B7 Pi extension \u00B7 agent \u00B7 standalone skills\n//\n// Zero dependencies (Node builtins only). Cross-platform.\n//\n// Precedence:\n// explicit process.env > <project>/.octocode/.env > <home>/.env > <home>/.octocoderc > defaults\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n// \u2500\u2500\u2500 Re-export getOctocodeHome (defined in home.ts to break circular deps) \u2500\u2500\u2500\nexport { getOctocodeHome } from './home.js';\nimport { getOctocodeHome } from './home.js';\n\n// \u2500\u2500\u2500 Re-exports from config/ and tokens/ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport * from './config/index.js';\nexport * from './tokens/index.js';\n\n// \u2500\u2500\u2500 Env loading (uses loadConfigSync from config/loader.ts below) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { loadConfigSync } from './config/loader.js';\n\n/** Keys a project/global .env must never override \u2014 infrastructure + all auth tokens. */\nexport const PROTECTED_KEYS: ReadonlySet<string> = new Set([\n 'PATH', 'HOME', 'SHELL', 'USER', 'LOGNAME', 'PWD', 'TMPDIR', 'NODE_OPTIONS',\n 'OCTOCODE_TOKEN', 'GH_TOKEN', 'GITHUB_TOKEN', 'GITHUB_PERSONAL_ACCESS_TOKEN', 'PYTHON',\n]);\n\n/**\n * Parse dotenv text into a { KEY: VALUE } map. Strict KEY=VALUE, `#` comments,\n * optional `export ` prefix, surrounding quotes stripped. No shell expansion.\n */\nexport function parseEnv(text: string | null | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (!text) return out;\n for (const rawLine of text.split('\\n')) {\n const trimmed = rawLine.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const normalized = trimmed.startsWith('export ')\n ? trimmed.slice('export '.length).trim()\n : trimmed;\n const eq = normalized.indexOf('=');\n if (eq === -1) continue;\n const key = normalized.slice(0, eq).trim();\n if (!key) continue;\n out[key] = normalized.slice(eq + 1).trim().replace(/^[\"']|[\"']$/g, '');\n }\n return out;\n}\n\nfunction readTextIfExists(filePath: string): string {\n try { return fs.readFileSync(filePath, 'utf8'); } catch { return ''; }\n}\n\nexport interface LoadOctocodeEnvOptions {\n home?: string;\n cwd?: string;\n trusted?: boolean;\n}\n\nexport interface LoadOctocodeEnvResult {\n map: Record<string, string>;\n sources: Record<string, 'global' | 'project'>;\n}\n\n/**\n * Load merged Octocode env from global then project (project wins).\n * Returns { map, sources } where sources[key] = 'global' | 'project' (names only, no values).\n * The project file is included only when trusted.\n */\nexport function loadOctocodeEnv({\n home,\n cwd,\n trusted = false,\n}: LoadOctocodeEnvOptions = {}): LoadOctocodeEnvResult {\n const map: Record<string, string> = {};\n const sources: Record<string, 'global' | 'project'> = {};\n\n if (home) {\n for (const [k, v] of Object.entries(parseEnv(readTextIfExists(path.join(home, '.env'))))) {\n map[k] = v;\n sources[k] = 'global';\n }\n }\n if (cwd && trusted) {\n for (const [k, v] of Object.entries(\n parseEnv(readTextIfExists(path.join(cwd, '.octocode', '.env'))),\n )) {\n map[k] = v;\n sources[k] = 'project';\n }\n }\n return { map, sources };\n}\n\nexport interface ApplyOctocodeEnvOptions {\n env?: Record<string, string | undefined>;\n}\n\nexport interface ApplyOctocodeEnvResult {\n applied: string[];\n skippedProtected: string[];\n skippedExisting: string[];\n}\n\n/**\n * Apply a parsed env map into `env`. Skips keys already set (env wins over files) and\n * protected keys. Returns names only \u2014 never values \u2014 for logging/status.\n */\nexport function applyOctocodeEnv(\n map: Record<string, string> | null | undefined,\n { env = process.env }: ApplyOctocodeEnvOptions = {},\n): ApplyOctocodeEnvResult {\n const applied: string[] = [];\n const skippedProtected: string[] = [];\n const skippedExisting: string[] = [];\n\n for (const [key, value] of Object.entries(map ?? {})) {\n if (PROTECTED_KEYS.has(key)) { skippedProtected.push(key); continue; }\n const existing = env[key];\n if (existing !== undefined && existing !== '') { skippedExisting.push(key); continue; }\n env[key] = value;\n applied.push(key);\n }\n return { applied, skippedProtected, skippedExisting };\n}\n\nexport interface PropagateOctocodeEnvOptions {\n home?: string;\n cwd?: string;\n trusted?: boolean;\n env?: Record<string, string | undefined>;\n}\n\nexport interface PropagateOctocodeEnvResult extends ApplyOctocodeEnvResult {\n sources: Record<string, 'global' | 'project'>;\n keys: string[];\n}\n\n/** Convenience: load + apply in one call. Returns names-only metadata. */\nexport function propagateOctocodeEnv({\n home = getOctocodeHome(),\n cwd,\n trusted = false,\n env = process.env,\n}: PropagateOctocodeEnvOptions = {}): PropagateOctocodeEnvResult {\n const { map, sources } = loadOctocodeEnv({ home, cwd, trusted });\n const result = applyOctocodeEnv(map, { env });\n return { ...result, sources, keys: Object.keys(map) };\n}\n\n/**\n * True when stats.json writes are enabled via OCTOCODE_ENABLE_STATS=1|true.\n * Stats are always tracked in memory; this flag controls disk persistence only.\n * Keeping it off (the default) eliminates one write per 60-second flush cycle.\n */\nexport function isStatsEnabled(env: NodeJS.ProcessEnv = process.env): boolean {\n const v = env['OCTOCODE_ENABLE_STATS'];\n return v === '1' || v === 'true';\n}\n\n/**\n * Read and parse `<home>/.octocoderc`.\n * Delegates to the robust JSON5 loader (state-machine based, handles // inside strings).\n * Returns {} when absent or invalid. No secrets belong here.\n */\nexport function loadOctocoderc(home: string = getOctocodeHome()): Record<string, unknown> {\n const result = loadConfigSync(home);\n if (result.success) return result.config ? (result.config as Record<string, unknown>) : {};\n // File absent is silent; any other failure (parse error etc.) is reported.\n if (result.error && result.error !== 'Config file does not exist') {\n process.stderr.write(`[octocode-config] Failed to parse .octocoderc: ${result.error}\\n`);\n }\n return {};\n}\n", "/**\n * getOctocodeHome \u2014 single source of truth for the Octocode home directory.\n * Kept in its own file so config/loader.ts can import it without creating a\n * circular dependency with the main index.ts.\n *\n * Unified home per platform (matches octocode-tools-core/src/shared/paths.ts):\n * macOS: ~/.octocode\n * Linux: ${XDG_CONFIG_HOME:-~/.config}/.octocode\n * Windows: %APPDATA%\\.octocode\n * override: OCTOCODE_HOME\n */\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport function getOctocodeHome(env: Record<string, string | undefined> = process.env): string {\n const override = env['OCTOCODE_HOME'];\n if (override && override.trim()) return path.resolve(override.trim());\n const home = os.homedir();\n const platform = os.platform();\n if (platform === 'win32') {\n const appData = env['APPDATA'] ?? path.join(home, 'AppData', 'Roaming');\n return path.join(appData, '.octocode');\n }\n if (platform === 'darwin') return path.join(home, '.octocode');\n const xdg = env['XDG_CONFIG_HOME'] ?? path.join(home, '.config');\n return path.join(xdg, '.octocode');\n}\n", "export const CONFIG_SCHEMA_VERSION = 1;\n\nexport const CONFIG_FILE_NAME = '.octocoderc';\n\nexport interface GitHubConfigOptions {\n apiUrl?: string;\n}\n\nexport interface LocalConfigOptions {\n enabled?: boolean;\n\n enableClone?: boolean;\n\n allowedPaths?: string[];\n\n workspaceRoot?: string;\n}\n\nexport interface ToolsConfigOptions {\n enabled?: string[] | null;\n\n enableAdditional?: string[] | null;\n\n disabled?: string[] | null;\n}\n\nexport interface NetworkConfigOptions {\n timeout?: number;\n\n maxRetries?: number;\n}\n\nexport interface LspConfigOptions {\n configPath?: string;\n}\n\nexport interface OutputPaginationConfigOptions {\n defaultCharLength?: number;\n}\n\nexport type MinifyMode = 'none' | 'standard' | 'symbols';\n\nexport interface OutputConfigOptions {\n format?: 'yaml' | 'json';\n\n pagination?: OutputPaginationConfigOptions;\n}\n\nexport interface OctocodeConfig {\n $schema?: string;\n\n version?: number;\n\n github?: GitHubConfigOptions;\n\n local?: LocalConfigOptions;\n\n tools?: ToolsConfigOptions;\n\n network?: NetworkConfigOptions;\n\n lsp?: LspConfigOptions;\n\n output?: OutputConfigOptions;\n}\n\nexport interface RequiredGitHubConfig {\n apiUrl: string;\n}\n\nexport interface RequiredLocalConfig {\n enabled: boolean;\n enableClone: boolean;\n allowedPaths: string[];\n workspaceRoot: string | undefined;\n}\n\nexport interface RequiredToolsConfig {\n enabled: string[] | null;\n enableAdditional: string[] | null;\n disabled: string[] | null;\n}\n\nexport interface RequiredNetworkConfig {\n timeout: number;\n maxRetries: number;\n}\n\nexport interface RequiredLspConfig {\n configPath: string | undefined;\n}\n\nexport interface RequiredOutputPaginationConfig {\n defaultCharLength: number;\n}\n\nexport interface RequiredOutputConfig {\n format: 'yaml' | 'json';\n pagination: RequiredOutputPaginationConfig;\n}\n\nexport interface ResolvedConfig {\n version: number;\n\n github: RequiredGitHubConfig;\n\n local: RequiredLocalConfig;\n\n tools: RequiredToolsConfig;\n\n network: RequiredNetworkConfig;\n\n lsp: RequiredLspConfig;\n\n output: RequiredOutputConfig;\n\n session: RequiredSessionConfig;\n\n source: 'file' | 'defaults' | 'mixed';\n\n configPath?: string;\n}\n\n/**\n * Session / stats persistence options (env-var only \u2014 no .octocoderc equivalent).\n * Resolved entirely from OCTOCODE_ENABLE_STATS; default is off to avoid\n * unnecessary SSD writes on long-running agent sessions.\n */\nexport interface RequiredSessionConfig {\n /** Write stats.json on every flush. Stats are always tracked in memory. */\n enableStats: boolean;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n\n errors: string[];\n\n warnings: string[];\n\n config?: OctocodeConfig;\n}\n\nexport interface LoadConfigResult {\n success: boolean;\n\n config?: OctocodeConfig;\n\n error?: string;\n\n path: string;\n}\n", "import type {\n RequiredGitHubConfig,\n RequiredLocalConfig,\n RequiredToolsConfig,\n RequiredNetworkConfig,\n RequiredLspConfig,\n RequiredOutputConfig,\n RequiredSessionConfig,\n ResolvedConfig,\n} from './types.js';\n\nexport const DEFAULT_GITHUB_CONFIG: RequiredGitHubConfig = {\n apiUrl: 'https://api.github.com',\n};\n\nexport const DEFAULT_LOCAL_CONFIG: RequiredLocalConfig = {\n enabled: true,\n enableClone: false,\n allowedPaths: [],\n workspaceRoot: undefined,\n};\n\nexport const DEFAULT_TOOLS_CONFIG: RequiredToolsConfig = {\n enabled: null,\n enableAdditional: null,\n disabled: null,\n};\n\nexport const DEFAULT_NETWORK_CONFIG: RequiredNetworkConfig = {\n timeout: 30000,\n maxRetries: 3,\n};\n\nexport const DEFAULT_LSP_CONFIG: RequiredLspConfig = {\n configPath: undefined,\n};\n\nexport const DEFAULT_OUTPUT_CONFIG: RequiredOutputConfig = {\n format: 'yaml',\n pagination: {\n defaultCharLength: 20000,\n },\n};\n\nexport const DEFAULT_SESSION_CONFIG: RequiredSessionConfig = {\n /** Stats persistence is opt-in: set OCTOCODE_ENABLE_STATS=1 to enable. */\n enableStats: false,\n};\n\nexport const DEFAULT_CONFIG: Omit<ResolvedConfig, 'source' | 'configPath'> = {\n version: 1,\n github: DEFAULT_GITHUB_CONFIG,\n local: DEFAULT_LOCAL_CONFIG,\n tools: DEFAULT_TOOLS_CONFIG,\n network: DEFAULT_NETWORK_CONFIG,\n lsp: DEFAULT_LSP_CONFIG,\n output: DEFAULT_OUTPUT_CONFIG,\n session: DEFAULT_SESSION_CONFIG,\n};\n\nexport const MIN_TIMEOUT = 5000;\n\nexport const MAX_TIMEOUT = 300000;\n\nexport const MIN_RETRIES = 0;\n\nexport const MAX_RETRIES = 10;\n\nexport const MIN_OUTPUT_DEFAULT_CHAR_LENGTH = 1000;\n\nexport const MAX_OUTPUT_DEFAULT_CHAR_LENGTH = 50000;\n", "/**\n * Which interface is driving the shared tool core right now.\n *\n * Some config defaults differ by surface (see `resolveLocal`):\n * - `cli`: local tools default to ENABLED; clone defaults to ENABLED.\n * - `mcp`: local tools default to ENABLED; clone defaults to DISABLED.\n *\n * `ENABLE_LOCAL=false` or `local.enabled=false` explicitly disables local tools\n * on every surface.\n *\n * Defaults to `mcp`, the primary consumer. The CLI binary calls\n * `setRuntimeSurface('cli')` at startup before any tool runs.\n *\n * State lives on `globalThis` (not a module-level variable) so a single shared\n * value is seen even when bundlers (esbuild) inline this module more than once\n * across different package subpath entry points (`/config`, `/direct`, \u2026).\n */\nexport type RuntimeSurface = 'cli' | 'mcp';\n\nconst SURFACE_KEY = '__octocodeRuntimeSurface__';\n\ntype SurfaceHolder = { [SURFACE_KEY]?: RuntimeSurface };\n\nexport function setRuntimeSurface(surface: RuntimeSurface): void {\n (globalThis as SurfaceHolder)[SURFACE_KEY] = surface;\n}\n\nexport function getRuntimeSurface(): RuntimeSurface {\n return (globalThis as SurfaceHolder)[SURFACE_KEY] ?? 'mcp';\n}\n\n/** Test helper: restore the default surface. */\nexport function _resetRuntimeSurface(): void {\n delete (globalThis as SurfaceHolder)[SURFACE_KEY];\n}\n", "import type { OctocodeConfig, ValidationResult } from './types.js';\nimport { CONFIG_SCHEMA_VERSION } from './types.js';\nimport {\n MIN_TIMEOUT,\n MAX_TIMEOUT,\n MIN_RETRIES,\n MAX_RETRIES,\n MIN_OUTPUT_DEFAULT_CHAR_LENGTH,\n MAX_OUTPUT_DEFAULT_CHAR_LENGTH,\n} from './defaults.js';\n\nfunction validateUrl(url: unknown, field: string): string | null {\n if (url === undefined || url === null) return null;\n\n if (typeof url !== 'string') {\n return `${field}: Must be a string`;\n }\n\n try {\n const parsed = new URL(url);\n if (!['http:', 'https:'].includes(parsed.protocol)) {\n return `${field}: Only http/https URLs allowed`;\n }\n return null;\n } catch {\n return `${field}: Invalid URL format`;\n }\n}\n\nfunction validateNumberRange(\n value: unknown,\n field: string,\n min: number,\n max: number\n): string | null {\n if (value === undefined || value === null) return null;\n\n if (typeof value !== 'number' || isNaN(value)) {\n return `${field}: Must be a number`;\n }\n\n if (value < min || value > max) {\n return `${field}: Must be between ${min} and ${max}`;\n }\n\n return null;\n}\n\nfunction validateBoolean(value: unknown, field: string): string | null {\n if (value === undefined || value === null) return null;\n\n if (typeof value !== 'boolean') {\n return `${field}: Must be a boolean`;\n }\n\n return null;\n}\n\nfunction validateStringArray(value: unknown, field: string): string | null {\n if (value === undefined || value === null) return null;\n\n if (!Array.isArray(value)) {\n return `${field}: Must be an array`;\n }\n\n for (let i = 0; i < value.length; i++) {\n if (typeof value[i] !== 'string') {\n return `${field}[${i}]: Must be a string`;\n }\n }\n\n return null;\n}\n\n// Rejects empty strings, relative paths, and path traversal attempts.\nfunction validateAllowedPathElements(paths: unknown[]): string[] {\n const errors: string[] = [];\n for (let i = 0; i < paths.length; i++) {\n const p = paths[i];\n if (typeof p !== 'string') continue;\n if (p.trim() === '') {\n errors.push(`local.allowedPaths[${i}]: empty or whitespace-only path`);\n } else if (!p.startsWith('/') && !p.startsWith('~')) {\n errors.push(\n `local.allowedPaths[${i}]: must be absolute path or start with ~ (got \"${p}\")`\n );\n } else if (p.includes('..')) {\n errors.push(\n `local.allowedPaths[${i}]: path traversal (..) not allowed (got \"${p}\")`\n );\n }\n }\n return errors;\n}\n\nfunction validateNullableStringArray(\n value: unknown,\n field: string\n): string | null {\n if (value === undefined) return null;\n if (value === null) return null;\n\n return validateStringArray(value, field);\n}\n\nfunction validateString(value: unknown, field: string): string | null {\n if (value === undefined || value === null) return null;\n\n if (typeof value !== 'string') {\n return `${field}: Must be a string`;\n }\n\n return null;\n}\n\nfunction validateGitHub(github: unknown, errors: string[]): void {\n if (github === undefined || github === null) return;\n\n if (typeof github !== 'object' || Array.isArray(github)) {\n errors.push('github: Must be an object');\n return;\n }\n\n const gh = github as Record<string, unknown>;\n\n const apiUrlError = validateUrl(gh.apiUrl, 'github.apiUrl');\n if (apiUrlError) errors.push(apiUrlError);\n}\n\nfunction validateLocal(local: unknown, errors: string[]): void {\n if (local === undefined || local === null) return;\n\n if (typeof local !== 'object' || Array.isArray(local)) {\n errors.push('local: Must be an object');\n return;\n }\n\n const loc = local as Record<string, unknown>;\n\n const enabledError = validateBoolean(loc.enabled, 'local.enabled');\n if (enabledError) errors.push(enabledError);\n\n const enableCloneError = validateBoolean(\n loc.enableClone,\n 'local.enableClone'\n );\n if (enableCloneError) errors.push(enableCloneError);\n\n const allowedPathsError = validateStringArray(\n loc.allowedPaths,\n 'local.allowedPaths'\n );\n if (allowedPathsError) {\n errors.push(allowedPathsError);\n } else if (Array.isArray(loc.allowedPaths)) {\n const pathErrors = validateAllowedPathElements(\n loc.allowedPaths as unknown[]\n );\n errors.push(...pathErrors);\n }\n\n if (loc.workspaceRoot !== undefined && loc.workspaceRoot !== null) {\n const workspaceRootError = validateString(\n loc.workspaceRoot,\n 'local.workspaceRoot'\n );\n if (workspaceRootError) {\n errors.push(workspaceRootError);\n } else if (\n typeof loc.workspaceRoot === 'string' &&\n !loc.workspaceRoot.startsWith('/') &&\n !loc.workspaceRoot.startsWith('~')\n ) {\n errors.push(\n 'local.workspaceRoot: must be an absolute path or start with ~ (got \"' +\n loc.workspaceRoot +\n '\")'\n );\n } else if (\n typeof loc.workspaceRoot === 'string' &&\n loc.workspaceRoot.includes('..')\n ) {\n errors.push(\n 'local.workspaceRoot: path traversal (..) not allowed (got \"' +\n loc.workspaceRoot +\n '\")'\n );\n }\n }\n}\n\nfunction validateTools(tools: unknown, errors: string[]): void {\n if (tools === undefined || tools === null) return;\n\n if (typeof tools !== 'object' || Array.isArray(tools)) {\n errors.push('tools: Must be an object');\n return;\n }\n\n const t = tools as Record<string, unknown>;\n\n const enabledError = validateNullableStringArray(t.enabled, 'tools.enabled');\n if (enabledError) errors.push(enabledError);\n\n const enableAdditionalError = validateNullableStringArray(\n t.enableAdditional,\n 'tools.enableAdditional'\n );\n if (enableAdditionalError) errors.push(enableAdditionalError);\n\n const disabledError = validateNullableStringArray(\n t.disabled,\n 'tools.disabled'\n );\n if (disabledError) errors.push(disabledError);\n}\n\nfunction validateNetwork(network: unknown, errors: string[]): void {\n if (network === undefined || network === null) return;\n\n if (typeof network !== 'object' || Array.isArray(network)) {\n errors.push('network: Must be an object');\n return;\n }\n\n const net = network as Record<string, unknown>;\n\n const timeoutError = validateNumberRange(\n net.timeout,\n 'network.timeout',\n MIN_TIMEOUT,\n MAX_TIMEOUT\n );\n if (timeoutError) errors.push(timeoutError);\n\n const retriesError = validateNumberRange(\n net.maxRetries,\n 'network.maxRetries',\n MIN_RETRIES,\n MAX_RETRIES\n );\n if (retriesError) errors.push(retriesError);\n}\n\nfunction validateLsp(lsp: unknown, errors: string[]): void {\n if (lsp === undefined || lsp === null) return;\n\n if (typeof lsp !== 'object' || Array.isArray(lsp)) {\n errors.push('lsp: Must be an object');\n return;\n }\n\n const l = lsp as Record<string, unknown>;\n\n const configPathError = validateString(l.configPath, 'lsp.configPath');\n if (configPathError) errors.push(configPathError);\n}\n\nfunction validateOutput(output: unknown, errors: string[]): void {\n if (output === undefined || output === null) return;\n\n if (typeof output !== 'object' || Array.isArray(output)) {\n errors.push('output: Must be an object');\n return;\n }\n\n const out = output as Record<string, unknown>;\n\n if (out.format !== undefined) {\n if (typeof out.format !== 'string') {\n errors.push('output.format: Must be a string');\n } else if (!['yaml', 'json'].includes(out.format)) {\n errors.push('output.format: Must be one of: yaml, json');\n }\n }\n\n if (out.pagination !== undefined && out.pagination !== null) {\n if (typeof out.pagination !== 'object' || Array.isArray(out.pagination)) {\n errors.push('output.pagination: Must be an object');\n } else {\n const pagination = out.pagination as Record<string, unknown>;\n const defaultCharLengthError = validateNumberRange(\n pagination.defaultCharLength,\n 'output.pagination.defaultCharLength',\n MIN_OUTPUT_DEFAULT_CHAR_LENGTH,\n MAX_OUTPUT_DEFAULT_CHAR_LENGTH\n );\n if (defaultCharLengthError) errors.push(defaultCharLengthError);\n }\n }\n}\n\nexport function validateConfig(config: unknown): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (typeof config !== 'object' || config === null || Array.isArray(config)) {\n return {\n valid: false,\n errors: ['Configuration must be a JSON object'],\n warnings: [],\n };\n }\n\n const cfg = config as Record<string, unknown>;\n\n if (cfg.version !== undefined) {\n if (typeof cfg.version !== 'number' || !Number.isInteger(cfg.version)) {\n errors.push('version: Must be an integer');\n } else if (cfg.version > CONFIG_SCHEMA_VERSION) {\n warnings.push(\n `version: Config version ${cfg.version} is newer than supported version ${CONFIG_SCHEMA_VERSION}`\n );\n }\n }\n\n validateGitHub(cfg.github, errors);\n validateLocal(cfg.local, errors);\n validateTools(cfg.tools, errors);\n validateNetwork(cfg.network, errors);\n validateLsp(cfg.lsp, errors);\n validateOutput(cfg.output, errors);\n\n const knownKeys = new Set([\n '$schema',\n 'version',\n 'github',\n 'local',\n 'tools',\n 'network',\n 'lsp',\n 'output',\n ]);\n\n for (const key of Object.keys(cfg)) {\n if (!knownKeys.has(key)) {\n warnings.push(`Unknown configuration key: ${key}`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n config: errors.length === 0 ? (config as OctocodeConfig) : undefined,\n };\n}\n", "import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { getOctocodeHome } from '../home.js';\nimport type { OctocodeConfig, LoadConfigResult } from './types.js';\n\n// \u2500\u2500\u2500 JSON5-compatible parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles: line comments (//) \u00B7 block comments (/* */) \u00B7 trailing commas.\n// State-machine based so // or /* inside string literals is never stripped.\n\nfunction stripJson5Features(content: string): string {\n let result = '';\n let i = 0;\n let inString = false;\n let stringChar = '';\n\n while (i < content.length) {\n const char = content[i]!;\n const nextChar = content[i + 1];\n\n if (!inString && (char === '\"' || char === \"'\")) {\n inString = true;\n stringChar = char;\n result += char;\n i++;\n continue;\n }\n\n if (inString) {\n result += char;\n if (char === '\\\\' && i + 1 < content.length) {\n result += content[i + 1]!;\n i += 2;\n continue;\n }\n if (char === stringChar) inString = false;\n i++;\n continue;\n }\n\n if (char === '/' && nextChar === '/') {\n while (i < content.length && content[i] !== '\\n') i++;\n continue;\n }\n\n if (char === '/' && nextChar === '*') {\n i += 2;\n while (i < content.length - 1) {\n if (content[i] === '*' && content[i + 1] === '/') { i += 2; break; }\n i++;\n }\n continue;\n }\n\n result += char;\n i++;\n }\n\n return result.replace(/,(\\s*[}\\]])/g, '$1');\n}\n\nfunction parseJson5(content: string): unknown {\n return JSON.parse(stripJson5Features(content));\n}\n\n// \u2500\u2500\u2500 Path helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Absolute path to the `.octocoderc` config file. */\nexport function getConfigFilePath(home: string = getOctocodeHome()): string {\n return path.join(home, '.octocoderc');\n}\n\n/** True when the `.octocoderc` file exists at the canonical location. */\nexport function configExists(home?: string): boolean {\n return existsSync(getConfigFilePath(home));\n}\n\n// \u2500\u2500\u2500 Loader \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function loadConfigSync(home?: string): LoadConfigResult {\n const filePath = getConfigFilePath(home);\n\n if (!existsSync(filePath)) {\n return { success: false, error: 'Config file does not exist', path: filePath };\n }\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n\n if (!content.trim()) {\n return { success: true, config: {}, path: filePath };\n }\n\n const parsed = parseJson5(content);\n\n // Simple structural guard (replaces zod OctocodeConfigSchema \u2014 which was\n // z.looseObject, so this is semantically equivalent with zero deps).\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return {\n success: false,\n error: 'Config file has invalid structure: must be a JSON object',\n path: filePath,\n };\n }\n\n return { success: true, config: parsed as OctocodeConfig, path: filePath };\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return { success: false, error: `Failed to parse config file: ${message}`, path: filePath };\n }\n}\n\nexport async function loadConfig(home?: string): Promise<LoadConfigResult> {\n return loadConfigSync(home);\n}\n", "import type {\n OctocodeConfig,\n RequiredGitHubConfig,\n RequiredLocalConfig,\n RequiredToolsConfig,\n RequiredNetworkConfig,\n RequiredLspConfig,\n RequiredOutputConfig,\n RequiredSessionConfig,\n} from './types.js';\nimport {\n DEFAULT_GITHUB_CONFIG,\n DEFAULT_LOCAL_CONFIG,\n DEFAULT_TOOLS_CONFIG,\n DEFAULT_NETWORK_CONFIG,\n DEFAULT_LSP_CONFIG,\n DEFAULT_OUTPUT_CONFIG,\n DEFAULT_SESSION_CONFIG,\n MIN_TIMEOUT,\n MAX_TIMEOUT,\n MIN_RETRIES,\n MAX_RETRIES,\n MIN_OUTPUT_DEFAULT_CHAR_LENGTH,\n MAX_OUTPUT_DEFAULT_CHAR_LENGTH,\n} from './defaults.js';\nimport { getRuntimeSurface } from './runtimeSurface.js';\n\nexport function parseBooleanEnv(\n value: string | undefined\n): boolean | undefined {\n if (value === undefined || value === null) return undefined;\n const trimmed = value.trim().toLowerCase();\n if (trimmed === '') return undefined;\n if (trimmed === 'true' || trimmed === '1') return true;\n if (trimmed === 'false' || trimmed === '0') return false;\n return undefined;\n}\n\nexport function parseIntEnv(value: string | undefined): number | undefined {\n if (value === undefined || value === null) return undefined;\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n const parsed = parseInt(trimmed, 10);\n if (isNaN(parsed)) return undefined;\n return parsed;\n}\n\nexport function parseStringArrayEnv(\n value: string | undefined\n): string[] | undefined {\n if (value === undefined || value === null) return undefined;\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n return trimmed\n .split(',')\n .map(s => s.trim())\n .filter(s => s.length > 0);\n}\n\nexport function resolveGitHub(\n fileConfig?: OctocodeConfig['github']\n): RequiredGitHubConfig {\n const envApiUrl = process.env.GITHUB_API_URL?.trim();\n\n return {\n apiUrl: envApiUrl || fileConfig?.apiUrl || DEFAULT_GITHUB_CONFIG.apiUrl,\n };\n}\n\nexport function resolveLocal(\n fileConfig?: OctocodeConfig['local']\n): RequiredLocalConfig {\n const isCli = getRuntimeSurface() === 'cli';\n const envEnableLocal = parseBooleanEnv(process.env.ENABLE_LOCAL);\n const envEnableClone = parseBooleanEnv(process.env.ENABLE_CLONE);\n const envAllowedPaths = parseStringArrayEnv(process.env.ALLOWED_PATHS);\n const envWorkspaceRoot = process.env.WORKSPACE_ROOT?.trim() || undefined;\n\n return {\n // Local tools are on by default. ENABLE_LOCAL=false (or local.enabled=false)\n // is an explicit opt-out for users who want to remove the local surface.\n enabled:\n envEnableLocal ?? fileConfig?.enabled ?? DEFAULT_LOCAL_CONFIG.enabled,\n // Clone: an explicit ENABLE_CLONE (env) or .octocoderc value wins for both\n // surfaces, so `false` disables everywhere. Otherwise the default is\n // surface-specific: ENABLED for the CLI, DISABLED for the MCP server.\n enableClone:\n envEnableClone ??\n fileConfig?.enableClone ??\n (isCli ? true : DEFAULT_LOCAL_CONFIG.enableClone),\n allowedPaths:\n envAllowedPaths ??\n fileConfig?.allowedPaths ??\n DEFAULT_LOCAL_CONFIG.allowedPaths,\n workspaceRoot:\n envWorkspaceRoot ??\n fileConfig?.workspaceRoot ??\n DEFAULT_LOCAL_CONFIG.workspaceRoot,\n };\n}\n\nexport function resolveTools(\n fileConfig?: OctocodeConfig['tools']\n): RequiredToolsConfig {\n const envToolsToRun = parseStringArrayEnv(process.env.TOOLS_TO_RUN);\n const envEnableTools = parseStringArrayEnv(process.env.ENABLE_TOOLS);\n const envDisableTools = parseStringArrayEnv(process.env.DISABLE_TOOLS);\n\n return {\n enabled:\n envToolsToRun ?? fileConfig?.enabled ?? DEFAULT_TOOLS_CONFIG.enabled,\n enableAdditional:\n envEnableTools ??\n fileConfig?.enableAdditional ??\n DEFAULT_TOOLS_CONFIG.enableAdditional,\n disabled:\n envDisableTools ?? fileConfig?.disabled ?? DEFAULT_TOOLS_CONFIG.disabled,\n };\n}\n\nexport function resolveNetwork(\n fileConfig?: OctocodeConfig['network']\n): RequiredNetworkConfig {\n const envTimeout = parseIntEnv(process.env.REQUEST_TIMEOUT);\n const envMaxRetries = parseIntEnv(process.env.MAX_RETRIES);\n\n let timeout =\n envTimeout ?? fileConfig?.timeout ?? DEFAULT_NETWORK_CONFIG.timeout;\n timeout = Math.max(MIN_TIMEOUT, Math.min(MAX_TIMEOUT, timeout));\n\n let maxRetries =\n envMaxRetries ??\n fileConfig?.maxRetries ??\n DEFAULT_NETWORK_CONFIG.maxRetries;\n maxRetries = Math.max(MIN_RETRIES, Math.min(MAX_RETRIES, maxRetries));\n\n return { timeout, maxRetries };\n}\n\nexport function resolveLsp(\n fileConfig?: OctocodeConfig['lsp']\n): RequiredLspConfig {\n const envConfigPath = process.env.OCTOCODE_LSP_CONFIG?.trim() || undefined;\n\n return {\n configPath:\n envConfigPath ?? fileConfig?.configPath ?? DEFAULT_LSP_CONFIG.configPath,\n };\n}\n\n/**\n * Resolve session / stats-persistence config from env only.\n * OCTOCODE_ENABLE_STATS=1|true turns on stats.json writes; default is off.\n */\nexport function resolveSession(): RequiredSessionConfig {\n const envEnableStats = parseBooleanEnv(process.env.OCTOCODE_ENABLE_STATS);\n return {\n enableStats: envEnableStats ?? DEFAULT_SESSION_CONFIG.enableStats,\n };\n}\n\nconst VALID_OUTPUT_FORMATS = new Set(['yaml', 'json']);\n\nexport function resolveOutput(\n fileConfig?: OctocodeConfig['output']\n): RequiredOutputConfig {\n const envFormat = process.env.OCTOCODE_OUTPUT_FORMAT?.trim().toLowerCase();\n const envDefaultCharLength = parseIntEnv(\n process.env.OCTOCODE_OUTPUT_DEFAULT_CHAR_LENGTH\n );\n const resolved =\n envFormat || fileConfig?.format || DEFAULT_OUTPUT_CONFIG.format;\n const configuredDefaultCharLength =\n envDefaultCharLength ??\n fileConfig?.pagination?.defaultCharLength ??\n DEFAULT_OUTPUT_CONFIG.pagination.defaultCharLength;\n const clampedDefaultCharLength = Math.max(\n MIN_OUTPUT_DEFAULT_CHAR_LENGTH,\n Math.min(MAX_OUTPUT_DEFAULT_CHAR_LENGTH, configuredDefaultCharLength)\n );\n\n return {\n format: VALID_OUTPUT_FORMATS.has(resolved)\n ? (resolved as 'yaml' | 'json')\n : DEFAULT_OUTPUT_CONFIG.format,\n pagination: {\n defaultCharLength: clampedDefaultCharLength,\n },\n };\n}\n", "import type { OctocodeConfig, ResolvedConfig } from './types.js';\nimport { DEFAULT_CONFIG } from './defaults.js';\nimport { loadConfigSync } from './loader.js';\nimport { validateConfig } from './validator.js';\nimport {\n resolveGitHub,\n resolveLocal,\n resolveTools,\n resolveNetwork,\n resolveLsp,\n resolveOutput,\n resolveSession,\n} from './resolverSections.js';\n\nfunction buildResolvedConfig(\n fileConfig: OctocodeConfig | undefined,\n configPath?: string\n): ResolvedConfig {\n const hasFile = fileConfig !== undefined;\n const hasEnvOverrides =\n process.env.GITHUB_API_URL !== undefined ||\n process.env.ENABLE_LOCAL !== undefined ||\n process.env.ENABLE_CLONE !== undefined ||\n process.env.ALLOWED_PATHS !== undefined ||\n process.env.WORKSPACE_ROOT !== undefined ||\n process.env.TOOLS_TO_RUN !== undefined ||\n process.env.ENABLE_TOOLS !== undefined ||\n process.env.DISABLE_TOOLS !== undefined ||\n process.env.REQUEST_TIMEOUT !== undefined ||\n process.env.MAX_RETRIES !== undefined ||\n process.env.OCTOCODE_LSP_CONFIG !== undefined ||\n process.env.OCTOCODE_OUTPUT_FORMAT !== undefined ||\n process.env.OCTOCODE_OUTPUT_DEFAULT_CHAR_LENGTH !== undefined ||\n process.env.OCTOCODE_ENABLE_STATS !== undefined;\n\n let source: ResolvedConfig['source'];\n if (hasFile && hasEnvOverrides) {\n source = 'mixed';\n } else if (hasFile) {\n source = 'file';\n } else {\n source = 'defaults';\n }\n\n return {\n version: fileConfig?.version ?? DEFAULT_CONFIG.version,\n github: resolveGitHub(fileConfig?.github),\n local: resolveLocal(fileConfig?.local),\n tools: resolveTools(fileConfig?.tools),\n network: resolveNetwork(fileConfig?.network),\n lsp: resolveLsp(fileConfig?.lsp),\n output: resolveOutput(fileConfig?.output),\n session: resolveSession(),\n source,\n configPath: hasFile ? configPath : undefined,\n };\n}\n\nexport function resolveConfigSync(): ResolvedConfig {\n const loadResult = loadConfigSync();\n\n if (loadResult.success && loadResult.config) {\n const validation = validateConfig(loadResult.config);\n\n if (!validation.valid) {\n return buildResolvedConfig(undefined);\n }\n\n return buildResolvedConfig(loadResult.config, loadResult.path);\n }\n\n return buildResolvedConfig(undefined);\n}\n\nexport async function resolveConfig(): Promise<ResolvedConfig> {\n return resolveConfigSync();\n}\n\nlet cachedConfig: ResolvedConfig | null = null;\n\nlet cacheTimestamp: number = 0;\n\nconst CACHE_TTL_MS = 60000;\n\nexport function getConfigSync(): ResolvedConfig {\n const now = Date.now();\n\n if (cachedConfig && now - cacheTimestamp < CACHE_TTL_MS) {\n return cachedConfig;\n }\n\n cachedConfig = resolveConfigSync();\n cacheTimestamp = now;\n\n return cachedConfig;\n}\n\nexport async function getConfig(): Promise<ResolvedConfig> {\n return getConfigSync();\n}\n\nexport async function reloadConfig(): Promise<ResolvedConfig> {\n invalidateConfigCache();\n return getConfig();\n}\n\nexport function invalidateConfigCache(): void {\n cachedConfig = null;\n cacheTimestamp = 0;\n}\n\nexport function _resetConfigCache(): void {\n cachedConfig = null;\n cacheTimestamp = 0;\n}\n\nexport function _getCacheState(): { cached: boolean; timestamp: number } {\n return {\n cached: cachedConfig !== null,\n timestamp: cacheTimestamp,\n };\n}\n", "// Thin re-export \u2014 all resolution logic lives in resolverCache.ts.\nexport {\n resolveConfigSync,\n resolveConfig,\n getConfig,\n getConfigSync,\n reloadConfig,\n invalidateConfigCache,\n _resetConfigCache,\n _getCacheState,\n} from './resolverCache.js';\n\nimport { getConfigSync } from './resolverCache.js';\n\nexport function getConfigValue<T = unknown>(keyPath: string): T | undefined {\n const config = getConfigSync();\n const parts = keyPath.split('.');\n let current: unknown = config;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n return current as T;\n}\n", "/**\n * Token resolution from environment variables.\n *\n * Priority order (highest \u2192 lowest):\n * OCTOCODE_TOKEN \u2192 GH_TOKEN \u2192 GITHUB_TOKEN \u2192 GITHUB_PERSONAL_ACCESS_TOKEN\n *\n * All four vars are in PROTECTED_KEYS and must never come from .env files.\n * They are read directly from process.env (set by the shell or MCP client).\n */\nimport type { TokenSource } from './types.js';\n\nexport const ENV_TOKEN_VARS = [\n 'OCTOCODE_TOKEN',\n 'GH_TOKEN',\n 'GITHUB_TOKEN',\n 'GITHUB_PERSONAL_ACCESS_TOKEN',\n] as const;\n\nexport type EnvTokenVar = (typeof ENV_TOKEN_VARS)[number];\n\n/** Return the first non-empty token value found in env, or null. */\nexport function getTokenFromEnv(env: NodeJS.ProcessEnv = process.env): string | null {\n for (const envVar of ENV_TOKEN_VARS) {\n const token = env[envVar];\n if (token && token.trim()) return token.trim();\n }\n return null;\n}\n\n/** Return the source label for the first non-empty token var, or null. */\nexport function getEnvTokenSource(env: NodeJS.ProcessEnv = process.env): TokenSource {\n for (const envVar of ENV_TOKEN_VARS) {\n const token = env[envVar];\n if (token && token.trim()) return `env:${envVar}` as TokenSource;\n }\n return null;\n}\n\n/** True when at least one token env var is set and non-empty. */\nexport function hasEnvToken(env: NodeJS.ProcessEnv = process.env): boolean {\n return getTokenFromEnv(env) !== null;\n}\n\n/** Return { token, source } for the first matching var, or null. */\nexport function resolveEnvToken(\n env: NodeJS.ProcessEnv = process.env,\n): { token: string; source: Exclude<TokenSource, null | 'octocode-storage' | 'gh-cli'> } | null {\n for (const envVar of ENV_TOKEN_VARS) {\n const token = env[envVar];\n if (token?.trim()) {\n return {\n token: token.trim(),\n source: `env:${envVar}` as Exclude<TokenSource, null | 'octocode-storage' | 'gh-cli'>,\n };\n }\n }\n return null;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["path", "path", "path", "path"]
7
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Token resolution from environment variables.
3
+ *
4
+ * Priority order (highest → lowest):
5
+ * OCTOCODE_TOKEN → GH_TOKEN → GITHUB_TOKEN → GITHUB_PERSONAL_ACCESS_TOKEN
6
+ *
7
+ * All four vars are in PROTECTED_KEYS and must never come from .env files.
8
+ * They are read directly from process.env (set by the shell or MCP client).
9
+ */
10
+ import type { TokenSource } from './types.js';
11
+ export declare const ENV_TOKEN_VARS: readonly ["OCTOCODE_TOKEN", "GH_TOKEN", "GITHUB_TOKEN", "GITHUB_PERSONAL_ACCESS_TOKEN"];
12
+ export type EnvTokenVar = (typeof ENV_TOKEN_VARS)[number];
13
+ /** Return the first non-empty token value found in env, or null. */
14
+ export declare function getTokenFromEnv(env?: NodeJS.ProcessEnv): string | null;
15
+ /** Return the source label for the first non-empty token var, or null. */
16
+ export declare function getEnvTokenSource(env?: NodeJS.ProcessEnv): TokenSource;
17
+ /** True when at least one token env var is set and non-empty. */
18
+ export declare function hasEnvToken(env?: NodeJS.ProcessEnv): boolean;
19
+ /** Return { token, source } for the first matching var, or null. */
20
+ export declare function resolveEnvToken(env?: NodeJS.ProcessEnv): {
21
+ token: string;
22
+ source: Exclude<TokenSource, null | 'octocode-storage' | 'gh-cli'>;
23
+ } | null;
24
+ //# sourceMappingURL=envTokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envTokens.d.ts","sourceRoot":"","sources":["../../src/tokens/envTokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,cAAc,yFAKjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,IAAI,CAMnF;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CAMnF;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEzE;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,GAAG,kBAAkB,GAAG,QAAQ,CAAC,CAAA;CAAE,GAAG,IAAI,CAW9F"}
@@ -0,0 +1,3 @@
1
+ export type { TokenSource } from './types.js';
2
+ export { ENV_TOKEN_VARS, type EnvTokenVar, getTokenFromEnv, getEnvTokenSource, hasEnvToken, resolveEnvToken, } from './envTokens.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,eAAe,GAChB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * All possible sources from which a GitHub token can originate.
3
+ * `null` means no token was found.
4
+ */
5
+ export type TokenSource = 'env:OCTOCODE_TOKEN' | 'env:GH_TOKEN' | 'env:GITHUB_TOKEN' | 'env:GITHUB_PERSONAL_ACCESS_TOKEN' | 'octocode-storage' | 'gh-cli' | null;
6
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tokens/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB,oBAAoB,GACpB,cAAc,GACd,kBAAkB,GAClB,kCAAkC,GAClC,kBAAkB,GAClB,QAAQ,GACR,IAAI,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@octocodeai/config",
3
+ "version": "17.0.0",
4
+ "description": "Octocode unified env + config loader — zero deps, shared by MCP, CLI, extension, agent, and standalone skills.",
5
+ "keywords": [
6
+ "octocode",
7
+ "config",
8
+ "env",
9
+ "dotenv"
10
+ ],
11
+ "author": "Guy Bary <bgauryy@octocodeai.com>",
12
+ "homepage": "https://octocode.ai",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/bgauryy/octocode.git",
16
+ "directory": "packages/octocode-config"
17
+ },
18
+ "bugs": "https://github.com/bgauryy/octocode/issues",
19
+ "license": "MIT",
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js",
27
+ "default": "./dist/index.js"
28
+ }
29
+ },
30
+ "bin": {
31
+ "octocode-config": "./dist/cli.js"
32
+ },
33
+ "files": [
34
+ "dist/**",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "engines": {
39
+ "node": ">=20.0.0"
40
+ },
41
+ "scripts": {
42
+ "build": "node build.mjs",
43
+ "clean": "rm -rf dist/",
44
+ "lint": "tsc --noEmit -p tsconfig.json",
45
+ "test": "node ../../node_modules/vitest/vitest.mjs run --coverage",
46
+ "test:quiet": "node ../../node_modules/vitest/vitest.mjs run --reporter=dot --silent",
47
+ "typecheck": "tsc --noEmit -p tsconfig.json",
48
+ "verify": "yarn lint && yarn test && yarn build"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^25.9.3",
52
+ "@vitest/coverage-v8": "^4.1.9",
53
+ "esbuild": "^0.28.1",
54
+ "typescript": "^5.9.3",
55
+ "vitest": "^4.1.9"
56
+ },
57
+ "publishConfig": {
58
+ "access": "public"
59
+ }
60
+ }