@eminent337/aery 0.1.113 → 0.1.115

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * One-time migrations that run on startup.
3
3
  */
4
- export declare const CORE_EXTENSION_PATHS: readonly ["damage-control", "model-failover", "web-search", "web-fetch", "commands", "hooks", "circuit-breaker", "auto-router", "memory-include", "aery-header", "aery-footer", "multi-agent", "agent-chain", "agent-teams", "help", "default-agents", "aery-doctor", "aery-team", "subagent/index", "marketplace", "session-auto-name", "upstream-notify", "init-prompt"];
4
+ export declare const CORE_EXTENSION_PATHS: readonly ["damage-control", "model-failover", "web-search", "web-fetch", "commands", "hooks", "circuit-breaker", "auto-router", "memory-include", "aery-header", "aery-footer", "multi-agent", "agent-chain", "agent-teams", "help", "default-agents", "aery-doctor", "aery-team", "subagent/index", "marketplace", "session-auto-name", "upstream-notify", "init-prompt", "graphify"];
5
5
  export declare const DEPRECATED_CORE_EXTENSION_PATHS: readonly ["provider-profiles"];
6
6
  export interface CoreExtensionDiagnostic {
7
7
  repoExists: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,eAAO,MAAM,oBAAoB,4WAwBvB,CAAC;AAEX,eAAO,MAAM,+BAA+B,gCAAiC,CAAC;AAE9E,MAAM,WAAW,uBAAuB;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sBAAsB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACvE,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACzE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpE;AAkBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAWtG;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAmClG;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAoDhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CA+CnD;AA+ID;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/E;AAoBD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,yBAAyB,CAkDhE;AAED,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,GAAG,SAAS,CAkBzG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC9B,CAQA","sourcesContent":["/**\n * One-time migrations that run on startup.\n */\n\nimport chalk from \"chalk\";\nimport { execSync, spawnSync } from \"child_process\";\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir, getBinDir } from \"./config.js\";\nimport { migrateKeybindingsConfig } from \"./core/keybindings.js\";\n\nconst MIGRATION_GUIDE_URL =\n\t\"https://github.com/eminent337/aery/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration\";\nconst EXTENSIONS_DOC_URL = \"https://github.com/eminent337/aery/blob/main/packages/coding-agent/docs/extensions.md\";\nexport const CORE_EXTENSION_PATHS = [\n\t\"damage-control\",\n\t\"model-failover\",\n\t\"web-search\",\n\t\"web-fetch\",\n\t\"commands\",\n\t\"hooks\",\n\t\"circuit-breaker\",\n\t\"auto-router\",\n\t\"memory-include\",\n\t\"aery-header\",\n\t\"aery-footer\",\n\t\"multi-agent\",\n\t\"agent-chain\",\n\t\"agent-teams\",\n\t\"help\",\n\t\"default-agents\",\n\t\"aery-doctor\",\n\t\"aery-team\",\n\t\"subagent/index\",\n\t\"marketplace\",\n\t\"session-auto-name\",\n\t\"upstream-notify\",\n\t\"init-prompt\",\n] as const;\n\nexport const DEPRECATED_CORE_EXTENSION_PATHS = [\"provider-profiles\"] as const;\n\nexport interface CoreExtensionDiagnostic {\n\trepoExists: boolean;\n\tmissingFiles: string[];\n\tmissingSettingsEntries: string[];\n}\n\nexport interface CoreExtensionWireResult extends CoreExtensionDiagnostic {\n\tadded: string[];\n}\n\nexport interface CoreExtensionEnsureResult extends CoreExtensionWireResult {\n\tstatus: \"installed\" | \"offline\" | \"ok\";\n\trepoPath: string;\n\tsettingsPath: string;\n\terror?: string;\n}\n\nexport function getCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction getDeprecatedCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn DEPRECATED_CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction readSettingsExtensions(settingsPath: string): string[] {\n\tif (!existsSync(settingsPath)) return [];\n\ttry {\n\t\tconst settings = JSON.parse(readFileSync(settingsPath, \"utf-8\")) as { extensions?: unknown };\n\t\treturn Array.isArray(settings.extensions)\n\t\t\t? settings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t\t: [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function diagnoseCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionDiagnostic {\n\tconst expectedPaths = getCoreExtensionFilePaths(repoPath);\n\tconst repoExists = existsSync(repoPath);\n\tconst settingsExtensions = new Set(readSettingsExtensions(settingsPath));\n\treturn {\n\t\trepoExists,\n\t\tmissingFiles: repoExists ? expectedPaths.filter((extensionPath) => !existsSync(extensionPath)) : expectedPaths,\n\t\tmissingSettingsEntries: expectedPaths.filter(\n\t\t\t(extensionPath) => existsSync(extensionPath) && !settingsExtensions.has(extensionPath),\n\t\t),\n\t};\n}\n\nexport function wireCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionWireResult {\n\tconst diagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\tif (!diagnostic.repoExists) return { ...diagnostic, added: [] };\n\n\tconst parsedSettings = (existsSync(settingsPath) ? JSON.parse(readFileSync(settingsPath, \"utf-8\")) : {}) as {\n\t\textensions?: unknown;\n\t};\n\tconst existingExtensions = Array.isArray(parsedSettings.extensions)\n\t\t? parsedSettings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\tconst deprecatedExtensions = new Set(getDeprecatedCoreExtensionFilePaths(repoPath));\n\tconst filteredExistingExtensions = existingExtensions.filter(\n\t\t(extensionPath) => !deprecatedExtensions.has(extensionPath),\n\t);\n\tconst settings: Record<string, unknown> & { extensions?: string[] } = {\n\t\t...parsedSettings,\n\t\textensions: filteredExistingExtensions,\n\t};\n\tconst existing = new Set<string>(filteredExistingExtensions);\n\tconst added: string[] = [];\n\tfor (const extensionPath of getCoreExtensionFilePaths(repoPath)) {\n\t\tif (!existsSync(extensionPath) || existing.has(extensionPath)) continue;\n\t\tsettings.extensions = settings.extensions ?? [];\n\t\tsettings.extensions.push(extensionPath);\n\t\texisting.add(extensionPath);\n\t\tadded.push(extensionPath);\n\t}\n\n\tif (added.length > 0 || filteredExistingExtensions.length !== existingExtensions.length) {\n\t\tmkdirSync(dirname(settingsPath), { recursive: true });\n\t\twriteFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\\n`);\n\t}\n\n\tconst nextDiagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\treturn { ...nextDiagnostic, added };\n}\n\n/**\n * Migrate legacy oauth.json and settings.json apiKeys to auth.json.\n *\n * @returns Array of provider names that were migrated\n */\nexport function migrateAuthToAuthJson(): string[] {\n\tconst agentDir = getAgentDir();\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Skip if auth.json already exists\n\tif (existsSync(authPath)) return [];\n\n\tconst migrated: Record<string, unknown> = {};\n\tconst providers: string[] = [];\n\n\t// Migrate oauth.json\n\tif (existsSync(oauthPath)) {\n\t\ttry {\n\t\t\tconst oauth = JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\tfor (const [provider, cred] of Object.entries(oauth)) {\n\t\t\t\tmigrated[provider] = { type: \"oauth\", ...(cred as object) };\n\t\t\t\tproviders.push(provider);\n\t\t\t}\n\t\t\trenameSync(oauthPath, `${oauthPath}.migrated`);\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\t// Migrate settings.json apiKeys\n\tif (existsSync(settingsPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(settingsPath, \"utf-8\");\n\t\t\tconst settings = JSON.parse(content);\n\t\t\tif (settings.apiKeys && typeof settings.apiKeys === \"object\") {\n\t\t\t\tfor (const [provider, key] of Object.entries(settings.apiKeys)) {\n\t\t\t\t\tif (!migrated[provider] && typeof key === \"string\") {\n\t\t\t\t\t\tmigrated[provider] = { type: \"api_key\", key };\n\t\t\t\t\t\tproviders.push(provider);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdelete settings.apiKeys;\n\t\t\t\twriteFileSync(settingsPath, JSON.stringify(settings, null, 2));\n\t\t\t}\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\tif (Object.keys(migrated).length > 0) {\n\t\tmkdirSync(dirname(authPath), { recursive: true });\n\t\twriteFileSync(authPath, JSON.stringify(migrated, null, 2), { mode: 0o600 });\n\t}\n\n\treturn providers;\n}\n\n/**\n * Migrate sessions from ~/.aery/agent/*.jsonl to proper session directories.\n *\n * Bug in v0.30.0: Sessions were saved to ~/.aery/agent/ instead of\n * ~/.aery/agent/sessions/<encoded-cwd>/. This migration moves them\n * to the correct location based on the cwd in their session header.\n *\n * See: https://github.com/eminent337/aery/issues/320\n */\nexport function migrateSessionsFromAgentRoot(): void {\n\tconst agentDir = getAgentDir();\n\n\t// Find all .jsonl files directly in agentDir (not in subdirectories)\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(agentDir)\n\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f) => join(agentDir, f));\n\t} catch {\n\t\treturn;\n\t}\n\n\tif (files.length === 0) return;\n\n\tfor (const file of files) {\n\t\ttry {\n\t\t\t// Read first line to get session header\n\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\tconst firstLine = content.split(\"\\n\")[0];\n\t\t\tif (!firstLine?.trim()) continue;\n\n\t\t\tconst header = JSON.parse(firstLine);\n\t\t\tif (header.type !== \"session\" || !header.cwd) continue;\n\n\t\t\tconst cwd: string = header.cwd;\n\n\t\t\t// Compute the correct session directory (same encoding as session-manager.ts)\n\t\t\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\t\t\tconst correctDir = join(agentDir, \"sessions\", safePath);\n\n\t\t\t// Create directory if needed\n\t\t\tif (!existsSync(correctDir)) {\n\t\t\t\tmkdirSync(correctDir, { recursive: true });\n\t\t\t}\n\n\t\t\t// Move the file\n\t\t\tconst fileName = file.split(\"/\").pop() || file.split(\"\\\\\").pop();\n\t\t\tconst newPath = join(correctDir, fileName!);\n\n\t\t\tif (existsSync(newPath)) continue; // Skip if target exists\n\n\t\t\trenameSync(file, newPath);\n\t\t} catch {\n\t\t\t// Skip files that can't be migrated\n\t\t}\n\t}\n}\n\n/**\n * Migrate commands/ to prompts/ if needed.\n * Works for both regular directories and symlinks.\n */\nfunction migrateCommandsToPrompts(baseDir: string, label: string): boolean {\n\tconst commandsDir = join(baseDir, \"commands\");\n\tconst promptsDir = join(baseDir, \"prompts\");\n\n\tif (existsSync(commandsDir) && !existsSync(promptsDir)) {\n\t\ttry {\n\t\t\trenameSync(commandsDir, promptsDir);\n\t\t\tconsole.log(chalk.green(`Migrated ${label} commands/ → prompts/`));\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tconsole.log(\n\t\t\t\tchalk.yellow(\n\t\t\t\t\t`Warning: Could not migrate ${label} commands/ to prompts/: ${err instanceof Error ? err.message : err}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction migrateKeybindingsConfigFile(): void {\n\tconst configPath = join(getAgentDir(), \"keybindings.json\");\n\tif (!existsSync(configPath)) return;\n\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(configPath, \"utf-8\")) as unknown;\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\t\treturn;\n\t\t}\n\t\tconst { config, migrated } = migrateKeybindingsConfig(parsed as Record<string, unknown>);\n\t\tif (!migrated) return;\n\t\twriteFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\t} catch {\n\t\t// Ignore malformed files during migration\n\t}\n}\n\n/**\n * Move fd/rg binaries from tools/ to bin/ if they exist.\n */\nfunction migrateToolsToBin(): void {\n\tconst agentDir = getAgentDir();\n\tconst toolsDir = join(agentDir, \"tools\");\n\tconst binDir = getBinDir();\n\n\tif (!existsSync(toolsDir)) return;\n\n\tconst binaries = [\"fd\", \"rg\", \"fd.exe\", \"rg.exe\"];\n\tlet movedAny = false;\n\n\tfor (const bin of binaries) {\n\t\tconst oldPath = join(toolsDir, bin);\n\t\tconst newPath = join(binDir, bin);\n\n\t\tif (existsSync(oldPath)) {\n\t\t\tif (!existsSync(binDir)) {\n\t\t\t\tmkdirSync(binDir, { recursive: true });\n\t\t\t}\n\t\t\tif (!existsSync(newPath)) {\n\t\t\t\ttry {\n\t\t\t\t\trenameSync(oldPath, newPath);\n\t\t\t\t\tmovedAny = true;\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Target exists, just delete the old one\n\t\t\t\ttry {\n\t\t\t\t\trmSync?.(oldPath, { force: true });\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (movedAny) {\n\t\tconsole.log(chalk.green(`Migrated managed binaries tools/ → bin/`));\n\t}\n}\n\n/**\n * Check for deprecated hooks/ and tools/ directories.\n * Note: tools/ may contain fd/rg binaries extracted by aery, so only warn if it has other files.\n */\nfunction checkDeprecatedExtensionDirs(baseDir: string, label: string): string[] {\n\tconst hooksDir = join(baseDir, \"hooks\");\n\tconst toolsDir = join(baseDir, \"tools\");\n\tconst warnings: string[] = [];\n\n\tif (existsSync(hooksDir)) {\n\t\twarnings.push(`${label} hooks/ directory found. Hooks have been renamed to extensions.`);\n\t}\n\n\tif (existsSync(toolsDir)) {\n\t\t// Check if tools/ contains anything other than fd/rg (which are auto-extracted binaries)\n\t\ttry {\n\t\t\tconst entries = readdirSync(toolsDir);\n\t\t\tconst customTools = entries.filter((e) => {\n\t\t\t\tconst lower = e.toLowerCase();\n\t\t\t\treturn (\n\t\t\t\t\tlower !== \"fd\" && lower !== \"rg\" && lower !== \"fd.exe\" && lower !== \"rg.exe\" && !e.startsWith(\".\") // Ignore .DS_Store and other hidden files\n\t\t\t\t);\n\t\t\t});\n\t\t\tif (customTools.length > 0) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`${label} tools/ directory contains custom tools. Custom tools have been merged into extensions.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors\n\t\t}\n\t}\n\n\treturn warnings;\n}\n\n/**\n * Run extension system migrations (commands→prompts) and collect warnings about deprecated directories.\n */\nfunction migrateExtensionSystem(cwd: string): string[] {\n\tconst agentDir = getAgentDir();\n\tconst projectDir = join(cwd, CONFIG_DIR_NAME);\n\n\t// Migrate commands/ to prompts/\n\tmigrateCommandsToPrompts(agentDir, \"Global\");\n\tmigrateCommandsToPrompts(projectDir, \"Project\");\n\n\t// Check for deprecated directories\n\tconst warnings = [\n\t\t...checkDeprecatedExtensionDirs(agentDir, \"Global\"),\n\t\t...checkDeprecatedExtensionDirs(projectDir, \"Project\"),\n\t];\n\n\treturn warnings;\n}\n\n/**\n * Print deprecation warnings and wait for keypress.\n */\nexport async function showDeprecationWarnings(warnings: string[]): Promise<void> {\n\tif (warnings.length === 0) return;\n\n\tfor (const warning of warnings) {\n\t\tconsole.log(chalk.yellow(`Warning: ${warning}`));\n\t}\n\tconsole.log(chalk.yellow(`\\nMove your extensions to the extensions/ directory.`));\n\tconsole.log(chalk.yellow(`Migration guide: ${MIGRATION_GUIDE_URL}`));\n\tconsole.log(chalk.yellow(`Documentation: ${EXTENSIONS_DOC_URL}`));\n\tconsole.log(chalk.dim(`\\nPress any key to continue...`));\n\n\tawait new Promise<void>((resolve) => {\n\t\tprocess.stdin.setRawMode?.(true);\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.once(\"data\", () => {\n\t\t\tprocess.stdin.setRawMode?.(false);\n\t\t\tprocess.stdin.pause();\n\t\t\tresolve();\n\t\t});\n\t});\n\tconsole.log();\n}\n\n/**\n * Wire any missing core extensions for existing users who already have aery-extensions installed.\n * Runs on every startup but is idempotent — only adds extensions not already in settings.\n */\nfunction wireMissingCoreExtensions(): void {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\tif (!existsSync(repoPath)) return;\n\n\ttry {\n\t\twireCoreExtensions(repoPath, settingsPath);\n\t} catch {\n\t\t// Silent fail\n\t}\n}\n\n/**\n * Ensure aery-extensions is cloned and core extensions are wired.\n * Called at startup — installs aery-extensions if missing, then wires core extensions.\n * Safe to call multiple times (idempotent).\n *\n * @returns core extension bootstrap status and diagnostics\n */\nexport function ensureCoreExtensions(): CoreExtensionEnsureResult {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Clone if missing\n\tif (!existsSync(repoPath)) {\n\t\ttry {\n\t\t\tmkdirSync(join(agentDir, \"git\", \"github.com\", \"eminent337\"), { recursive: true });\n\t\t\texecSync(`git clone --depth=1 https://github.com/eminent337/aery-extensions.git \"${repoPath}\"`, {\n\t\t\t\tstdio: \"pipe\",\n\t\t\t\ttimeout: 30000,\n\t\t\t});\n\t\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"installed\", repoPath, settingsPath };\n\t\t} catch (error) {\n\t\t\t// Network unavailable or git missing\n\t\t\treturn {\n\t\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\t\tadded: [],\n\t\t\t\tstatus: \"offline\",\n\t\t\t\trepoPath,\n\t\t\t\tsettingsPath,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t// Repo exists — pull updates in the background (fire and forget)\n\ttry {\n\t\tspawnSync(\"git\", [\"-C\", repoPath, \"pull\", \"--ff-only\", \"--quiet\"], {\n\t\t\ttimeout: 10000,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\t} catch {\n\t\t// Ignore pull failures — offline or git missing\n\t}\n\n\t// Wire any newly added core extensions\n\ttry {\n\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"ok\", repoPath, settingsPath };\n\t} catch (error) {\n\t\treturn {\n\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\tadded: [],\n\t\t\tstatus: \"ok\",\n\t\t\trepoPath,\n\t\t\tsettingsPath,\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function formatCoreExtensionAttentionMessage(result: CoreExtensionEnsureResult): string | undefined {\n\tif (result.status === \"offline\") {\n\t\treturn \"Extensions not installed (no network). Run aery again with network access, or run: aery update --extensions\";\n\t}\n\n\tif (result.error) {\n\t\treturn `Core extensions need attention: ${result.error}. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingFiles.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingFiles.length} core extension file(s) are missing. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingSettingsEntries.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingSettingsEntries.length} core extension setting(s) are missing. Run: aery update --extensions`;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Run all migrations. Called once on startup.\n *\n * @returns Object with migration results and deprecation warnings\n */\nexport function runMigrations(cwd: string): {\n\tmigratedAuthProviders: string[];\n\tdeprecationWarnings: string[];\n} {\n\tconst migratedAuthProviders = migrateAuthToAuthJson();\n\tmigrateSessionsFromAgentRoot();\n\tmigrateToolsToBin();\n\tmigrateKeybindingsConfigFile();\n\twireMissingCoreExtensions();\n\tconst deprecationWarnings = migrateExtensionSystem(cwd);\n\treturn { migratedAuthProviders, deprecationWarnings };\n}\n"]}
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,eAAO,MAAM,oBAAoB,wXAyBvB,CAAC;AAEX,eAAO,MAAM,+BAA+B,gCAAiC,CAAC;AAE9E,MAAM,WAAW,uBAAuB;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sBAAsB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACvE,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACzE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpE;AAkBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAWtG;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAmClG;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAoDhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CA+CnD;AA+ID;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/E;AAoBD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,yBAAyB,CAkDhE;AAED,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,GAAG,SAAS,CAkBzG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC9B,CAQA","sourcesContent":["/**\n * One-time migrations that run on startup.\n */\n\nimport chalk from \"chalk\";\nimport { execSync, spawnSync } from \"child_process\";\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir, getBinDir } from \"./config.js\";\nimport { migrateKeybindingsConfig } from \"./core/keybindings.js\";\n\nconst MIGRATION_GUIDE_URL =\n\t\"https://github.com/eminent337/aery/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration\";\nconst EXTENSIONS_DOC_URL = \"https://github.com/eminent337/aery/blob/main/packages/coding-agent/docs/extensions.md\";\nexport const CORE_EXTENSION_PATHS = [\n\t\"damage-control\",\n\t\"model-failover\",\n\t\"web-search\",\n\t\"web-fetch\",\n\t\"commands\",\n\t\"hooks\",\n\t\"circuit-breaker\",\n\t\"auto-router\",\n\t\"memory-include\",\n\t\"aery-header\",\n\t\"aery-footer\",\n\t\"multi-agent\",\n\t\"agent-chain\",\n\t\"agent-teams\",\n\t\"help\",\n\t\"default-agents\",\n\t\"aery-doctor\",\n\t\"aery-team\",\n\t\"subagent/index\",\n\t\"marketplace\",\n\t\"session-auto-name\",\n\t\"upstream-notify\",\n\t\"init-prompt\",\n\t\"graphify\",\n] as const;\n\nexport const DEPRECATED_CORE_EXTENSION_PATHS = [\"provider-profiles\"] as const;\n\nexport interface CoreExtensionDiagnostic {\n\trepoExists: boolean;\n\tmissingFiles: string[];\n\tmissingSettingsEntries: string[];\n}\n\nexport interface CoreExtensionWireResult extends CoreExtensionDiagnostic {\n\tadded: string[];\n}\n\nexport interface CoreExtensionEnsureResult extends CoreExtensionWireResult {\n\tstatus: \"installed\" | \"offline\" | \"ok\";\n\trepoPath: string;\n\tsettingsPath: string;\n\terror?: string;\n}\n\nexport function getCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction getDeprecatedCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn DEPRECATED_CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction readSettingsExtensions(settingsPath: string): string[] {\n\tif (!existsSync(settingsPath)) return [];\n\ttry {\n\t\tconst settings = JSON.parse(readFileSync(settingsPath, \"utf-8\")) as { extensions?: unknown };\n\t\treturn Array.isArray(settings.extensions)\n\t\t\t? settings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t\t: [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function diagnoseCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionDiagnostic {\n\tconst expectedPaths = getCoreExtensionFilePaths(repoPath);\n\tconst repoExists = existsSync(repoPath);\n\tconst settingsExtensions = new Set(readSettingsExtensions(settingsPath));\n\treturn {\n\t\trepoExists,\n\t\tmissingFiles: repoExists ? expectedPaths.filter((extensionPath) => !existsSync(extensionPath)) : expectedPaths,\n\t\tmissingSettingsEntries: expectedPaths.filter(\n\t\t\t(extensionPath) => existsSync(extensionPath) && !settingsExtensions.has(extensionPath),\n\t\t),\n\t};\n}\n\nexport function wireCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionWireResult {\n\tconst diagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\tif (!diagnostic.repoExists) return { ...diagnostic, added: [] };\n\n\tconst parsedSettings = (existsSync(settingsPath) ? JSON.parse(readFileSync(settingsPath, \"utf-8\")) : {}) as {\n\t\textensions?: unknown;\n\t};\n\tconst existingExtensions = Array.isArray(parsedSettings.extensions)\n\t\t? parsedSettings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\tconst deprecatedExtensions = new Set(getDeprecatedCoreExtensionFilePaths(repoPath));\n\tconst filteredExistingExtensions = existingExtensions.filter(\n\t\t(extensionPath) => !deprecatedExtensions.has(extensionPath),\n\t);\n\tconst settings: Record<string, unknown> & { extensions?: string[] } = {\n\t\t...parsedSettings,\n\t\textensions: filteredExistingExtensions,\n\t};\n\tconst existing = new Set<string>(filteredExistingExtensions);\n\tconst added: string[] = [];\n\tfor (const extensionPath of getCoreExtensionFilePaths(repoPath)) {\n\t\tif (!existsSync(extensionPath) || existing.has(extensionPath)) continue;\n\t\tsettings.extensions = settings.extensions ?? [];\n\t\tsettings.extensions.push(extensionPath);\n\t\texisting.add(extensionPath);\n\t\tadded.push(extensionPath);\n\t}\n\n\tif (added.length > 0 || filteredExistingExtensions.length !== existingExtensions.length) {\n\t\tmkdirSync(dirname(settingsPath), { recursive: true });\n\t\twriteFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\\n`);\n\t}\n\n\tconst nextDiagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\treturn { ...nextDiagnostic, added };\n}\n\n/**\n * Migrate legacy oauth.json and settings.json apiKeys to auth.json.\n *\n * @returns Array of provider names that were migrated\n */\nexport function migrateAuthToAuthJson(): string[] {\n\tconst agentDir = getAgentDir();\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Skip if auth.json already exists\n\tif (existsSync(authPath)) return [];\n\n\tconst migrated: Record<string, unknown> = {};\n\tconst providers: string[] = [];\n\n\t// Migrate oauth.json\n\tif (existsSync(oauthPath)) {\n\t\ttry {\n\t\t\tconst oauth = JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\tfor (const [provider, cred] of Object.entries(oauth)) {\n\t\t\t\tmigrated[provider] = { type: \"oauth\", ...(cred as object) };\n\t\t\t\tproviders.push(provider);\n\t\t\t}\n\t\t\trenameSync(oauthPath, `${oauthPath}.migrated`);\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\t// Migrate settings.json apiKeys\n\tif (existsSync(settingsPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(settingsPath, \"utf-8\");\n\t\t\tconst settings = JSON.parse(content);\n\t\t\tif (settings.apiKeys && typeof settings.apiKeys === \"object\") {\n\t\t\t\tfor (const [provider, key] of Object.entries(settings.apiKeys)) {\n\t\t\t\t\tif (!migrated[provider] && typeof key === \"string\") {\n\t\t\t\t\t\tmigrated[provider] = { type: \"api_key\", key };\n\t\t\t\t\t\tproviders.push(provider);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdelete settings.apiKeys;\n\t\t\t\twriteFileSync(settingsPath, JSON.stringify(settings, null, 2));\n\t\t\t}\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\tif (Object.keys(migrated).length > 0) {\n\t\tmkdirSync(dirname(authPath), { recursive: true });\n\t\twriteFileSync(authPath, JSON.stringify(migrated, null, 2), { mode: 0o600 });\n\t}\n\n\treturn providers;\n}\n\n/**\n * Migrate sessions from ~/.aery/agent/*.jsonl to proper session directories.\n *\n * Bug in v0.30.0: Sessions were saved to ~/.aery/agent/ instead of\n * ~/.aery/agent/sessions/<encoded-cwd>/. This migration moves them\n * to the correct location based on the cwd in their session header.\n *\n * See: https://github.com/eminent337/aery/issues/320\n */\nexport function migrateSessionsFromAgentRoot(): void {\n\tconst agentDir = getAgentDir();\n\n\t// Find all .jsonl files directly in agentDir (not in subdirectories)\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(agentDir)\n\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f) => join(agentDir, f));\n\t} catch {\n\t\treturn;\n\t}\n\n\tif (files.length === 0) return;\n\n\tfor (const file of files) {\n\t\ttry {\n\t\t\t// Read first line to get session header\n\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\tconst firstLine = content.split(\"\\n\")[0];\n\t\t\tif (!firstLine?.trim()) continue;\n\n\t\t\tconst header = JSON.parse(firstLine);\n\t\t\tif (header.type !== \"session\" || !header.cwd) continue;\n\n\t\t\tconst cwd: string = header.cwd;\n\n\t\t\t// Compute the correct session directory (same encoding as session-manager.ts)\n\t\t\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\t\t\tconst correctDir = join(agentDir, \"sessions\", safePath);\n\n\t\t\t// Create directory if needed\n\t\t\tif (!existsSync(correctDir)) {\n\t\t\t\tmkdirSync(correctDir, { recursive: true });\n\t\t\t}\n\n\t\t\t// Move the file\n\t\t\tconst fileName = file.split(\"/\").pop() || file.split(\"\\\\\").pop();\n\t\t\tconst newPath = join(correctDir, fileName!);\n\n\t\t\tif (existsSync(newPath)) continue; // Skip if target exists\n\n\t\t\trenameSync(file, newPath);\n\t\t} catch {\n\t\t\t// Skip files that can't be migrated\n\t\t}\n\t}\n}\n\n/**\n * Migrate commands/ to prompts/ if needed.\n * Works for both regular directories and symlinks.\n */\nfunction migrateCommandsToPrompts(baseDir: string, label: string): boolean {\n\tconst commandsDir = join(baseDir, \"commands\");\n\tconst promptsDir = join(baseDir, \"prompts\");\n\n\tif (existsSync(commandsDir) && !existsSync(promptsDir)) {\n\t\ttry {\n\t\t\trenameSync(commandsDir, promptsDir);\n\t\t\tconsole.log(chalk.green(`Migrated ${label} commands/ → prompts/`));\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tconsole.log(\n\t\t\t\tchalk.yellow(\n\t\t\t\t\t`Warning: Could not migrate ${label} commands/ to prompts/: ${err instanceof Error ? err.message : err}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction migrateKeybindingsConfigFile(): void {\n\tconst configPath = join(getAgentDir(), \"keybindings.json\");\n\tif (!existsSync(configPath)) return;\n\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(configPath, \"utf-8\")) as unknown;\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\t\treturn;\n\t\t}\n\t\tconst { config, migrated } = migrateKeybindingsConfig(parsed as Record<string, unknown>);\n\t\tif (!migrated) return;\n\t\twriteFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\t} catch {\n\t\t// Ignore malformed files during migration\n\t}\n}\n\n/**\n * Move fd/rg binaries from tools/ to bin/ if they exist.\n */\nfunction migrateToolsToBin(): void {\n\tconst agentDir = getAgentDir();\n\tconst toolsDir = join(agentDir, \"tools\");\n\tconst binDir = getBinDir();\n\n\tif (!existsSync(toolsDir)) return;\n\n\tconst binaries = [\"fd\", \"rg\", \"fd.exe\", \"rg.exe\"];\n\tlet movedAny = false;\n\n\tfor (const bin of binaries) {\n\t\tconst oldPath = join(toolsDir, bin);\n\t\tconst newPath = join(binDir, bin);\n\n\t\tif (existsSync(oldPath)) {\n\t\t\tif (!existsSync(binDir)) {\n\t\t\t\tmkdirSync(binDir, { recursive: true });\n\t\t\t}\n\t\t\tif (!existsSync(newPath)) {\n\t\t\t\ttry {\n\t\t\t\t\trenameSync(oldPath, newPath);\n\t\t\t\t\tmovedAny = true;\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Target exists, just delete the old one\n\t\t\t\ttry {\n\t\t\t\t\trmSync?.(oldPath, { force: true });\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (movedAny) {\n\t\tconsole.log(chalk.green(`Migrated managed binaries tools/ → bin/`));\n\t}\n}\n\n/**\n * Check for deprecated hooks/ and tools/ directories.\n * Note: tools/ may contain fd/rg binaries extracted by aery, so only warn if it has other files.\n */\nfunction checkDeprecatedExtensionDirs(baseDir: string, label: string): string[] {\n\tconst hooksDir = join(baseDir, \"hooks\");\n\tconst toolsDir = join(baseDir, \"tools\");\n\tconst warnings: string[] = [];\n\n\tif (existsSync(hooksDir)) {\n\t\twarnings.push(`${label} hooks/ directory found. Hooks have been renamed to extensions.`);\n\t}\n\n\tif (existsSync(toolsDir)) {\n\t\t// Check if tools/ contains anything other than fd/rg (which are auto-extracted binaries)\n\t\ttry {\n\t\t\tconst entries = readdirSync(toolsDir);\n\t\t\tconst customTools = entries.filter((e) => {\n\t\t\t\tconst lower = e.toLowerCase();\n\t\t\t\treturn (\n\t\t\t\t\tlower !== \"fd\" && lower !== \"rg\" && lower !== \"fd.exe\" && lower !== \"rg.exe\" && !e.startsWith(\".\") // Ignore .DS_Store and other hidden files\n\t\t\t\t);\n\t\t\t});\n\t\t\tif (customTools.length > 0) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`${label} tools/ directory contains custom tools. Custom tools have been merged into extensions.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors\n\t\t}\n\t}\n\n\treturn warnings;\n}\n\n/**\n * Run extension system migrations (commands→prompts) and collect warnings about deprecated directories.\n */\nfunction migrateExtensionSystem(cwd: string): string[] {\n\tconst agentDir = getAgentDir();\n\tconst projectDir = join(cwd, CONFIG_DIR_NAME);\n\n\t// Migrate commands/ to prompts/\n\tmigrateCommandsToPrompts(agentDir, \"Global\");\n\tmigrateCommandsToPrompts(projectDir, \"Project\");\n\n\t// Check for deprecated directories\n\tconst warnings = [\n\t\t...checkDeprecatedExtensionDirs(agentDir, \"Global\"),\n\t\t...checkDeprecatedExtensionDirs(projectDir, \"Project\"),\n\t];\n\n\treturn warnings;\n}\n\n/**\n * Print deprecation warnings and wait for keypress.\n */\nexport async function showDeprecationWarnings(warnings: string[]): Promise<void> {\n\tif (warnings.length === 0) return;\n\n\tfor (const warning of warnings) {\n\t\tconsole.log(chalk.yellow(`Warning: ${warning}`));\n\t}\n\tconsole.log(chalk.yellow(`\\nMove your extensions to the extensions/ directory.`));\n\tconsole.log(chalk.yellow(`Migration guide: ${MIGRATION_GUIDE_URL}`));\n\tconsole.log(chalk.yellow(`Documentation: ${EXTENSIONS_DOC_URL}`));\n\tconsole.log(chalk.dim(`\\nPress any key to continue...`));\n\n\tawait new Promise<void>((resolve) => {\n\t\tprocess.stdin.setRawMode?.(true);\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.once(\"data\", () => {\n\t\t\tprocess.stdin.setRawMode?.(false);\n\t\t\tprocess.stdin.pause();\n\t\t\tresolve();\n\t\t});\n\t});\n\tconsole.log();\n}\n\n/**\n * Wire any missing core extensions for existing users who already have aery-extensions installed.\n * Runs on every startup but is idempotent — only adds extensions not already in settings.\n */\nfunction wireMissingCoreExtensions(): void {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\tif (!existsSync(repoPath)) return;\n\n\ttry {\n\t\twireCoreExtensions(repoPath, settingsPath);\n\t} catch {\n\t\t// Silent fail\n\t}\n}\n\n/**\n * Ensure aery-extensions is cloned and core extensions are wired.\n * Called at startup — installs aery-extensions if missing, then wires core extensions.\n * Safe to call multiple times (idempotent).\n *\n * @returns core extension bootstrap status and diagnostics\n */\nexport function ensureCoreExtensions(): CoreExtensionEnsureResult {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Clone if missing\n\tif (!existsSync(repoPath)) {\n\t\ttry {\n\t\t\tmkdirSync(join(agentDir, \"git\", \"github.com\", \"eminent337\"), { recursive: true });\n\t\t\texecSync(`git clone --depth=1 https://github.com/eminent337/aery-extensions.git \"${repoPath}\"`, {\n\t\t\t\tstdio: \"pipe\",\n\t\t\t\ttimeout: 30000,\n\t\t\t});\n\t\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"installed\", repoPath, settingsPath };\n\t\t} catch (error) {\n\t\t\t// Network unavailable or git missing\n\t\t\treturn {\n\t\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\t\tadded: [],\n\t\t\t\tstatus: \"offline\",\n\t\t\t\trepoPath,\n\t\t\t\tsettingsPath,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t// Repo exists — pull updates in the background (fire and forget)\n\ttry {\n\t\tspawnSync(\"git\", [\"-C\", repoPath, \"pull\", \"--ff-only\", \"--quiet\"], {\n\t\t\ttimeout: 10000,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\t} catch {\n\t\t// Ignore pull failures — offline or git missing\n\t}\n\n\t// Wire any newly added core extensions\n\ttry {\n\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"ok\", repoPath, settingsPath };\n\t} catch (error) {\n\t\treturn {\n\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\tadded: [],\n\t\t\tstatus: \"ok\",\n\t\t\trepoPath,\n\t\t\tsettingsPath,\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function formatCoreExtensionAttentionMessage(result: CoreExtensionEnsureResult): string | undefined {\n\tif (result.status === \"offline\") {\n\t\treturn \"Extensions not installed (no network). Run aery again with network access, or run: aery update --extensions\";\n\t}\n\n\tif (result.error) {\n\t\treturn `Core extensions need attention: ${result.error}. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingFiles.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingFiles.length} core extension file(s) are missing. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingSettingsEntries.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingSettingsEntries.length} core extension setting(s) are missing. Run: aery update --extensions`;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Run all migrations. Called once on startup.\n *\n * @returns Object with migration results and deprecation warnings\n */\nexport function runMigrations(cwd: string): {\n\tmigratedAuthProviders: string[];\n\tdeprecationWarnings: string[];\n} {\n\tconst migratedAuthProviders = migrateAuthToAuthJson();\n\tmigrateSessionsFromAgentRoot();\n\tmigrateToolsToBin();\n\tmigrateKeybindingsConfigFile();\n\twireMissingCoreExtensions();\n\tconst deprecationWarnings = migrateExtensionSystem(cwd);\n\treturn { migratedAuthProviders, deprecationWarnings };\n}\n"]}
@@ -33,6 +33,7 @@ export const CORE_EXTENSION_PATHS = [
33
33
  "session-auto-name",
34
34
  "upstream-notify",
35
35
  "init-prompt",
36
+ "graphify",
36
37
  ];
37
38
  export const DEPRECATED_CORE_EXTENSION_PATHS = ["provider-profiles"];
38
39
  export function getCoreExtensionFilePaths(repoPath) {
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One-time migrations that run on startup.\n */\n\nimport chalk from \"chalk\";\nimport { execSync, spawnSync } from \"child_process\";\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir, getBinDir } from \"./config.js\";\nimport { migrateKeybindingsConfig } from \"./core/keybindings.js\";\n\nconst MIGRATION_GUIDE_URL =\n\t\"https://github.com/eminent337/aery/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration\";\nconst EXTENSIONS_DOC_URL = \"https://github.com/eminent337/aery/blob/main/packages/coding-agent/docs/extensions.md\";\nexport const CORE_EXTENSION_PATHS = [\n\t\"damage-control\",\n\t\"model-failover\",\n\t\"web-search\",\n\t\"web-fetch\",\n\t\"commands\",\n\t\"hooks\",\n\t\"circuit-breaker\",\n\t\"auto-router\",\n\t\"memory-include\",\n\t\"aery-header\",\n\t\"aery-footer\",\n\t\"multi-agent\",\n\t\"agent-chain\",\n\t\"agent-teams\",\n\t\"help\",\n\t\"default-agents\",\n\t\"aery-doctor\",\n\t\"aery-team\",\n\t\"subagent/index\",\n\t\"marketplace\",\n\t\"session-auto-name\",\n\t\"upstream-notify\",\n\t\"init-prompt\",\n] as const;\n\nexport const DEPRECATED_CORE_EXTENSION_PATHS = [\"provider-profiles\"] as const;\n\nexport interface CoreExtensionDiagnostic {\n\trepoExists: boolean;\n\tmissingFiles: string[];\n\tmissingSettingsEntries: string[];\n}\n\nexport interface CoreExtensionWireResult extends CoreExtensionDiagnostic {\n\tadded: string[];\n}\n\nexport interface CoreExtensionEnsureResult extends CoreExtensionWireResult {\n\tstatus: \"installed\" | \"offline\" | \"ok\";\n\trepoPath: string;\n\tsettingsPath: string;\n\terror?: string;\n}\n\nexport function getCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction getDeprecatedCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn DEPRECATED_CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction readSettingsExtensions(settingsPath: string): string[] {\n\tif (!existsSync(settingsPath)) return [];\n\ttry {\n\t\tconst settings = JSON.parse(readFileSync(settingsPath, \"utf-8\")) as { extensions?: unknown };\n\t\treturn Array.isArray(settings.extensions)\n\t\t\t? settings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t\t: [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function diagnoseCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionDiagnostic {\n\tconst expectedPaths = getCoreExtensionFilePaths(repoPath);\n\tconst repoExists = existsSync(repoPath);\n\tconst settingsExtensions = new Set(readSettingsExtensions(settingsPath));\n\treturn {\n\t\trepoExists,\n\t\tmissingFiles: repoExists ? expectedPaths.filter((extensionPath) => !existsSync(extensionPath)) : expectedPaths,\n\t\tmissingSettingsEntries: expectedPaths.filter(\n\t\t\t(extensionPath) => existsSync(extensionPath) && !settingsExtensions.has(extensionPath),\n\t\t),\n\t};\n}\n\nexport function wireCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionWireResult {\n\tconst diagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\tif (!diagnostic.repoExists) return { ...diagnostic, added: [] };\n\n\tconst parsedSettings = (existsSync(settingsPath) ? JSON.parse(readFileSync(settingsPath, \"utf-8\")) : {}) as {\n\t\textensions?: unknown;\n\t};\n\tconst existingExtensions = Array.isArray(parsedSettings.extensions)\n\t\t? parsedSettings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\tconst deprecatedExtensions = new Set(getDeprecatedCoreExtensionFilePaths(repoPath));\n\tconst filteredExistingExtensions = existingExtensions.filter(\n\t\t(extensionPath) => !deprecatedExtensions.has(extensionPath),\n\t);\n\tconst settings: Record<string, unknown> & { extensions?: string[] } = {\n\t\t...parsedSettings,\n\t\textensions: filteredExistingExtensions,\n\t};\n\tconst existing = new Set<string>(filteredExistingExtensions);\n\tconst added: string[] = [];\n\tfor (const extensionPath of getCoreExtensionFilePaths(repoPath)) {\n\t\tif (!existsSync(extensionPath) || existing.has(extensionPath)) continue;\n\t\tsettings.extensions = settings.extensions ?? [];\n\t\tsettings.extensions.push(extensionPath);\n\t\texisting.add(extensionPath);\n\t\tadded.push(extensionPath);\n\t}\n\n\tif (added.length > 0 || filteredExistingExtensions.length !== existingExtensions.length) {\n\t\tmkdirSync(dirname(settingsPath), { recursive: true });\n\t\twriteFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\\n`);\n\t}\n\n\tconst nextDiagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\treturn { ...nextDiagnostic, added };\n}\n\n/**\n * Migrate legacy oauth.json and settings.json apiKeys to auth.json.\n *\n * @returns Array of provider names that were migrated\n */\nexport function migrateAuthToAuthJson(): string[] {\n\tconst agentDir = getAgentDir();\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Skip if auth.json already exists\n\tif (existsSync(authPath)) return [];\n\n\tconst migrated: Record<string, unknown> = {};\n\tconst providers: string[] = [];\n\n\t// Migrate oauth.json\n\tif (existsSync(oauthPath)) {\n\t\ttry {\n\t\t\tconst oauth = JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\tfor (const [provider, cred] of Object.entries(oauth)) {\n\t\t\t\tmigrated[provider] = { type: \"oauth\", ...(cred as object) };\n\t\t\t\tproviders.push(provider);\n\t\t\t}\n\t\t\trenameSync(oauthPath, `${oauthPath}.migrated`);\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\t// Migrate settings.json apiKeys\n\tif (existsSync(settingsPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(settingsPath, \"utf-8\");\n\t\t\tconst settings = JSON.parse(content);\n\t\t\tif (settings.apiKeys && typeof settings.apiKeys === \"object\") {\n\t\t\t\tfor (const [provider, key] of Object.entries(settings.apiKeys)) {\n\t\t\t\t\tif (!migrated[provider] && typeof key === \"string\") {\n\t\t\t\t\t\tmigrated[provider] = { type: \"api_key\", key };\n\t\t\t\t\t\tproviders.push(provider);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdelete settings.apiKeys;\n\t\t\t\twriteFileSync(settingsPath, JSON.stringify(settings, null, 2));\n\t\t\t}\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\tif (Object.keys(migrated).length > 0) {\n\t\tmkdirSync(dirname(authPath), { recursive: true });\n\t\twriteFileSync(authPath, JSON.stringify(migrated, null, 2), { mode: 0o600 });\n\t}\n\n\treturn providers;\n}\n\n/**\n * Migrate sessions from ~/.aery/agent/*.jsonl to proper session directories.\n *\n * Bug in v0.30.0: Sessions were saved to ~/.aery/agent/ instead of\n * ~/.aery/agent/sessions/<encoded-cwd>/. This migration moves them\n * to the correct location based on the cwd in their session header.\n *\n * See: https://github.com/eminent337/aery/issues/320\n */\nexport function migrateSessionsFromAgentRoot(): void {\n\tconst agentDir = getAgentDir();\n\n\t// Find all .jsonl files directly in agentDir (not in subdirectories)\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(agentDir)\n\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f) => join(agentDir, f));\n\t} catch {\n\t\treturn;\n\t}\n\n\tif (files.length === 0) return;\n\n\tfor (const file of files) {\n\t\ttry {\n\t\t\t// Read first line to get session header\n\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\tconst firstLine = content.split(\"\\n\")[0];\n\t\t\tif (!firstLine?.trim()) continue;\n\n\t\t\tconst header = JSON.parse(firstLine);\n\t\t\tif (header.type !== \"session\" || !header.cwd) continue;\n\n\t\t\tconst cwd: string = header.cwd;\n\n\t\t\t// Compute the correct session directory (same encoding as session-manager.ts)\n\t\t\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\t\t\tconst correctDir = join(agentDir, \"sessions\", safePath);\n\n\t\t\t// Create directory if needed\n\t\t\tif (!existsSync(correctDir)) {\n\t\t\t\tmkdirSync(correctDir, { recursive: true });\n\t\t\t}\n\n\t\t\t// Move the file\n\t\t\tconst fileName = file.split(\"/\").pop() || file.split(\"\\\\\").pop();\n\t\t\tconst newPath = join(correctDir, fileName!);\n\n\t\t\tif (existsSync(newPath)) continue; // Skip if target exists\n\n\t\t\trenameSync(file, newPath);\n\t\t} catch {\n\t\t\t// Skip files that can't be migrated\n\t\t}\n\t}\n}\n\n/**\n * Migrate commands/ to prompts/ if needed.\n * Works for both regular directories and symlinks.\n */\nfunction migrateCommandsToPrompts(baseDir: string, label: string): boolean {\n\tconst commandsDir = join(baseDir, \"commands\");\n\tconst promptsDir = join(baseDir, \"prompts\");\n\n\tif (existsSync(commandsDir) && !existsSync(promptsDir)) {\n\t\ttry {\n\t\t\trenameSync(commandsDir, promptsDir);\n\t\t\tconsole.log(chalk.green(`Migrated ${label} commands/ → prompts/`));\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tconsole.log(\n\t\t\t\tchalk.yellow(\n\t\t\t\t\t`Warning: Could not migrate ${label} commands/ to prompts/: ${err instanceof Error ? err.message : err}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction migrateKeybindingsConfigFile(): void {\n\tconst configPath = join(getAgentDir(), \"keybindings.json\");\n\tif (!existsSync(configPath)) return;\n\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(configPath, \"utf-8\")) as unknown;\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\t\treturn;\n\t\t}\n\t\tconst { config, migrated } = migrateKeybindingsConfig(parsed as Record<string, unknown>);\n\t\tif (!migrated) return;\n\t\twriteFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\t} catch {\n\t\t// Ignore malformed files during migration\n\t}\n}\n\n/**\n * Move fd/rg binaries from tools/ to bin/ if they exist.\n */\nfunction migrateToolsToBin(): void {\n\tconst agentDir = getAgentDir();\n\tconst toolsDir = join(agentDir, \"tools\");\n\tconst binDir = getBinDir();\n\n\tif (!existsSync(toolsDir)) return;\n\n\tconst binaries = [\"fd\", \"rg\", \"fd.exe\", \"rg.exe\"];\n\tlet movedAny = false;\n\n\tfor (const bin of binaries) {\n\t\tconst oldPath = join(toolsDir, bin);\n\t\tconst newPath = join(binDir, bin);\n\n\t\tif (existsSync(oldPath)) {\n\t\t\tif (!existsSync(binDir)) {\n\t\t\t\tmkdirSync(binDir, { recursive: true });\n\t\t\t}\n\t\t\tif (!existsSync(newPath)) {\n\t\t\t\ttry {\n\t\t\t\t\trenameSync(oldPath, newPath);\n\t\t\t\t\tmovedAny = true;\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Target exists, just delete the old one\n\t\t\t\ttry {\n\t\t\t\t\trmSync?.(oldPath, { force: true });\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (movedAny) {\n\t\tconsole.log(chalk.green(`Migrated managed binaries tools/ → bin/`));\n\t}\n}\n\n/**\n * Check for deprecated hooks/ and tools/ directories.\n * Note: tools/ may contain fd/rg binaries extracted by aery, so only warn if it has other files.\n */\nfunction checkDeprecatedExtensionDirs(baseDir: string, label: string): string[] {\n\tconst hooksDir = join(baseDir, \"hooks\");\n\tconst toolsDir = join(baseDir, \"tools\");\n\tconst warnings: string[] = [];\n\n\tif (existsSync(hooksDir)) {\n\t\twarnings.push(`${label} hooks/ directory found. Hooks have been renamed to extensions.`);\n\t}\n\n\tif (existsSync(toolsDir)) {\n\t\t// Check if tools/ contains anything other than fd/rg (which are auto-extracted binaries)\n\t\ttry {\n\t\t\tconst entries = readdirSync(toolsDir);\n\t\t\tconst customTools = entries.filter((e) => {\n\t\t\t\tconst lower = e.toLowerCase();\n\t\t\t\treturn (\n\t\t\t\t\tlower !== \"fd\" && lower !== \"rg\" && lower !== \"fd.exe\" && lower !== \"rg.exe\" && !e.startsWith(\".\") // Ignore .DS_Store and other hidden files\n\t\t\t\t);\n\t\t\t});\n\t\t\tif (customTools.length > 0) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`${label} tools/ directory contains custom tools. Custom tools have been merged into extensions.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors\n\t\t}\n\t}\n\n\treturn warnings;\n}\n\n/**\n * Run extension system migrations (commands→prompts) and collect warnings about deprecated directories.\n */\nfunction migrateExtensionSystem(cwd: string): string[] {\n\tconst agentDir = getAgentDir();\n\tconst projectDir = join(cwd, CONFIG_DIR_NAME);\n\n\t// Migrate commands/ to prompts/\n\tmigrateCommandsToPrompts(agentDir, \"Global\");\n\tmigrateCommandsToPrompts(projectDir, \"Project\");\n\n\t// Check for deprecated directories\n\tconst warnings = [\n\t\t...checkDeprecatedExtensionDirs(agentDir, \"Global\"),\n\t\t...checkDeprecatedExtensionDirs(projectDir, \"Project\"),\n\t];\n\n\treturn warnings;\n}\n\n/**\n * Print deprecation warnings and wait for keypress.\n */\nexport async function showDeprecationWarnings(warnings: string[]): Promise<void> {\n\tif (warnings.length === 0) return;\n\n\tfor (const warning of warnings) {\n\t\tconsole.log(chalk.yellow(`Warning: ${warning}`));\n\t}\n\tconsole.log(chalk.yellow(`\\nMove your extensions to the extensions/ directory.`));\n\tconsole.log(chalk.yellow(`Migration guide: ${MIGRATION_GUIDE_URL}`));\n\tconsole.log(chalk.yellow(`Documentation: ${EXTENSIONS_DOC_URL}`));\n\tconsole.log(chalk.dim(`\\nPress any key to continue...`));\n\n\tawait new Promise<void>((resolve) => {\n\t\tprocess.stdin.setRawMode?.(true);\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.once(\"data\", () => {\n\t\t\tprocess.stdin.setRawMode?.(false);\n\t\t\tprocess.stdin.pause();\n\t\t\tresolve();\n\t\t});\n\t});\n\tconsole.log();\n}\n\n/**\n * Wire any missing core extensions for existing users who already have aery-extensions installed.\n * Runs on every startup but is idempotent — only adds extensions not already in settings.\n */\nfunction wireMissingCoreExtensions(): void {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\tif (!existsSync(repoPath)) return;\n\n\ttry {\n\t\twireCoreExtensions(repoPath, settingsPath);\n\t} catch {\n\t\t// Silent fail\n\t}\n}\n\n/**\n * Ensure aery-extensions is cloned and core extensions are wired.\n * Called at startup — installs aery-extensions if missing, then wires core extensions.\n * Safe to call multiple times (idempotent).\n *\n * @returns core extension bootstrap status and diagnostics\n */\nexport function ensureCoreExtensions(): CoreExtensionEnsureResult {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Clone if missing\n\tif (!existsSync(repoPath)) {\n\t\ttry {\n\t\t\tmkdirSync(join(agentDir, \"git\", \"github.com\", \"eminent337\"), { recursive: true });\n\t\t\texecSync(`git clone --depth=1 https://github.com/eminent337/aery-extensions.git \"${repoPath}\"`, {\n\t\t\t\tstdio: \"pipe\",\n\t\t\t\ttimeout: 30000,\n\t\t\t});\n\t\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"installed\", repoPath, settingsPath };\n\t\t} catch (error) {\n\t\t\t// Network unavailable or git missing\n\t\t\treturn {\n\t\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\t\tadded: [],\n\t\t\t\tstatus: \"offline\",\n\t\t\t\trepoPath,\n\t\t\t\tsettingsPath,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t// Repo exists — pull updates in the background (fire and forget)\n\ttry {\n\t\tspawnSync(\"git\", [\"-C\", repoPath, \"pull\", \"--ff-only\", \"--quiet\"], {\n\t\t\ttimeout: 10000,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\t} catch {\n\t\t// Ignore pull failures — offline or git missing\n\t}\n\n\t// Wire any newly added core extensions\n\ttry {\n\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"ok\", repoPath, settingsPath };\n\t} catch (error) {\n\t\treturn {\n\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\tadded: [],\n\t\t\tstatus: \"ok\",\n\t\t\trepoPath,\n\t\t\tsettingsPath,\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function formatCoreExtensionAttentionMessage(result: CoreExtensionEnsureResult): string | undefined {\n\tif (result.status === \"offline\") {\n\t\treturn \"Extensions not installed (no network). Run aery again with network access, or run: aery update --extensions\";\n\t}\n\n\tif (result.error) {\n\t\treturn `Core extensions need attention: ${result.error}. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingFiles.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingFiles.length} core extension file(s) are missing. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingSettingsEntries.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingSettingsEntries.length} core extension setting(s) are missing. Run: aery update --extensions`;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Run all migrations. Called once on startup.\n *\n * @returns Object with migration results and deprecation warnings\n */\nexport function runMigrations(cwd: string): {\n\tmigratedAuthProviders: string[];\n\tdeprecationWarnings: string[];\n} {\n\tconst migratedAuthProviders = migrateAuthToAuthJson();\n\tmigrateSessionsFromAgentRoot();\n\tmigrateToolsToBin();\n\tmigrateKeybindingsConfigFile();\n\twireMissingCoreExtensions();\n\tconst deprecationWarnings = migrateExtensionSystem(cwd);\n\treturn { migratedAuthProviders, deprecationWarnings };\n}\n"]}
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One-time migrations that run on startup.\n */\n\nimport chalk from \"chalk\";\nimport { execSync, spawnSync } from \"child_process\";\nimport { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir, getBinDir } from \"./config.js\";\nimport { migrateKeybindingsConfig } from \"./core/keybindings.js\";\n\nconst MIGRATION_GUIDE_URL =\n\t\"https://github.com/eminent337/aery/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration\";\nconst EXTENSIONS_DOC_URL = \"https://github.com/eminent337/aery/blob/main/packages/coding-agent/docs/extensions.md\";\nexport const CORE_EXTENSION_PATHS = [\n\t\"damage-control\",\n\t\"model-failover\",\n\t\"web-search\",\n\t\"web-fetch\",\n\t\"commands\",\n\t\"hooks\",\n\t\"circuit-breaker\",\n\t\"auto-router\",\n\t\"memory-include\",\n\t\"aery-header\",\n\t\"aery-footer\",\n\t\"multi-agent\",\n\t\"agent-chain\",\n\t\"agent-teams\",\n\t\"help\",\n\t\"default-agents\",\n\t\"aery-doctor\",\n\t\"aery-team\",\n\t\"subagent/index\",\n\t\"marketplace\",\n\t\"session-auto-name\",\n\t\"upstream-notify\",\n\t\"init-prompt\",\n\t\"graphify\",\n] as const;\n\nexport const DEPRECATED_CORE_EXTENSION_PATHS = [\"provider-profiles\"] as const;\n\nexport interface CoreExtensionDiagnostic {\n\trepoExists: boolean;\n\tmissingFiles: string[];\n\tmissingSettingsEntries: string[];\n}\n\nexport interface CoreExtensionWireResult extends CoreExtensionDiagnostic {\n\tadded: string[];\n}\n\nexport interface CoreExtensionEnsureResult extends CoreExtensionWireResult {\n\tstatus: \"installed\" | \"offline\" | \"ok\";\n\trepoPath: string;\n\tsettingsPath: string;\n\terror?: string;\n}\n\nexport function getCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction getDeprecatedCoreExtensionFilePaths(repoPath: string): string[] {\n\treturn DEPRECATED_CORE_EXTENSION_PATHS.map((extensionPath) => join(repoPath, \"core\", `${extensionPath}.ts`));\n}\n\nfunction readSettingsExtensions(settingsPath: string): string[] {\n\tif (!existsSync(settingsPath)) return [];\n\ttry {\n\t\tconst settings = JSON.parse(readFileSync(settingsPath, \"utf-8\")) as { extensions?: unknown };\n\t\treturn Array.isArray(settings.extensions)\n\t\t\t? settings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t\t: [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function diagnoseCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionDiagnostic {\n\tconst expectedPaths = getCoreExtensionFilePaths(repoPath);\n\tconst repoExists = existsSync(repoPath);\n\tconst settingsExtensions = new Set(readSettingsExtensions(settingsPath));\n\treturn {\n\t\trepoExists,\n\t\tmissingFiles: repoExists ? expectedPaths.filter((extensionPath) => !existsSync(extensionPath)) : expectedPaths,\n\t\tmissingSettingsEntries: expectedPaths.filter(\n\t\t\t(extensionPath) => existsSync(extensionPath) && !settingsExtensions.has(extensionPath),\n\t\t),\n\t};\n}\n\nexport function wireCoreExtensions(repoPath: string, settingsPath: string): CoreExtensionWireResult {\n\tconst diagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\tif (!diagnostic.repoExists) return { ...diagnostic, added: [] };\n\n\tconst parsedSettings = (existsSync(settingsPath) ? JSON.parse(readFileSync(settingsPath, \"utf-8\")) : {}) as {\n\t\textensions?: unknown;\n\t};\n\tconst existingExtensions = Array.isArray(parsedSettings.extensions)\n\t\t? parsedSettings.extensions.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\tconst deprecatedExtensions = new Set(getDeprecatedCoreExtensionFilePaths(repoPath));\n\tconst filteredExistingExtensions = existingExtensions.filter(\n\t\t(extensionPath) => !deprecatedExtensions.has(extensionPath),\n\t);\n\tconst settings: Record<string, unknown> & { extensions?: string[] } = {\n\t\t...parsedSettings,\n\t\textensions: filteredExistingExtensions,\n\t};\n\tconst existing = new Set<string>(filteredExistingExtensions);\n\tconst added: string[] = [];\n\tfor (const extensionPath of getCoreExtensionFilePaths(repoPath)) {\n\t\tif (!existsSync(extensionPath) || existing.has(extensionPath)) continue;\n\t\tsettings.extensions = settings.extensions ?? [];\n\t\tsettings.extensions.push(extensionPath);\n\t\texisting.add(extensionPath);\n\t\tadded.push(extensionPath);\n\t}\n\n\tif (added.length > 0 || filteredExistingExtensions.length !== existingExtensions.length) {\n\t\tmkdirSync(dirname(settingsPath), { recursive: true });\n\t\twriteFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\\n`);\n\t}\n\n\tconst nextDiagnostic = diagnoseCoreExtensions(repoPath, settingsPath);\n\treturn { ...nextDiagnostic, added };\n}\n\n/**\n * Migrate legacy oauth.json and settings.json apiKeys to auth.json.\n *\n * @returns Array of provider names that were migrated\n */\nexport function migrateAuthToAuthJson(): string[] {\n\tconst agentDir = getAgentDir();\n\tconst authPath = join(agentDir, \"auth.json\");\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Skip if auth.json already exists\n\tif (existsSync(authPath)) return [];\n\n\tconst migrated: Record<string, unknown> = {};\n\tconst providers: string[] = [];\n\n\t// Migrate oauth.json\n\tif (existsSync(oauthPath)) {\n\t\ttry {\n\t\t\tconst oauth = JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\tfor (const [provider, cred] of Object.entries(oauth)) {\n\t\t\t\tmigrated[provider] = { type: \"oauth\", ...(cred as object) };\n\t\t\t\tproviders.push(provider);\n\t\t\t}\n\t\t\trenameSync(oauthPath, `${oauthPath}.migrated`);\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\t// Migrate settings.json apiKeys\n\tif (existsSync(settingsPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(settingsPath, \"utf-8\");\n\t\t\tconst settings = JSON.parse(content);\n\t\t\tif (settings.apiKeys && typeof settings.apiKeys === \"object\") {\n\t\t\t\tfor (const [provider, key] of Object.entries(settings.apiKeys)) {\n\t\t\t\t\tif (!migrated[provider] && typeof key === \"string\") {\n\t\t\t\t\t\tmigrated[provider] = { type: \"api_key\", key };\n\t\t\t\t\t\tproviders.push(provider);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdelete settings.apiKeys;\n\t\t\t\twriteFileSync(settingsPath, JSON.stringify(settings, null, 2));\n\t\t\t}\n\t\t} catch {\n\t\t\t// Skip on error\n\t\t}\n\t}\n\n\tif (Object.keys(migrated).length > 0) {\n\t\tmkdirSync(dirname(authPath), { recursive: true });\n\t\twriteFileSync(authPath, JSON.stringify(migrated, null, 2), { mode: 0o600 });\n\t}\n\n\treturn providers;\n}\n\n/**\n * Migrate sessions from ~/.aery/agent/*.jsonl to proper session directories.\n *\n * Bug in v0.30.0: Sessions were saved to ~/.aery/agent/ instead of\n * ~/.aery/agent/sessions/<encoded-cwd>/. This migration moves them\n * to the correct location based on the cwd in their session header.\n *\n * See: https://github.com/eminent337/aery/issues/320\n */\nexport function migrateSessionsFromAgentRoot(): void {\n\tconst agentDir = getAgentDir();\n\n\t// Find all .jsonl files directly in agentDir (not in subdirectories)\n\tlet files: string[];\n\ttry {\n\t\tfiles = readdirSync(agentDir)\n\t\t\t.filter((f) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f) => join(agentDir, f));\n\t} catch {\n\t\treturn;\n\t}\n\n\tif (files.length === 0) return;\n\n\tfor (const file of files) {\n\t\ttry {\n\t\t\t// Read first line to get session header\n\t\t\tconst content = readFileSync(file, \"utf8\");\n\t\t\tconst firstLine = content.split(\"\\n\")[0];\n\t\t\tif (!firstLine?.trim()) continue;\n\n\t\t\tconst header = JSON.parse(firstLine);\n\t\t\tif (header.type !== \"session\" || !header.cwd) continue;\n\n\t\t\tconst cwd: string = header.cwd;\n\n\t\t\t// Compute the correct session directory (same encoding as session-manager.ts)\n\t\t\tconst safePath = `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n\t\t\tconst correctDir = join(agentDir, \"sessions\", safePath);\n\n\t\t\t// Create directory if needed\n\t\t\tif (!existsSync(correctDir)) {\n\t\t\t\tmkdirSync(correctDir, { recursive: true });\n\t\t\t}\n\n\t\t\t// Move the file\n\t\t\tconst fileName = file.split(\"/\").pop() || file.split(\"\\\\\").pop();\n\t\t\tconst newPath = join(correctDir, fileName!);\n\n\t\t\tif (existsSync(newPath)) continue; // Skip if target exists\n\n\t\t\trenameSync(file, newPath);\n\t\t} catch {\n\t\t\t// Skip files that can't be migrated\n\t\t}\n\t}\n}\n\n/**\n * Migrate commands/ to prompts/ if needed.\n * Works for both regular directories and symlinks.\n */\nfunction migrateCommandsToPrompts(baseDir: string, label: string): boolean {\n\tconst commandsDir = join(baseDir, \"commands\");\n\tconst promptsDir = join(baseDir, \"prompts\");\n\n\tif (existsSync(commandsDir) && !existsSync(promptsDir)) {\n\t\ttry {\n\t\t\trenameSync(commandsDir, promptsDir);\n\t\t\tconsole.log(chalk.green(`Migrated ${label} commands/ → prompts/`));\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tconsole.log(\n\t\t\t\tchalk.yellow(\n\t\t\t\t\t`Warning: Could not migrate ${label} commands/ to prompts/: ${err instanceof Error ? err.message : err}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction migrateKeybindingsConfigFile(): void {\n\tconst configPath = join(getAgentDir(), \"keybindings.json\");\n\tif (!existsSync(configPath)) return;\n\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(configPath, \"utf-8\")) as unknown;\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\t\treturn;\n\t\t}\n\t\tconst { config, migrated } = migrateKeybindingsConfig(parsed as Record<string, unknown>);\n\t\tif (!migrated) return;\n\t\twriteFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\t} catch {\n\t\t// Ignore malformed files during migration\n\t}\n}\n\n/**\n * Move fd/rg binaries from tools/ to bin/ if they exist.\n */\nfunction migrateToolsToBin(): void {\n\tconst agentDir = getAgentDir();\n\tconst toolsDir = join(agentDir, \"tools\");\n\tconst binDir = getBinDir();\n\n\tif (!existsSync(toolsDir)) return;\n\n\tconst binaries = [\"fd\", \"rg\", \"fd.exe\", \"rg.exe\"];\n\tlet movedAny = false;\n\n\tfor (const bin of binaries) {\n\t\tconst oldPath = join(toolsDir, bin);\n\t\tconst newPath = join(binDir, bin);\n\n\t\tif (existsSync(oldPath)) {\n\t\t\tif (!existsSync(binDir)) {\n\t\t\t\tmkdirSync(binDir, { recursive: true });\n\t\t\t}\n\t\t\tif (!existsSync(newPath)) {\n\t\t\t\ttry {\n\t\t\t\t\trenameSync(oldPath, newPath);\n\t\t\t\t\tmovedAny = true;\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Target exists, just delete the old one\n\t\t\t\ttry {\n\t\t\t\t\trmSync?.(oldPath, { force: true });\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (movedAny) {\n\t\tconsole.log(chalk.green(`Migrated managed binaries tools/ → bin/`));\n\t}\n}\n\n/**\n * Check for deprecated hooks/ and tools/ directories.\n * Note: tools/ may contain fd/rg binaries extracted by aery, so only warn if it has other files.\n */\nfunction checkDeprecatedExtensionDirs(baseDir: string, label: string): string[] {\n\tconst hooksDir = join(baseDir, \"hooks\");\n\tconst toolsDir = join(baseDir, \"tools\");\n\tconst warnings: string[] = [];\n\n\tif (existsSync(hooksDir)) {\n\t\twarnings.push(`${label} hooks/ directory found. Hooks have been renamed to extensions.`);\n\t}\n\n\tif (existsSync(toolsDir)) {\n\t\t// Check if tools/ contains anything other than fd/rg (which are auto-extracted binaries)\n\t\ttry {\n\t\t\tconst entries = readdirSync(toolsDir);\n\t\t\tconst customTools = entries.filter((e) => {\n\t\t\t\tconst lower = e.toLowerCase();\n\t\t\t\treturn (\n\t\t\t\t\tlower !== \"fd\" && lower !== \"rg\" && lower !== \"fd.exe\" && lower !== \"rg.exe\" && !e.startsWith(\".\") // Ignore .DS_Store and other hidden files\n\t\t\t\t);\n\t\t\t});\n\t\t\tif (customTools.length > 0) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`${label} tools/ directory contains custom tools. Custom tools have been merged into extensions.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors\n\t\t}\n\t}\n\n\treturn warnings;\n}\n\n/**\n * Run extension system migrations (commands→prompts) and collect warnings about deprecated directories.\n */\nfunction migrateExtensionSystem(cwd: string): string[] {\n\tconst agentDir = getAgentDir();\n\tconst projectDir = join(cwd, CONFIG_DIR_NAME);\n\n\t// Migrate commands/ to prompts/\n\tmigrateCommandsToPrompts(agentDir, \"Global\");\n\tmigrateCommandsToPrompts(projectDir, \"Project\");\n\n\t// Check for deprecated directories\n\tconst warnings = [\n\t\t...checkDeprecatedExtensionDirs(agentDir, \"Global\"),\n\t\t...checkDeprecatedExtensionDirs(projectDir, \"Project\"),\n\t];\n\n\treturn warnings;\n}\n\n/**\n * Print deprecation warnings and wait for keypress.\n */\nexport async function showDeprecationWarnings(warnings: string[]): Promise<void> {\n\tif (warnings.length === 0) return;\n\n\tfor (const warning of warnings) {\n\t\tconsole.log(chalk.yellow(`Warning: ${warning}`));\n\t}\n\tconsole.log(chalk.yellow(`\\nMove your extensions to the extensions/ directory.`));\n\tconsole.log(chalk.yellow(`Migration guide: ${MIGRATION_GUIDE_URL}`));\n\tconsole.log(chalk.yellow(`Documentation: ${EXTENSIONS_DOC_URL}`));\n\tconsole.log(chalk.dim(`\\nPress any key to continue...`));\n\n\tawait new Promise<void>((resolve) => {\n\t\tprocess.stdin.setRawMode?.(true);\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.once(\"data\", () => {\n\t\t\tprocess.stdin.setRawMode?.(false);\n\t\t\tprocess.stdin.pause();\n\t\t\tresolve();\n\t\t});\n\t});\n\tconsole.log();\n}\n\n/**\n * Wire any missing core extensions for existing users who already have aery-extensions installed.\n * Runs on every startup but is idempotent — only adds extensions not already in settings.\n */\nfunction wireMissingCoreExtensions(): void {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\tif (!existsSync(repoPath)) return;\n\n\ttry {\n\t\twireCoreExtensions(repoPath, settingsPath);\n\t} catch {\n\t\t// Silent fail\n\t}\n}\n\n/**\n * Ensure aery-extensions is cloned and core extensions are wired.\n * Called at startup — installs aery-extensions if missing, then wires core extensions.\n * Safe to call multiple times (idempotent).\n *\n * @returns core extension bootstrap status and diagnostics\n */\nexport function ensureCoreExtensions(): CoreExtensionEnsureResult {\n\tconst agentDir = getAgentDir();\n\tconst repoPath = join(agentDir, \"git\", \"github.com\", \"eminent337\", \"aery-extensions\");\n\tconst settingsPath = join(agentDir, \"settings.json\");\n\n\t// Clone if missing\n\tif (!existsSync(repoPath)) {\n\t\ttry {\n\t\t\tmkdirSync(join(agentDir, \"git\", \"github.com\", \"eminent337\"), { recursive: true });\n\t\t\texecSync(`git clone --depth=1 https://github.com/eminent337/aery-extensions.git \"${repoPath}\"`, {\n\t\t\t\tstdio: \"pipe\",\n\t\t\t\ttimeout: 30000,\n\t\t\t});\n\t\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"installed\", repoPath, settingsPath };\n\t\t} catch (error) {\n\t\t\t// Network unavailable or git missing\n\t\t\treturn {\n\t\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\t\tadded: [],\n\t\t\t\tstatus: \"offline\",\n\t\t\t\trepoPath,\n\t\t\t\tsettingsPath,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t// Repo exists — pull updates in the background (fire and forget)\n\ttry {\n\t\tspawnSync(\"git\", [\"-C\", repoPath, \"pull\", \"--ff-only\", \"--quiet\"], {\n\t\t\ttimeout: 10000,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\t} catch {\n\t\t// Ignore pull failures — offline or git missing\n\t}\n\n\t// Wire any newly added core extensions\n\ttry {\n\t\treturn { ...wireCoreExtensions(repoPath, settingsPath), status: \"ok\", repoPath, settingsPath };\n\t} catch (error) {\n\t\treturn {\n\t\t\t...diagnoseCoreExtensions(repoPath, settingsPath),\n\t\t\tadded: [],\n\t\t\tstatus: \"ok\",\n\t\t\trepoPath,\n\t\t\tsettingsPath,\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function formatCoreExtensionAttentionMessage(result: CoreExtensionEnsureResult): string | undefined {\n\tif (result.status === \"offline\") {\n\t\treturn \"Extensions not installed (no network). Run aery again with network access, or run: aery update --extensions\";\n\t}\n\n\tif (result.error) {\n\t\treturn `Core extensions need attention: ${result.error}. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingFiles.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingFiles.length} core extension file(s) are missing. Run: aery update --extensions`;\n\t}\n\n\tif (result.missingSettingsEntries.length > 0) {\n\t\treturn `Core extensions need attention: ${result.missingSettingsEntries.length} core extension setting(s) are missing. Run: aery update --extensions`;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Run all migrations. Called once on startup.\n *\n * @returns Object with migration results and deprecation warnings\n */\nexport function runMigrations(cwd: string): {\n\tmigratedAuthProviders: string[];\n\tdeprecationWarnings: string[];\n} {\n\tconst migratedAuthProviders = migrateAuthToAuthJson();\n\tmigrateSessionsFromAgentRoot();\n\tmigrateToolsToBin();\n\tmigrateKeybindingsConfigFile();\n\twireMissingCoreExtensions();\n\tconst deprecationWarnings = migrateExtensionSystem(cwd);\n\treturn { migratedAuthProviders, deprecationWarnings };\n}\n"]}
@@ -324,6 +324,7 @@ export declare class InteractiveMode {
324
324
  private showOAuthSelector;
325
325
  private completeProviderAuthentication;
326
326
  private showApiKeyLoginDialog;
327
+ private showAeryGatewayLoginDialog;
327
328
  private showCustomOpenAICompatibleLoginDialog;
328
329
  private showLoginDialog;
329
330
  private handleReloadCommand;