@akon-labs/nexus-cli 0.1.2 → 0.1.4

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.
Files changed (155) hide show
  1. package/CHANGELOG.md +16 -5316
  2. package/README.md +30 -26
  3. package/dist/cli.js +90 -62
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +1 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/extensions/loader.d.ts.map +1 -1
  8. package/dist/core/extensions/loader.js +18 -63
  9. package/dist/core/extensions/loader.js.map +1 -1
  10. package/dist/extensions/gitnexus/gateway.d.ts +2 -0
  11. package/dist/extensions/gitnexus/gateway.d.ts.map +1 -1
  12. package/dist/extensions/gitnexus/gateway.js +22 -4
  13. package/dist/extensions/gitnexus/gateway.js.map +1 -1
  14. package/dist/extensions/gitnexus/index.d.ts.map +1 -1
  15. package/dist/extensions/gitnexus/index.js +21 -3
  16. package/dist/extensions/gitnexus/index.js.map +1 -1
  17. package/dist/extensions/llama/index.d.ts.map +1 -1
  18. package/dist/extensions/llama/index.js +1 -1
  19. package/dist/extensions/llama/index.js.map +1 -1
  20. package/dist/extensions/web-access.d.ts +8 -1
  21. package/dist/extensions/web-access.d.ts.map +1 -1
  22. package/dist/extensions/web-access.js +48 -2
  23. package/dist/extensions/web-access.js.map +1 -1
  24. package/dist/index.js +93 -65
  25. package/dist/migrations.d.ts.map +1 -1
  26. package/dist/migrations.js +2 -2
  27. package/dist/migrations.js.map +1 -1
  28. package/dist/rpc-entry.js +90 -62
  29. package/dist/vendor/agent-core.js +6805 -0
  30. package/dist/vendor/ai.js +12407 -0
  31. package/dist/vendor/tui.js +11645 -0
  32. package/dist/vendor/web-access.js +93103 -0
  33. package/docs/compaction.md +14 -14
  34. package/docs/containerization.md +1 -1
  35. package/docs/custom-provider.md +17 -17
  36. package/docs/development.md +2 -2
  37. package/docs/environment-variables.md +1 -1
  38. package/docs/extensions.md +44 -44
  39. package/docs/index.md +5 -11
  40. package/docs/json.md +4 -4
  41. package/docs/llama-cpp.md +2 -2
  42. package/docs/models.md +3 -3
  43. package/docs/packages.md +6 -6
  44. package/docs/providers.md +13 -13
  45. package/docs/quickstart.md +19 -13
  46. package/docs/rpc.md +1 -1
  47. package/docs/sdk.md +28 -28
  48. package/docs/security.md +1 -1
  49. package/docs/session-format.md +6 -6
  50. package/docs/settings.md +1 -1
  51. package/docs/termux.md +1 -1
  52. package/docs/themes.md +2 -2
  53. package/docs/tui.md +20 -20
  54. package/docs/usage.md +5 -4
  55. package/examples/extensions/README.md +2 -2
  56. package/examples/extensions/auto-commit-on-exit.ts +1 -1
  57. package/examples/extensions/bash-spawn-hook.ts +2 -2
  58. package/examples/extensions/bookmark.ts +1 -1
  59. package/examples/extensions/border-status-editor.ts +3 -3
  60. package/examples/extensions/built-in-tool-renderer.ts +3 -3
  61. package/examples/extensions/claude-rules.ts +1 -1
  62. package/examples/extensions/commands.ts +1 -1
  63. package/examples/extensions/confirm-destructive.ts +1 -1
  64. package/examples/extensions/custom-compaction.ts +3 -3
  65. package/examples/extensions/custom-footer.ts +3 -3
  66. package/examples/extensions/custom-header.ts +2 -2
  67. package/examples/extensions/custom-provider-anthropic/index.ts +2 -2
  68. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  69. package/examples/extensions/custom-provider-gitlab-duo/test.ts +1 -1
  70. package/examples/extensions/dirty-repo-guard.ts +1 -1
  71. package/examples/extensions/doom-overlay/doom-component.ts +2 -2
  72. package/examples/extensions/doom-overlay/doom-keys.ts +1 -1
  73. package/examples/extensions/doom-overlay/index.ts +1 -1
  74. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  75. package/examples/extensions/dynamic-resources/index.ts +1 -1
  76. package/examples/extensions/dynamic-tools.ts +1 -1
  77. package/examples/extensions/entry-renderer.ts +2 -2
  78. package/examples/extensions/event-bus.ts +1 -1
  79. package/examples/extensions/file-trigger.ts +1 -1
  80. package/examples/extensions/git-checkpoint.ts +1 -1
  81. package/examples/extensions/git-merge-and-resolve.ts +1 -1
  82. package/examples/extensions/github-issue-autocomplete.ts +2 -2
  83. package/examples/extensions/gondolin/index.ts +2 -2
  84. package/examples/extensions/handoff.ts +4 -4
  85. package/examples/extensions/hello.ts +2 -2
  86. package/examples/extensions/hidden-thinking-label.ts +1 -1
  87. package/examples/extensions/inline-bash.ts +1 -1
  88. package/examples/extensions/input-transform-streaming.ts +1 -1
  89. package/examples/extensions/input-transform.ts +1 -1
  90. package/examples/extensions/interactive-shell.ts +1 -1
  91. package/examples/extensions/kimi-deferred-tools.ts +1 -1
  92. package/examples/extensions/mac-system-theme.ts +1 -1
  93. package/examples/extensions/message-renderer.ts +2 -2
  94. package/examples/extensions/minimal-mode.ts +3 -3
  95. package/examples/extensions/modal-editor.ts +2 -2
  96. package/examples/extensions/model-status.ts +1 -1
  97. package/examples/extensions/notify.ts +1 -1
  98. package/examples/extensions/overlay-qa-tests.ts +5 -5
  99. package/examples/extensions/overlay-test.ts +2 -2
  100. package/examples/extensions/permission-gate.ts +1 -1
  101. package/examples/extensions/pirate.ts +1 -1
  102. package/examples/extensions/plan-mode/index.ts +4 -4
  103. package/examples/extensions/preset.ts +4 -4
  104. package/examples/extensions/project-trust.ts +1 -1
  105. package/examples/extensions/prompt-customizer.ts +1 -1
  106. package/examples/extensions/protected-paths.ts +1 -1
  107. package/examples/extensions/provider-payload.ts +1 -1
  108. package/examples/extensions/qna.ts +3 -3
  109. package/examples/extensions/question.ts +2 -2
  110. package/examples/extensions/questionnaire.ts +2 -2
  111. package/examples/extensions/rainbow-editor.ts +1 -1
  112. package/examples/extensions/reload-runtime.ts +1 -1
  113. package/examples/extensions/rpc-demo.ts +1 -1
  114. package/examples/extensions/sandbox/index.ts +2 -2
  115. package/examples/extensions/send-user-message.ts +1 -1
  116. package/examples/extensions/session-name.ts +1 -1
  117. package/examples/extensions/shutdown-command.ts +1 -1
  118. package/examples/extensions/snake.ts +2 -2
  119. package/examples/extensions/space-invaders.ts +2 -2
  120. package/examples/extensions/ssh.ts +2 -2
  121. package/examples/extensions/status-line.ts +1 -1
  122. package/examples/extensions/structured-output.ts +2 -2
  123. package/examples/extensions/subagent/agents.ts +1 -1
  124. package/examples/extensions/subagent/index.ts +5 -5
  125. package/examples/extensions/summarize.ts +4 -4
  126. package/examples/extensions/system-prompt-header.ts +1 -1
  127. package/examples/extensions/tic-tac-toe.ts +3 -3
  128. package/examples/extensions/timed-confirm.ts +1 -1
  129. package/examples/extensions/titlebar-spinner.ts +1 -1
  130. package/examples/extensions/todo.ts +3 -3
  131. package/examples/extensions/tool-override.ts +2 -2
  132. package/examples/extensions/tools.ts +3 -3
  133. package/examples/extensions/trigger-compact.ts +1 -1
  134. package/examples/extensions/truncated-tool.ts +3 -3
  135. package/examples/extensions/widget-placement.ts +1 -1
  136. package/examples/extensions/with-deps/index.ts +1 -1
  137. package/examples/extensions/working-indicator.ts +1 -1
  138. package/examples/extensions/working-message-test.ts +1 -1
  139. package/examples/rpc-extension-ui.ts +1 -1
  140. package/examples/sdk/01-minimal.ts +1 -1
  141. package/examples/sdk/02-custom-model.ts +1 -1
  142. package/examples/sdk/03-custom-prompt.ts +1 -6
  143. package/examples/sdk/04-skills.ts +1 -1
  144. package/examples/sdk/05-tools.ts +1 -1
  145. package/examples/sdk/06-extensions.ts +2 -7
  146. package/examples/sdk/07-context-files.ts +1 -6
  147. package/examples/sdk/08-prompt-templates.ts +1 -1
  148. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  149. package/examples/sdk/10-settings.ts +1 -1
  150. package/examples/sdk/11-sessions.ts +1 -1
  151. package/examples/sdk/12-full-control.ts +2 -2
  152. package/examples/sdk/13-session-runtime.ts +1 -1
  153. package/examples/sdk/README.md +2 -2
  154. package/npm-shrinkwrap.json +2 -26
  155. package/package.json +10 -25
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@earendil-works/pi-agent-core\";\nimport type { Provider } from \"@earendil-works/pi-ai\";\nimport * as _bundledPiAiCompat from \"@earendil-works/pi-ai/compat\";\nimport * as _bundledPiAiOauth from \"@earendil-works/pi-ai/oauth\";\nimport * as _bundledPiAiProviders from \"@earendil-works/pi-ai/providers/all\";\nimport type { KeyId } from \"@earendil-works/pi-tui\";\nimport * as _bundledPiTui from \"@earendil-works/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @earendil-works/pi-coding-agent.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { readPiManifest } from \"../pi-manifest.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport { time } from \"../timings.ts\";\nimport type {\n\tEntryRenderer,\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMarkdownTransformer,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t// Extensions resolve the pi-ai root to the compat entrypoint (a strict\n\t// superset of the core entrypoint): existing extensions using the old\n\t// global API keep working at runtime until compat is removed.\n\t\"@earendil-works/pi-ai\": _bundledPiAiCompat,\n\t\"@earendil-works/pi-ai/compat\": _bundledPiAiCompat,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-ai/providers/all\": _bundledPiAiProviders,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAiCompat,\n\t\"@mariozechner/pi-ai/compat\": _bundledPiAiCompat,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-ai/providers/all\": _bundledPiAiProviders,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\nconst isTypeScriptSourceRuntime = !isBunBinary && path.extname(fileURLToPath(import.meta.url)) === \".ts\";\n\n/**\n * Get aliases for jiti (used in built Node.js mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@earendil-works/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@earendil-works/pi-tui\");\n\t// Extensions resolve the pi-ai root to the compat entrypoint (a strict\n\t// superset of the core entrypoint): existing extensions using the old\n\t// global API keep working at runtime until compat is removed.\n\tconst piAiCompatEntry = resolveWorkspaceOrImport(\"ai/dist/compat.js\", \"@earendil-works/pi-ai/compat\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@earendil-works/pi-ai/oauth\");\n\tconst piAiProvidersEntry = resolveWorkspaceOrImport(\n\t\t\"ai/dist/providers/all.js\",\n\t\t\"@earendil-works/pi-ai/providers/all\",\n\t);\n\n\t_aliases = {\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai/providers/all\": piAiProvidersEntry,\n\t\t\"@earendil-works/pi-ai/compat\": piAiCompatEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-ai\": piAiCompatEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai/providers/all\": piAiProvidersEntry,\n\t\t\"@mariozechner/pi-ai/compat\": piAiCompatEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-ai\": piAiCompatEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nlet extensionCacheCwd: string | undefined;\nlet extensionCacheGeneration = 0;\nconst extensionCache = new Map<string, ExtensionFactory>();\n\ninterface ExtensionCacheToken {\n\tcwd: string;\n\tgeneration: number;\n}\n\nexport function clearExtensionCache(): void {\n\textensionCache.clear();\n\textensionCacheCwd = undefined;\n\textensionCacheGeneration++;\n}\n\nfunction useExtensionCacheCwd(cwd: string): ExtensionCacheToken {\n\tconst resolvedCwd = resolvePath(cwd);\n\tif (extensionCacheCwd !== undefined && extensionCacheCwd !== resolvedCwd) {\n\t\tclearExtensionCache();\n\t}\n\textensionCacheCwd = resolvedCwd;\n\treturn { cwd: resolvedCwd, generation: extensionCacheGeneration };\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst eventBusUnsubscribers = new Set<() => void>();\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tpendingNativeProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tif (state.staleMessage) return;\n\t\t\tstate.staleMessage =\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured extension API or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t\tfor (const unsubscribe of eventBusUnsubscribers) unsubscribe();\n\t\t\teventBusUnsubscribers.clear();\n\t\t},\n\t\ttrackEventBusSubscription: (unsubscribe) => {\n\t\t\tlet active = true;\n\t\t\tconst trackedUnsubscribe = () => {\n\t\t\t\tif (!active) return;\n\t\t\t\tactive = false;\n\t\t\t\teventBusUnsubscribers.delete(trackedUnsubscribe);\n\t\t\t\tunsubscribe();\n\t\t\t};\n\t\t\teventBusUnsubscribers.add(trackedUnsubscribe);\n\t\t\treturn trackedUnsubscribe;\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tregisterNativeProvider: (provider, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingNativeProviderRegistrations.push({ provider, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t\truntime.pendingNativeProviderRegistrations = runtime.pendingNativeProviderRegistrations.filter(\n\t\t\t\t(r) => r.provider.id !== name,\n\t\t\t);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tregisterMarkdownTransformer(transformer: MarkdownTransformer): void {\n\t\t\truntime.assertActive();\n\t\t\textension.markdownTransformer = transformer;\n\t\t},\n\n\t\tregisterEntryRenderer<T>(customType: string, renderer: EntryRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.entryRenderers ??= new Map();\n\t\t\textension.entryRenderers.set(customType, renderer as EntryRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(providerOrName: Provider | string, config?: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\tif (typeof providerOrName === \"string\") {\n\t\t\t\tif (!config) throw new Error(\"Provider config is required when registering by name\");\n\t\t\t\truntime.registerProvider(providerOrName, config, extension.path);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\truntime.registerNativeProvider(providerOrName, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: {\n\t\t\temit(channel, data) {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton(channel, handler) {\n\t\t\t\truntime.assertActive();\n\t\t\t\treturn runtime.trackEventBusSubscription(eventBus.on(channel, handler));\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nfunction isCurrentCacheToken(cacheToken: ExtensionCacheToken | undefined): cacheToken is ExtensionCacheToken {\n\treturn (\n\t\tcacheToken !== undefined &&\n\t\textensionCacheCwd === cacheToken.cwd &&\n\t\textensionCacheGeneration === cacheToken.generation\n\t);\n}\n\nasync function loadExtensionModule(extensionPath: string, cacheToken?: ExtensionCacheToken) {\n\tif (isCurrentCacheToken(cacheToken)) {\n\t\tconst cachedFactory = extensionCache.get(extensionPath);\n\t\tif (cachedFactory) {\n\t\t\treturn cachedFactory;\n\t\t}\n\t}\n\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// Bun uses modules embedded in the executable. Source TypeScript reuses the\n\t\t// host-resolved modules and root tsconfig paths. Built Node uses dist aliases.\n\t\t...(isBunBinary\n\t\t\t? { virtualModules: VIRTUAL_MODULES, tryNative: false }\n\t\t\t: isTypeScriptSourceRuntime\n\t\t\t\t? { virtualModules: VIRTUAL_MODULES, tsconfigPaths: true }\n\t\t\t\t: { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\tif (typeof factory !== \"function\") {\n\t\treturn undefined;\n\t}\n\tif (isCurrentCacheToken(cacheToken)) {\n\t\textensionCache.set(extensionPath, factory);\n\t}\n\treturn factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tentryRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\tcacheToken?: ExtensionCacheToken,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath, cacheToken);\n\t\ttime(`${extensionPath} module import`, \"extensions\");\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\t\ttime(`${extensionPath} factory`, \"extensions\");\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\ttime(`${extensionPath} factory`, \"extensions\");\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nasync function loadExtensionsInternal(\n\tpaths: string[],\n\tcwd: string,\n\teventBus?: EventBus,\n\truntime?: ExtensionRuntime,\n\tuseCache = false,\n): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst cacheToken = useCache ? useExtensionCacheCwd(cwd) : undefined;\n\tconst resolvedCwd = cacheToken?.cwd ?? resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst resolvedRuntime = runtime ?? createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(\n\t\t\textPath,\n\t\t\tresolvedCwd,\n\t\t\tresolvedEventBus,\n\t\t\tresolvedRuntime,\n\t\t\tcacheToken,\n\t\t);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime: resolvedRuntime,\n\t};\n}\n\nexport async function loadExtensions(\n\tpaths: string[],\n\tcwd: string,\n\teventBus?: EventBus,\n\truntime?: ExtensionRuntime,\n): Promise<LoadExtensionsResult> {\n\treturn loadExtensionsInternal(paths, cwd, eventBus, runtime);\n}\n\nexport async function loadExtensionsCached(\n\tpaths: string[],\n\tcwd: string,\n\teventBus?: EventBus,\n\truntime?: ExtensionRuntime,\n): Promise<LoadExtensionsResult> {\n\treturn loadExtensionsInternal(paths, cwd, eventBus, runtime, true);\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@earendil-works/pi-agent-core\";\nimport type { Provider } from \"@earendil-works/pi-ai\";\nimport * as _bundledPiAiCompat from \"@earendil-works/pi-ai/compat\";\nimport * as _bundledPiAiOauth from \"@earendil-works/pi-ai/oauth\";\nimport * as _bundledPiAiProviders from \"@earendil-works/pi-ai/providers/all\";\nimport type { KeyId } from \"@earendil-works/pi-tui\";\nimport * as _bundledPiTui from \"@earendil-works/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @earendil-works/pi-coding-agent.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { readPiManifest } from \"../pi-manifest.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport { time } from \"../timings.ts\";\nimport type {\n\tEntryRenderer,\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMarkdownTransformer,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t// Extensions resolve the pi-ai root to the compat entrypoint (a strict\n\t// superset of the core entrypoint): existing extensions using the old\n\t// global API keep working at runtime until compat is removed.\n\t\"@earendil-works/pi-ai\": _bundledPiAiCompat,\n\t\"@earendil-works/pi-ai/compat\": _bundledPiAiCompat,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-ai/providers/all\": _bundledPiAiProviders,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t// The fork's own SDK names: without these mappings, an extension importing\n\t// them would resolve the installed package from disk and load a second copy\n\t// instead of sharing the host's instances. These are also the only names\n\t// the public docs/examples use for the pi ecosystem packages.\n\t\"@akon-labs/nexus-cli\": _bundledPiCodingAgent,\n\t\"@akon-labs/nexus-cli/agent-core\": _bundledPiAgentCore,\n\t\"@akon-labs/nexus-cli/tui\": _bundledPiTui,\n\t\"@akon-labs/nexus-cli/ai\": _bundledPiAiCompat,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAiCompat,\n\t\"@mariozechner/pi-ai/compat\": _bundledPiAiCompat,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-ai/providers/all\": _bundledPiAiProviders,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nconst isTypeScriptSourceRuntime = !isBunBinary && path.extname(fileURLToPath(import.meta.url)) === \".ts\";\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nlet extensionCacheCwd: string | undefined;\nlet extensionCacheGeneration = 0;\nconst extensionCache = new Map<string, ExtensionFactory>();\n\ninterface ExtensionCacheToken {\n\tcwd: string;\n\tgeneration: number;\n}\n\nexport function clearExtensionCache(): void {\n\textensionCache.clear();\n\textensionCacheCwd = undefined;\n\textensionCacheGeneration++;\n}\n\nfunction useExtensionCacheCwd(cwd: string): ExtensionCacheToken {\n\tconst resolvedCwd = resolvePath(cwd);\n\tif (extensionCacheCwd !== undefined && extensionCacheCwd !== resolvedCwd) {\n\t\tclearExtensionCache();\n\t}\n\textensionCacheCwd = resolvedCwd;\n\treturn { cwd: resolvedCwd, generation: extensionCacheGeneration };\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst eventBusUnsubscribers = new Set<() => void>();\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tpendingNativeProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tif (state.staleMessage) return;\n\t\t\tstate.staleMessage =\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured extension API or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t\tfor (const unsubscribe of eventBusUnsubscribers) unsubscribe();\n\t\t\teventBusUnsubscribers.clear();\n\t\t},\n\t\ttrackEventBusSubscription: (unsubscribe) => {\n\t\t\tlet active = true;\n\t\t\tconst trackedUnsubscribe = () => {\n\t\t\t\tif (!active) return;\n\t\t\t\tactive = false;\n\t\t\t\teventBusUnsubscribers.delete(trackedUnsubscribe);\n\t\t\t\tunsubscribe();\n\t\t\t};\n\t\t\teventBusUnsubscribers.add(trackedUnsubscribe);\n\t\t\treturn trackedUnsubscribe;\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tregisterNativeProvider: (provider, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingNativeProviderRegistrations.push({ provider, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t\truntime.pendingNativeProviderRegistrations = runtime.pendingNativeProviderRegistrations.filter(\n\t\t\t\t(r) => r.provider.id !== name,\n\t\t\t);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tregisterMarkdownTransformer(transformer: MarkdownTransformer): void {\n\t\t\truntime.assertActive();\n\t\t\textension.markdownTransformer = transformer;\n\t\t},\n\n\t\tregisterEntryRenderer<T>(customType: string, renderer: EntryRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.entryRenderers ??= new Map();\n\t\t\textension.entryRenderers.set(customType, renderer as EntryRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(providerOrName: Provider | string, config?: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\tif (typeof providerOrName === \"string\") {\n\t\t\t\tif (!config) throw new Error(\"Provider config is required when registering by name\");\n\t\t\t\truntime.registerProvider(providerOrName, config, extension.path);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\truntime.registerNativeProvider(providerOrName, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: {\n\t\t\temit(channel, data) {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton(channel, handler) {\n\t\t\t\truntime.assertActive();\n\t\t\t\treturn runtime.trackEventBusSubscription(eventBus.on(channel, handler));\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nfunction isCurrentCacheToken(cacheToken: ExtensionCacheToken | undefined): cacheToken is ExtensionCacheToken {\n\treturn (\n\t\tcacheToken !== undefined &&\n\t\textensionCacheCwd === cacheToken.cwd &&\n\t\textensionCacheGeneration === cacheToken.generation\n\t);\n}\n\nasync function loadExtensionModule(extensionPath: string, cacheToken?: ExtensionCacheToken) {\n\tif (isCurrentCacheToken(cacheToken)) {\n\t\tconst cachedFactory = extensionCache.get(extensionPath);\n\t\tif (cachedFactory) {\n\t\t\treturn cachedFactory;\n\t\t}\n\t}\n\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// All modes serve extensions the statically imported module instances via\n\t\t// virtualModules. This is required for Bun (modules are embedded in the\n\t\t// executable) and for the published npm build (the vendored workspace\n\t\t// packages are inlined into dist/cli.js and exist nowhere on disk), and it\n\t\t// guarantees extensions share the host's module instances rather than\n\t\t// loading a second copy. Source TypeScript additionally resolves through\n\t\t// the root tsconfig paths.\n\t\t...(isTypeScriptSourceRuntime && !isBunBinary\n\t\t\t? { virtualModules: VIRTUAL_MODULES, tsconfigPaths: true }\n\t\t\t: { virtualModules: VIRTUAL_MODULES, tryNative: false }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\tif (typeof factory !== \"function\") {\n\t\treturn undefined;\n\t}\n\tif (isCurrentCacheToken(cacheToken)) {\n\t\textensionCache.set(extensionPath, factory);\n\t}\n\treturn factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tentryRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\tcacheToken?: ExtensionCacheToken,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath, cacheToken);\n\t\ttime(`${extensionPath} module import`, \"extensions\");\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\t\ttime(`${extensionPath} factory`, \"extensions\");\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\ttime(`${extensionPath} factory`, \"extensions\");\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nasync function loadExtensionsInternal(\n\tpaths: string[],\n\tcwd: string,\n\teventBus?: EventBus,\n\truntime?: ExtensionRuntime,\n\tuseCache = false,\n): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst cacheToken = useCache ? useExtensionCacheCwd(cwd) : undefined;\n\tconst resolvedCwd = cacheToken?.cwd ?? resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst resolvedRuntime = runtime ?? createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(\n\t\t\textPath,\n\t\t\tresolvedCwd,\n\t\t\tresolvedEventBus,\n\t\t\tresolvedRuntime,\n\t\t\tcacheToken,\n\t\t);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime: resolvedRuntime,\n\t};\n}\n\nexport async function loadExtensions(\n\tpaths: string[],\n\tcwd: string,\n\teventBus?: EventBus,\n\truntime?: ExtensionRuntime,\n): Promise<LoadExtensionsResult> {\n\treturn loadExtensionsInternal(paths, cwd, eventBus, runtime);\n}\n\nexport async function loadExtensionsCached(\n\tpaths: string[],\n\tcwd: string,\n\teventBus?: EventBus,\n\truntime?: ExtensionRuntime,\n): Promise<LoadExtensionsResult> {\n\treturn loadExtensionsInternal(paths, cwd, eventBus, runtime, true);\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
@@ -28,8 +28,10 @@ export interface GatewayPolicy {
28
28
  usage?: {
29
29
  used: number;
30
30
  limit: number;
31
+ remaining?: number;
31
32
  };
32
33
  }
34
+ export declare function formatCreditBalance(policy: GatewayPolicy | undefined): string | undefined;
33
35
  export declare function gatewayCachePath(): string;
34
36
  /** Cached policy from the last successful refresh, or undefined. */
35
37
  export declare function readGatewayCache(path?: string): GatewayPolicy | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../src/extensions/gitnexus/gateway.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,aAAa,CAAC;AAGtE;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,MAAM,WAAW,aAAa;IAC7B,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAA2B,GAAG,aAAa,GAAG,SAAS,CAa7F;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAGzC,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChF,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAuCpC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CACnC,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,MAAM,EAAE,aAAa,GAAG,SAAS,GAC/B,OAAO,CAgCT","sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { type GitNexusConfig, gitNexusConfigPath } from \"./config.ts\";\nimport { hubApiBase } from \"./device-auth.ts\";\n\n/**\n * Auto mode: models served through the hub's LLM gateway.\n *\n * The hub decides which model \"auto\" is and never tells the CLI — the policy\n * endpoint serves budget numbers (context window, output cap), not a name, so\n * there is nothing here that could display one. The entry the user sees is\n * \"Auto\", and the hub can move the underlying model without a CLI release.\n *\n * Providers must exist before the initial model is resolved, which happens\n * before any network round-trip could finish, so registration reads a policy\n * cache written the last time the hub was reachable:\n *\n * startup gate (already talks to the hub) -> refreshGatewayPolicy()\n * extension factory (synchronous) -> registerAutoProvider()\n *\n * The gate runs at every startup, so the cache is at most one session stale.\n * Entitlement is the hub's call: a 404 from the policy endpoint (feature off\n * for this account) deletes the cache and the next session has no Auto entry.\n */\n\nexport const AUTO_PROVIDER_ID = \"gitnexus\";\nexport const AUTO_MODEL_ID = \"auto\";\n\nexport interface GatewayPolicy {\n\tconfigured: boolean;\n\tcontextWindow: number;\n\tmaxTokens: number;\n\tusage?: { used: number; limit: number };\n}\n\nexport function gatewayCachePath(): string {\n\treturn join(dirname(gitNexusConfigPath()), \"gateway.json\");\n}\n\n/** Cached policy from the last successful refresh, or undefined. */\nexport function readGatewayCache(path: string = gatewayCachePath()): GatewayPolicy | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf8\")) as Partial<GatewayPolicy>;\n\t\tif (typeof parsed.contextWindow !== \"number\" || typeof parsed.maxTokens !== \"number\") return undefined;\n\t\treturn {\n\t\t\tconfigured: parsed.configured === true,\n\t\t\tcontextWindow: parsed.contextWindow,\n\t\t\tmaxTokens: parsed.maxTokens,\n\t\t\tusage: parsed.usage,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Ask the hub what auto mode looks like for this account and cache the answer.\n *\n * Never throws: auto mode is additive, and a hub outage at startup must not\n * cost the user their session. A definitive \"no\" (404: not entitled; 401/403:\n * bad credential) clears the cache; a transient failure keeps it, so a flaky\n * network does not flap the Auto entry in and out of the model list.\n */\nexport async function refreshGatewayPolicy(\n\t// No default: an explicit `undefined` must mean signed out, never \"read the\n\t// real config\" — a test passing undefined once sent a real token upstream.\n\tconfig: GitNexusConfig | undefined,\n\toptions: { fetchImpl?: typeof fetch; cachePath?: string; timeoutMs?: number } = {},\n): Promise<GatewayPolicy | undefined> {\n\tconst cachePath = options.cachePath ?? gatewayCachePath();\n\tif (!config) return undefined;\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\n\ttry {\n\t\tconst response = await fetchImpl(`${hubApiBase(config.hubUrl)}/llm/policy`, {\n\t\t\t// Device-bound tokens are rejected without the fingerprint headers the\n\t\t\t// login flow registered them with, so these mirror GitNexusClient.\n\t\t\theaders: {\n\t\t\t\tauthorization: `Bearer ${config.token}`,\n\t\t\t\taccept: \"application/json\",\n\t\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t\t},\n\t\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n\t\t});\n\t\tif (response.status === 404 || response.status === 401 || response.status === 403) {\n\t\t\trmSync(cachePath, { force: true });\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!response.ok) return readGatewayCache(cachePath);\n\n\t\tconst body = (await response.json()) as Partial<GatewayPolicy>;\n\t\tif (typeof body.contextWindow !== \"number\" || typeof body.maxTokens !== \"number\") {\n\t\t\treturn readGatewayCache(cachePath);\n\t\t}\n\t\tconst policy: GatewayPolicy = {\n\t\t\tconfigured: body.configured === true,\n\t\t\tcontextWindow: body.contextWindow,\n\t\t\tmaxTokens: body.maxTokens,\n\t\t\tusage: body.usage,\n\t\t};\n\t\tif (!existsSync(dirname(cachePath))) mkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });\n\t\twriteFileSync(cachePath, JSON.stringify(policy), { mode: 0o600 });\n\t\treturn policy;\n\t} catch {\n\t\treturn readGatewayCache(cachePath);\n\t}\n}\n\n/**\n * Register the Auto entry. Synchronous — called from the extension factory so\n * the provider exists before initial model resolution.\n *\n * No config, no cache, or a gateway with no upstream key all mean no\n * registration: an Auto entry that cannot serve a request is worse than none.\n */\nexport function registerAutoProvider(\n\tpi: ExtensionAPI,\n\tconfig: GitNexusConfig | undefined,\n\tpolicy: GatewayPolicy | undefined,\n): boolean {\n\tif (!config || !policy || !policy.configured) return false;\n\n\tpi.registerProvider(AUTO_PROVIDER_ID, {\n\t\tname: \"GitNexus\",\n\t\tbaseUrl: `${hubApiBase(config.hubUrl)}/llm`,\n\t\tapiKey: config.token,\n\t\tauthHeader: true,\n\t\t// Device-bound tokens 403 without the fingerprint they were minted with.\n\t\theaders: {\n\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t},\n\t\tapi: \"openai-completions\",\n\t\tmodels: [\n\t\t\t{\n\t\t\t\tid: AUTO_MODEL_ID,\n\t\t\t\tname: \"Auto\",\n\t\t\t\t// The hub may route to a reasoning model, but reasoning controls are\n\t\t\t\t// provider-specific and \"auto\" promises nothing about the provider —\n\t\t\t\t// so none are offered.\n\t\t\t\treasoning: false,\n\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t// Spend is metered hub-side against a monthly allowance; there is no\n\t\t\t\t// per-token price to show.\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\tcontextWindow: policy.contextWindow,\n\t\t\t\tmaxTokens: policy.maxTokens,\n\t\t\t},\n\t\t],\n\t});\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../src/extensions/gitnexus/gateway.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,aAAa,CAAC;AAGtE;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,MAAM,WAAW,aAAa;IAC7B,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D;AAaD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIzF;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAA2B,GAAG,aAAa,GAAG,SAAS,CAa7F;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAGzC,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChF,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAuCpC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CACnC,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,MAAM,EAAE,aAAa,GAAG,SAAS,GAC/B,OAAO,CAgCT","sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { type GitNexusConfig, gitNexusConfigPath } from \"./config.ts\";\nimport { hubApiBase } from \"./device-auth.ts\";\n\n/**\n * Auto mode: models served through the hub's LLM gateway.\n *\n * The hub decides which model \"auto\" is and never tells the CLI — the policy\n * endpoint serves budget numbers (context window, output cap), not a name, so\n * there is nothing here that could display one. The entry the user sees is\n * \"Auto\", and the hub can move the underlying model without a CLI release.\n *\n * Providers must exist before the initial model is resolved, which happens\n * before any network round-trip could finish, so registration reads a policy\n * cache written the last time the hub was reachable:\n *\n * startup gate (already talks to the hub) -> refreshGatewayPolicy()\n * extension factory (synchronous) -> registerAutoProvider()\n *\n * The gate runs at every startup, so the cache is at most one session stale.\n * Entitlement is the hub's call: a 404 from the policy endpoint (feature off\n * for this account) deletes the cache and the next session has no Auto entry.\n */\n\nexport const AUTO_PROVIDER_ID = \"gitnexus\";\nexport const AUTO_MODEL_ID = \"auto\";\n\nexport interface GatewayPolicy {\n\tconfigured: boolean;\n\tcontextWindow: number;\n\tmaxTokens: number;\n\tusage?: { used: number; limit: number; remaining?: number };\n}\n\nfunction parseUsage(value: unknown): GatewayPolicy[\"usage\"] {\n\tif (!value || typeof value !== \"object\") return undefined;\n\tconst usage = value as Record<string, unknown>;\n\tif (typeof usage.used !== \"number\" || typeof usage.limit !== \"number\") return undefined;\n\treturn {\n\t\tused: usage.used,\n\t\tlimit: usage.limit,\n\t\t...(typeof usage.remaining === \"number\" ? { remaining: usage.remaining } : {}),\n\t};\n}\n\nexport function formatCreditBalance(policy: GatewayPolicy | undefined): string | undefined {\n\tif (!policy?.usage) return undefined;\n\tconst remaining = policy.usage.remaining ?? Math.max(0, policy.usage.limit - policy.usage.used);\n\treturn `Nexus Credits: ${remaining.toLocaleString()} / ${policy.usage.limit.toLocaleString()}`;\n}\n\nexport function gatewayCachePath(): string {\n\treturn join(dirname(gitNexusConfigPath()), \"gateway.json\");\n}\n\n/** Cached policy from the last successful refresh, or undefined. */\nexport function readGatewayCache(path: string = gatewayCachePath()): GatewayPolicy | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf8\")) as Partial<GatewayPolicy>;\n\t\tif (typeof parsed.contextWindow !== \"number\" || typeof parsed.maxTokens !== \"number\") return undefined;\n\t\treturn {\n\t\t\tconfigured: parsed.configured === true,\n\t\t\tcontextWindow: parsed.contextWindow,\n\t\t\tmaxTokens: parsed.maxTokens,\n\t\t\tusage: parseUsage(parsed.usage),\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Ask the hub what auto mode looks like for this account and cache the answer.\n *\n * Never throws: auto mode is additive, and a hub outage at startup must not\n * cost the user their session. A definitive \"no\" (404: not entitled; 401/403:\n * bad credential) clears the cache; a transient failure keeps it, so a flaky\n * network does not flap the Auto entry in and out of the model list.\n */\nexport async function refreshGatewayPolicy(\n\t// No default: an explicit `undefined` must mean signed out, never \"read the\n\t// real config\" — a test passing undefined once sent a real token upstream.\n\tconfig: GitNexusConfig | undefined,\n\toptions: { fetchImpl?: typeof fetch; cachePath?: string; timeoutMs?: number } = {},\n): Promise<GatewayPolicy | undefined> {\n\tconst cachePath = options.cachePath ?? gatewayCachePath();\n\tif (!config) return undefined;\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\n\ttry {\n\t\tconst response = await fetchImpl(`${hubApiBase(config.hubUrl)}/llm/policy`, {\n\t\t\t// Device-bound tokens are rejected without the fingerprint headers the\n\t\t\t// login flow registered them with, so these mirror GitNexusClient.\n\t\t\theaders: {\n\t\t\t\tauthorization: `Bearer ${config.token}`,\n\t\t\t\taccept: \"application/json\",\n\t\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t\t},\n\t\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n\t\t});\n\t\tif (response.status === 404 || response.status === 401 || response.status === 403) {\n\t\t\trmSync(cachePath, { force: true });\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!response.ok) return readGatewayCache(cachePath);\n\n\t\tconst body = (await response.json()) as Partial<GatewayPolicy>;\n\t\tif (typeof body.contextWindow !== \"number\" || typeof body.maxTokens !== \"number\") {\n\t\t\treturn readGatewayCache(cachePath);\n\t\t}\n\t\tconst policy: GatewayPolicy = {\n\t\t\tconfigured: body.configured === true,\n\t\t\tcontextWindow: body.contextWindow,\n\t\t\tmaxTokens: body.maxTokens,\n\t\t\tusage: parseUsage(body.usage),\n\t\t};\n\t\tif (!existsSync(dirname(cachePath))) mkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });\n\t\twriteFileSync(cachePath, JSON.stringify(policy), { mode: 0o600 });\n\t\treturn policy;\n\t} catch {\n\t\treturn readGatewayCache(cachePath);\n\t}\n}\n\n/**\n * Register the Auto entry. Synchronous — called from the extension factory so\n * the provider exists before initial model resolution.\n *\n * No config, no cache, or a gateway with no upstream key all mean no\n * registration: an Auto entry that cannot serve a request is worse than none.\n */\nexport function registerAutoProvider(\n\tpi: ExtensionAPI,\n\tconfig: GitNexusConfig | undefined,\n\tpolicy: GatewayPolicy | undefined,\n): boolean {\n\tif (!config || !policy || !policy.configured) return false;\n\n\tpi.registerProvider(AUTO_PROVIDER_ID, {\n\t\tname: \"GitNexus\",\n\t\tbaseUrl: `${hubApiBase(config.hubUrl)}/llm`,\n\t\tapiKey: config.token,\n\t\tauthHeader: true,\n\t\t// Device-bound tokens 403 without the fingerprint they were minted with.\n\t\theaders: {\n\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t},\n\t\tapi: \"openai-completions\",\n\t\tmodels: [\n\t\t\t{\n\t\t\t\tid: AUTO_MODEL_ID,\n\t\t\t\tname: \"Auto\",\n\t\t\t\t// The hub may route to a reasoning model, but reasoning controls are\n\t\t\t\t// provider-specific and \"auto\" promises nothing about the provider —\n\t\t\t\t// so none are offered.\n\t\t\t\treasoning: false,\n\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t// Spend is metered hub-side against Nexus Credits; there is no\n\t\t\t\t// per-token or dollar price to show.\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\tcontextWindow: policy.contextWindow,\n\t\t\t\tmaxTokens: policy.maxTokens,\n\t\t\t},\n\t\t],\n\t});\n\treturn true;\n}\n"]}
@@ -23,6 +23,24 @@ import { hubApiBase } from "./device-auth.js";
23
23
  */
24
24
  export const AUTO_PROVIDER_ID = "gitnexus";
25
25
  export const AUTO_MODEL_ID = "auto";
26
+ function parseUsage(value) {
27
+ if (!value || typeof value !== "object")
28
+ return undefined;
29
+ const usage = value;
30
+ if (typeof usage.used !== "number" || typeof usage.limit !== "number")
31
+ return undefined;
32
+ return {
33
+ used: usage.used,
34
+ limit: usage.limit,
35
+ ...(typeof usage.remaining === "number" ? { remaining: usage.remaining } : {}),
36
+ };
37
+ }
38
+ export function formatCreditBalance(policy) {
39
+ if (!policy?.usage)
40
+ return undefined;
41
+ const remaining = policy.usage.remaining ?? Math.max(0, policy.usage.limit - policy.usage.used);
42
+ return `Nexus Credits: ${remaining.toLocaleString()} / ${policy.usage.limit.toLocaleString()}`;
43
+ }
26
44
  export function gatewayCachePath() {
27
45
  return join(dirname(gitNexusConfigPath()), "gateway.json");
28
46
  }
@@ -36,7 +54,7 @@ export function readGatewayCache(path = gatewayCachePath()) {
36
54
  configured: parsed.configured === true,
37
55
  contextWindow: parsed.contextWindow,
38
56
  maxTokens: parsed.maxTokens,
39
- usage: parsed.usage,
57
+ usage: parseUsage(parsed.usage),
40
58
  };
41
59
  }
42
60
  catch {
@@ -85,7 +103,7 @@ config, options = {}) {
85
103
  configured: body.configured === true,
86
104
  contextWindow: body.contextWindow,
87
105
  maxTokens: body.maxTokens,
88
- usage: body.usage,
106
+ usage: parseUsage(body.usage),
89
107
  };
90
108
  if (!existsSync(dirname(cachePath)))
91
109
  mkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });
@@ -126,8 +144,8 @@ export function registerAutoProvider(pi, config, policy) {
126
144
  // so none are offered.
127
145
  reasoning: false,
128
146
  input: ["text", "image"],
129
- // Spend is metered hub-side against a monthly allowance; there is no
130
- // per-token price to show.
147
+ // Spend is metered hub-side against Nexus Credits; there is no
148
+ // per-token or dollar price to show.
131
149
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
132
150
  contextWindow: policy.contextWindow,
133
151
  maxTokens: policy.maxTokens,
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/gateway.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { type GitNexusConfig, gitNexusConfigPath } from \"./config.ts\";\nimport { hubApiBase } from \"./device-auth.ts\";\n\n/**\n * Auto mode: models served through the hub's LLM gateway.\n *\n * The hub decides which model \"auto\" is and never tells the CLI — the policy\n * endpoint serves budget numbers (context window, output cap), not a name, so\n * there is nothing here that could display one. The entry the user sees is\n * \"Auto\", and the hub can move the underlying model without a CLI release.\n *\n * Providers must exist before the initial model is resolved, which happens\n * before any network round-trip could finish, so registration reads a policy\n * cache written the last time the hub was reachable:\n *\n * startup gate (already talks to the hub) -> refreshGatewayPolicy()\n * extension factory (synchronous) -> registerAutoProvider()\n *\n * The gate runs at every startup, so the cache is at most one session stale.\n * Entitlement is the hub's call: a 404 from the policy endpoint (feature off\n * for this account) deletes the cache and the next session has no Auto entry.\n */\n\nexport const AUTO_PROVIDER_ID = \"gitnexus\";\nexport const AUTO_MODEL_ID = \"auto\";\n\nexport interface GatewayPolicy {\n\tconfigured: boolean;\n\tcontextWindow: number;\n\tmaxTokens: number;\n\tusage?: { used: number; limit: number };\n}\n\nexport function gatewayCachePath(): string {\n\treturn join(dirname(gitNexusConfigPath()), \"gateway.json\");\n}\n\n/** Cached policy from the last successful refresh, or undefined. */\nexport function readGatewayCache(path: string = gatewayCachePath()): GatewayPolicy | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf8\")) as Partial<GatewayPolicy>;\n\t\tif (typeof parsed.contextWindow !== \"number\" || typeof parsed.maxTokens !== \"number\") return undefined;\n\t\treturn {\n\t\t\tconfigured: parsed.configured === true,\n\t\t\tcontextWindow: parsed.contextWindow,\n\t\t\tmaxTokens: parsed.maxTokens,\n\t\t\tusage: parsed.usage,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Ask the hub what auto mode looks like for this account and cache the answer.\n *\n * Never throws: auto mode is additive, and a hub outage at startup must not\n * cost the user their session. A definitive \"no\" (404: not entitled; 401/403:\n * bad credential) clears the cache; a transient failure keeps it, so a flaky\n * network does not flap the Auto entry in and out of the model list.\n */\nexport async function refreshGatewayPolicy(\n\t// No default: an explicit `undefined` must mean signed out, never \"read the\n\t// real config\" — a test passing undefined once sent a real token upstream.\n\tconfig: GitNexusConfig | undefined,\n\toptions: { fetchImpl?: typeof fetch; cachePath?: string; timeoutMs?: number } = {},\n): Promise<GatewayPolicy | undefined> {\n\tconst cachePath = options.cachePath ?? gatewayCachePath();\n\tif (!config) return undefined;\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\n\ttry {\n\t\tconst response = await fetchImpl(`${hubApiBase(config.hubUrl)}/llm/policy`, {\n\t\t\t// Device-bound tokens are rejected without the fingerprint headers the\n\t\t\t// login flow registered them with, so these mirror GitNexusClient.\n\t\t\theaders: {\n\t\t\t\tauthorization: `Bearer ${config.token}`,\n\t\t\t\taccept: \"application/json\",\n\t\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t\t},\n\t\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n\t\t});\n\t\tif (response.status === 404 || response.status === 401 || response.status === 403) {\n\t\t\trmSync(cachePath, { force: true });\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!response.ok) return readGatewayCache(cachePath);\n\n\t\tconst body = (await response.json()) as Partial<GatewayPolicy>;\n\t\tif (typeof body.contextWindow !== \"number\" || typeof body.maxTokens !== \"number\") {\n\t\t\treturn readGatewayCache(cachePath);\n\t\t}\n\t\tconst policy: GatewayPolicy = {\n\t\t\tconfigured: body.configured === true,\n\t\t\tcontextWindow: body.contextWindow,\n\t\t\tmaxTokens: body.maxTokens,\n\t\t\tusage: body.usage,\n\t\t};\n\t\tif (!existsSync(dirname(cachePath))) mkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });\n\t\twriteFileSync(cachePath, JSON.stringify(policy), { mode: 0o600 });\n\t\treturn policy;\n\t} catch {\n\t\treturn readGatewayCache(cachePath);\n\t}\n}\n\n/**\n * Register the Auto entry. Synchronous — called from the extension factory so\n * the provider exists before initial model resolution.\n *\n * No config, no cache, or a gateway with no upstream key all mean no\n * registration: an Auto entry that cannot serve a request is worse than none.\n */\nexport function registerAutoProvider(\n\tpi: ExtensionAPI,\n\tconfig: GitNexusConfig | undefined,\n\tpolicy: GatewayPolicy | undefined,\n): boolean {\n\tif (!config || !policy || !policy.configured) return false;\n\n\tpi.registerProvider(AUTO_PROVIDER_ID, {\n\t\tname: \"GitNexus\",\n\t\tbaseUrl: `${hubApiBase(config.hubUrl)}/llm`,\n\t\tapiKey: config.token,\n\t\tauthHeader: true,\n\t\t// Device-bound tokens 403 without the fingerprint they were minted with.\n\t\theaders: {\n\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t},\n\t\tapi: \"openai-completions\",\n\t\tmodels: [\n\t\t\t{\n\t\t\t\tid: AUTO_MODEL_ID,\n\t\t\t\tname: \"Auto\",\n\t\t\t\t// The hub may route to a reasoning model, but reasoning controls are\n\t\t\t\t// provider-specific and \"auto\" promises nothing about the provider —\n\t\t\t\t// so none are offered.\n\t\t\t\treasoning: false,\n\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t// Spend is metered hub-side against a monthly allowance; there is no\n\t\t\t\t// per-token price to show.\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\tcontextWindow: policy.contextWindow,\n\t\t\t\tmaxTokens: policy.maxTokens,\n\t\t\t},\n\t\t],\n\t});\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/gateway.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { type GitNexusConfig, gitNexusConfigPath } from \"./config.ts\";\nimport { hubApiBase } from \"./device-auth.ts\";\n\n/**\n * Auto mode: models served through the hub's LLM gateway.\n *\n * The hub decides which model \"auto\" is and never tells the CLI — the policy\n * endpoint serves budget numbers (context window, output cap), not a name, so\n * there is nothing here that could display one. The entry the user sees is\n * \"Auto\", and the hub can move the underlying model without a CLI release.\n *\n * Providers must exist before the initial model is resolved, which happens\n * before any network round-trip could finish, so registration reads a policy\n * cache written the last time the hub was reachable:\n *\n * startup gate (already talks to the hub) -> refreshGatewayPolicy()\n * extension factory (synchronous) -> registerAutoProvider()\n *\n * The gate runs at every startup, so the cache is at most one session stale.\n * Entitlement is the hub's call: a 404 from the policy endpoint (feature off\n * for this account) deletes the cache and the next session has no Auto entry.\n */\n\nexport const AUTO_PROVIDER_ID = \"gitnexus\";\nexport const AUTO_MODEL_ID = \"auto\";\n\nexport interface GatewayPolicy {\n\tconfigured: boolean;\n\tcontextWindow: number;\n\tmaxTokens: number;\n\tusage?: { used: number; limit: number; remaining?: number };\n}\n\nfunction parseUsage(value: unknown): GatewayPolicy[\"usage\"] {\n\tif (!value || typeof value !== \"object\") return undefined;\n\tconst usage = value as Record<string, unknown>;\n\tif (typeof usage.used !== \"number\" || typeof usage.limit !== \"number\") return undefined;\n\treturn {\n\t\tused: usage.used,\n\t\tlimit: usage.limit,\n\t\t...(typeof usage.remaining === \"number\" ? { remaining: usage.remaining } : {}),\n\t};\n}\n\nexport function formatCreditBalance(policy: GatewayPolicy | undefined): string | undefined {\n\tif (!policy?.usage) return undefined;\n\tconst remaining = policy.usage.remaining ?? Math.max(0, policy.usage.limit - policy.usage.used);\n\treturn `Nexus Credits: ${remaining.toLocaleString()} / ${policy.usage.limit.toLocaleString()}`;\n}\n\nexport function gatewayCachePath(): string {\n\treturn join(dirname(gitNexusConfigPath()), \"gateway.json\");\n}\n\n/** Cached policy from the last successful refresh, or undefined. */\nexport function readGatewayCache(path: string = gatewayCachePath()): GatewayPolicy | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(path, \"utf8\")) as Partial<GatewayPolicy>;\n\t\tif (typeof parsed.contextWindow !== \"number\" || typeof parsed.maxTokens !== \"number\") return undefined;\n\t\treturn {\n\t\t\tconfigured: parsed.configured === true,\n\t\t\tcontextWindow: parsed.contextWindow,\n\t\t\tmaxTokens: parsed.maxTokens,\n\t\t\tusage: parseUsage(parsed.usage),\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Ask the hub what auto mode looks like for this account and cache the answer.\n *\n * Never throws: auto mode is additive, and a hub outage at startup must not\n * cost the user their session. A definitive \"no\" (404: not entitled; 401/403:\n * bad credential) clears the cache; a transient failure keeps it, so a flaky\n * network does not flap the Auto entry in and out of the model list.\n */\nexport async function refreshGatewayPolicy(\n\t// No default: an explicit `undefined` must mean signed out, never \"read the\n\t// real config\" — a test passing undefined once sent a real token upstream.\n\tconfig: GitNexusConfig | undefined,\n\toptions: { fetchImpl?: typeof fetch; cachePath?: string; timeoutMs?: number } = {},\n): Promise<GatewayPolicy | undefined> {\n\tconst cachePath = options.cachePath ?? gatewayCachePath();\n\tif (!config) return undefined;\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\n\ttry {\n\t\tconst response = await fetchImpl(`${hubApiBase(config.hubUrl)}/llm/policy`, {\n\t\t\t// Device-bound tokens are rejected without the fingerprint headers the\n\t\t\t// login flow registered them with, so these mirror GitNexusClient.\n\t\t\theaders: {\n\t\t\t\tauthorization: `Bearer ${config.token}`,\n\t\t\t\taccept: \"application/json\",\n\t\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t\t},\n\t\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? 10_000),\n\t\t});\n\t\tif (response.status === 404 || response.status === 401 || response.status === 403) {\n\t\t\trmSync(cachePath, { force: true });\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!response.ok) return readGatewayCache(cachePath);\n\n\t\tconst body = (await response.json()) as Partial<GatewayPolicy>;\n\t\tif (typeof body.contextWindow !== \"number\" || typeof body.maxTokens !== \"number\") {\n\t\t\treturn readGatewayCache(cachePath);\n\t\t}\n\t\tconst policy: GatewayPolicy = {\n\t\t\tconfigured: body.configured === true,\n\t\t\tcontextWindow: body.contextWindow,\n\t\t\tmaxTokens: body.maxTokens,\n\t\t\tusage: parseUsage(body.usage),\n\t\t};\n\t\tif (!existsSync(dirname(cachePath))) mkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });\n\t\twriteFileSync(cachePath, JSON.stringify(policy), { mode: 0o600 });\n\t\treturn policy;\n\t} catch {\n\t\treturn readGatewayCache(cachePath);\n\t}\n}\n\n/**\n * Register the Auto entry. Synchronous — called from the extension factory so\n * the provider exists before initial model resolution.\n *\n * No config, no cache, or a gateway with no upstream key all mean no\n * registration: an Auto entry that cannot serve a request is worse than none.\n */\nexport function registerAutoProvider(\n\tpi: ExtensionAPI,\n\tconfig: GitNexusConfig | undefined,\n\tpolicy: GatewayPolicy | undefined,\n): boolean {\n\tif (!config || !policy || !policy.configured) return false;\n\n\tpi.registerProvider(AUTO_PROVIDER_ID, {\n\t\tname: \"GitNexus\",\n\t\tbaseUrl: `${hubApiBase(config.hubUrl)}/llm`,\n\t\tapiKey: config.token,\n\t\tauthHeader: true,\n\t\t// Device-bound tokens 403 without the fingerprint they were minted with.\n\t\theaders: {\n\t\t\t...(config.deviceFingerprint ? { \"x-device-fingerprint\": config.deviceFingerprint } : {}),\n\t\t\t...(config.deviceName ? { \"x-device-name\": config.deviceName } : {}),\n\t\t},\n\t\tapi: \"openai-completions\",\n\t\tmodels: [\n\t\t\t{\n\t\t\t\tid: AUTO_MODEL_ID,\n\t\t\t\tname: \"Auto\",\n\t\t\t\t// The hub may route to a reasoning model, but reasoning controls are\n\t\t\t\t// provider-specific and \"auto\" promises nothing about the provider —\n\t\t\t\t// so none are offered.\n\t\t\t\treasoning: false,\n\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t// Spend is metered hub-side against Nexus Credits; there is no\n\t\t\t\t// per-token or dollar price to show.\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\tcontextWindow: policy.contextWindow,\n\t\t\t\tmaxTokens: policy.maxTokens,\n\t\t\t},\n\t\t],\n\t});\n\treturn true;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/gitnexus/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAqBnE,2EAA2E;AAC3E,wBAAgB,wBAAwB,CACvC,SAAS,GAAE,MAAwB,EACnC,UAAU,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAoB,GAChD,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAuKhE","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { graphRailStore } from \"../../core/graph-rail-store.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport { registerAugmentedGrep } from \"./augment.ts\";\nimport { registerChangeTracking } from \"./changes.ts\";\nimport { GitNexusClient, GitNexusClientError } from \"./client.ts\";\nimport { DEFAULT_HUB_URL, resolveGitNexusConfig, saveGitNexusConfig } from \"./config.ts\";\nimport { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from \"./device-auth.ts\";\nimport { readGatewayCache, registerAutoProvider } from \"./gateway.ts\";\nimport { spawnObservatoryFetch } from \"./observatory.ts\";\nimport { buildGitNexusPrompt } from \"./prompt.ts\";\nimport { withGitNexusRenderer } from \"./render.ts\";\nimport {\n\tgitRemoteSlug,\n\ttype IndexedRepo,\n\tmatchCurrentRepo,\n\tparseRepoInventory,\n\ttype RepoInventory,\n} from \"./resolve.ts\";\nimport { createGitNexusTools } from \"./tools.ts\";\n\n/** Resolve workflow skills in source mode and bundled dist/cli.js mode. */\nexport function resolveGitNexusSkillsDir(\n\tmoduleUrl: string = import.meta.url,\n\tpathExists: (path: string) => boolean = existsSync,\n): string | undefined {\n\tconst candidates = [\n\t\tfileURLToPath(new URL(\"./skills/\", moduleUrl)),\n\t\tfileURLToPath(new URL(\"./extensions/gitnexus/skills/\", moduleUrl)),\n\t];\n\treturn candidates.find(pathExists);\n}\n\n/**\n * GitNexus built-in extension: connects nexus-cli to the GitNexus hub.\n *\n * - session_start: resolve config + repo inventory, register the six graph\n * tools and the augmented grep. No token / hub down / repo unindexed all\n * degrade to a plain coding agent (graph is additive, never load-bearing).\n * - before_agent_start: append the GitNexus guidance block (ported from the\n * CLAUDE.md generator) to the system prompt.\n */\nexport default function gitnexusExtension(pi: ExtensionAPI): void {\n\tlet inventory: RepoInventory | undefined;\n\tlet current: IndexedRepo | undefined;\n\tlet activeClient: GitNexusClient | undefined;\n\tlet toolsRegistered = false;\n\tlet startupNotice: string | undefined;\n\tlet loginRequired = false;\n\n\tconst cwd = process.cwd();\n\n\t// Auto mode must also register at factory time: the initial model is\n\t// resolved before session_start fires, and a provider that appears after\n\t// that is invisible to it. Reads the policy cache the startup gate wrote.\n\tregisterAutoProvider(pi, resolveGitNexusConfig(), readGatewayCache());\n\n\t// Built-in tool overrides must happen at factory time (like the bash-spawn-hook\n\t// example) — session_start registrations only add NEW names reliably. The wrapper\n\t// behaves as plain grep until connect() provides a client + current repo.\n\tregisterAugmentedGrep(\n\t\tpi,\n\t\tcwd,\n\t\t() => activeClient,\n\t\t() => current?.name,\n\t);\n\tregisterChangeTracking(pi, cwd);\n\n\tasync function connect(): Promise<void> {\n\t\tinventory = undefined;\n\t\tcurrent = undefined;\n\t\tactiveClient = undefined;\n\t\tstartupNotice = undefined;\n\t\tloginRequired = false;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) return;\n\t\tconst client = new GitNexusClient(config);\n\t\ttry {\n\t\t\tconst listResult = await client.callTool(\"list_repos\", {});\n\t\t\tinventory = parseRepoInventory(GitNexusClient.text(listResult));\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof GitNexusClientError ? error.message : String(error);\n\t\t\tif (error instanceof GitNexusClientError && error.kind === \"auth\") {\n\t\t\t\tloginRequired = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstartupNotice = `GitNexus unavailable: ${reason}`;\n\t\t\treturn;\n\t\t}\n\n\t\tcurrent = matchCurrentRepo(inventory, gitRemoteSlug(cwd));\n\t\tactiveClient = client;\n\t\tgraphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));\n\t\t// Observatory (community map) rides a detached subprocess + temp-file\n\t\t// handoff — in-process hub calls made after startup can starve in some\n\t\t// environments, a fresh process never does. The UI picks the file up\n\t\t// lazily via tryLoadObservatoryCache.\n\t\tif (current) spawnObservatoryFetch(config, current.name);\n\t\tgraphRailStore.setRepo(\n\t\t\tcurrent\n\t\t\t\t? {\n\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\tsymbols: current.symbols,\n\t\t\t\t\t\trelationships: current.relationships,\n\t\t\t\t\t\tindexedAt: current.indexedAt,\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tname: \"\",\n\t\t\t\t\t\tsymbols: \"0\",\n\t\t\t\t\t\trelationships: \"0\",\n\t\t\t\t\t\tindexedAt: \"\",\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t},\n\t\t\tcurrent !== undefined,\n\t\t);\n\t\tif (!toolsRegistered) {\n\t\t\tconst ctx = { client, currentRepo: () => current?.name, cwd };\n\t\t\tfor (const tool of createGitNexusTools(ctx)) pi.registerTool(withGitNexusRenderer(tool));\n\t\t\ttoolsRegistered = true;\n\t\t}\n\n\t\tstartupNotice = current\n\t\t\t? `GitNexus: connected — ${current.name} (${current.symbols} symbols, indexed ${current.indexedAt}), ${inventory.repos.length} repos available.`\n\t\t\t: `GitNexus: connected — current directory is not indexed; ${inventory.repos.length} indexed repos remain queryable. Index this repo from the Hub dashboard to unlock local graph context.`;\n\t}\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tawait connect();\n\t\tif (startupNotice) ctx.ui.notify(startupNotice, inventory ? \"info\" : \"warning\");\n\t});\n\n\t// Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,\n\t// refactoring, pr-review, guide) — same SKILL.md content the Claude plugin\n\t// ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.\n\t// Skipped entirely when the user already has gitnexus skills (project or\n\t// global) so the startup screen doesn't report shadowed duplicates.\n\tpi.on(\"resources_discover\", (event) => {\n\t\tconst hasOwnGitnexusSkills =\n\t\t\texistsSync(join(event.cwd, \".agents\", \"skills\", \"gitnexus\")) ||\n\t\t\texistsSync(join(homedir(), \".agents\", \"skills\", \"gitnexus-debugging\"));\n\t\tif (hasOwnGitnexusSkills) return;\n\t\tconst skillsDir = resolveGitNexusSkillsDir();\n\t\tif (!skillsDir) return;\n\t\treturn { skillPaths: [skillsDir] };\n\t});\n\n\tpi.on(\"before_agent_start\", (event) => {\n\t\tif (!inventory) return;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n\\n${buildGitNexusPrompt(inventory, current)}` };\n\t});\n\n\tpi.registerCommand(\"gitnexus-login\", {\n\t\tdescription: \"Sign in to GitNexus (implementation of /login → GitNexus account; accepts a pasted token)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst hubUrl = process.env.GITNEXUS_HUB_URL ?? DEFAULT_HUB_URL;\n\t\t\tconst pasted = args.trim();\n\n\t\t\t// Pasting a token stays supported for CI and headless installs.\n\t\t\tif (pasted) {\n\t\t\t\tawait new GitNexusClient({ hubUrl, token: pasted }).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig({ hubUrl, token: pasted });\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`GitNexus token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst deviceName = defaultDeviceName();\n\t\t\t\tconst fingerprint = deviceFingerprint();\n\t\t\t\tconst start = await startDeviceAuth(hubUrl, { deviceName, deviceFingerprint: fingerprint });\n\t\t\t\tconst link = start.verificationUrlComplete ?? start.verificationUrl;\n\t\t\t\t// The link carries the code, so an opened browser needs no typing.\n\t\t\t\t// Print it too: the launcher is best effort and can be headless.\n\t\t\t\tctx.ui.notify(`Code ${start.userCode} — opening ${link}`, \"info\");\n\t\t\t\topenBrowser(link);\n\n\t\t\t\tconst result = await pollDeviceAuth(hubUrl, start);\n\t\t\t\tconst config = {\n\t\t\t\t\thubUrl: result.hubUrl,\n\t\t\t\t\ttoken: result.token,\n\t\t\t\t\tdeviceFingerprint: fingerprint,\n\t\t\t\t\tdeviceName,\n\t\t\t\t};\n\t\t\t\tawait new GitNexusClient(config).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig(config);\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`Signed in. Token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-status\", {\n\t\tdescription: \"Show GitNexus connection status\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (!inventory) {\n\t\t\t\tconst message = loginRequired\n\t\t\t\t\t? \"GitNexus session expired. Run /login to sign in again.\"\n\t\t\t\t\t: (startupNotice ?? \"GitNexus: not signed in. Run /login.\");\n\t\t\t\tctx.ui.notify(message, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst repoLine = current ? `current repo: ${current.name}` : \"current repo: not indexed\";\n\t\t\tctx.ui.notify(`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}`, \"info\");\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/gitnexus/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAqBnE,2EAA2E;AAC3E,wBAAgB,wBAAwB,CACvC,SAAS,GAAE,MAAwB,EACnC,UAAU,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAoB,GAChD,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA2LhE","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { graphRailStore } from \"../../core/graph-rail-store.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport { registerAugmentedGrep } from \"./augment.ts\";\nimport { registerChangeTracking } from \"./changes.ts\";\nimport { GitNexusClient, GitNexusClientError } from \"./client.ts\";\nimport { DEFAULT_HUB_URL, resolveGitNexusConfig, saveGitNexusConfig } from \"./config.ts\";\nimport { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from \"./device-auth.ts\";\nimport { formatCreditBalance, readGatewayCache, refreshGatewayPolicy, registerAutoProvider } from \"./gateway.ts\";\nimport { spawnObservatoryFetch } from \"./observatory.ts\";\nimport { buildGitNexusPrompt } from \"./prompt.ts\";\nimport { withGitNexusRenderer } from \"./render.ts\";\nimport {\n\tgitRemoteSlug,\n\ttype IndexedRepo,\n\tmatchCurrentRepo,\n\tparseRepoInventory,\n\ttype RepoInventory,\n} from \"./resolve.ts\";\nimport { createGitNexusTools } from \"./tools.ts\";\n\n/** Resolve workflow skills in source mode and bundled dist/cli.js mode. */\nexport function resolveGitNexusSkillsDir(\n\tmoduleUrl: string = import.meta.url,\n\tpathExists: (path: string) => boolean = existsSync,\n): string | undefined {\n\tconst candidates = [\n\t\tfileURLToPath(new URL(\"./skills/\", moduleUrl)),\n\t\tfileURLToPath(new URL(\"./extensions/gitnexus/skills/\", moduleUrl)),\n\t];\n\treturn candidates.find(pathExists);\n}\n\n/**\n * GitNexus built-in extension: connects nexus-cli to the GitNexus hub.\n *\n * - session_start: resolve config + repo inventory, register the six graph\n * tools and the augmented grep. No token / hub down / repo unindexed all\n * degrade to a plain coding agent (graph is additive, never load-bearing).\n * - before_agent_start: append the GitNexus guidance block (ported from the\n * CLAUDE.md generator) to the system prompt.\n */\nexport default function gitnexusExtension(pi: ExtensionAPI): void {\n\tlet inventory: RepoInventory | undefined;\n\tlet current: IndexedRepo | undefined;\n\tlet activeClient: GitNexusClient | undefined;\n\tlet toolsRegistered = false;\n\tlet startupNotice: string | undefined;\n\tlet loginRequired = false;\n\n\tconst cwd = process.cwd();\n\n\t// Auto mode must also register at factory time: the initial model is\n\t// resolved before session_start fires, and a provider that appears after\n\t// that is invisible to it. Reads the policy cache the startup gate wrote.\n\tlet gatewayPolicy = readGatewayCache();\n\tregisterAutoProvider(pi, resolveGitNexusConfig(), gatewayPolicy);\n\n\tfunction updateCreditStatus(ctx: { ui: { setStatus(key: string, text: string | undefined): void } }): void {\n\t\tctx.ui.setStatus(\"nexus-credits\", formatCreditBalance(gatewayPolicy));\n\t}\n\n\t// Built-in tool overrides must happen at factory time (like the bash-spawn-hook\n\t// example) — session_start registrations only add NEW names reliably. The wrapper\n\t// behaves as plain grep until connect() provides a client + current repo.\n\tregisterAugmentedGrep(\n\t\tpi,\n\t\tcwd,\n\t\t() => activeClient,\n\t\t() => current?.name,\n\t);\n\tregisterChangeTracking(pi, cwd);\n\n\tasync function connect(): Promise<void> {\n\t\tinventory = undefined;\n\t\tcurrent = undefined;\n\t\tactiveClient = undefined;\n\t\tstartupNotice = undefined;\n\t\tloginRequired = false;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) return;\n\t\tconst client = new GitNexusClient(config);\n\t\ttry {\n\t\t\tconst listResult = await client.callTool(\"list_repos\", {});\n\t\t\tinventory = parseRepoInventory(GitNexusClient.text(listResult));\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof GitNexusClientError ? error.message : String(error);\n\t\t\tif (error instanceof GitNexusClientError && error.kind === \"auth\") {\n\t\t\t\tloginRequired = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstartupNotice = `GitNexus unavailable: ${reason}`;\n\t\t\treturn;\n\t\t}\n\n\t\tcurrent = matchCurrentRepo(inventory, gitRemoteSlug(cwd));\n\t\tactiveClient = client;\n\t\tgraphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));\n\t\t// Observatory (community map) rides a detached subprocess + temp-file\n\t\t// handoff — in-process hub calls made after startup can starve in some\n\t\t// environments, a fresh process never does. The UI picks the file up\n\t\t// lazily via tryLoadObservatoryCache.\n\t\tif (current) spawnObservatoryFetch(config, current.name);\n\t\tgraphRailStore.setRepo(\n\t\t\tcurrent\n\t\t\t\t? {\n\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\tsymbols: current.symbols,\n\t\t\t\t\t\trelationships: current.relationships,\n\t\t\t\t\t\tindexedAt: current.indexedAt,\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tname: \"\",\n\t\t\t\t\t\tsymbols: \"0\",\n\t\t\t\t\t\trelationships: \"0\",\n\t\t\t\t\t\tindexedAt: \"\",\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t},\n\t\t\tcurrent !== undefined,\n\t\t);\n\t\tif (!toolsRegistered) {\n\t\t\tconst ctx = { client, currentRepo: () => current?.name, cwd };\n\t\t\tfor (const tool of createGitNexusTools(ctx)) pi.registerTool(withGitNexusRenderer(tool));\n\t\t\ttoolsRegistered = true;\n\t\t}\n\n\t\tstartupNotice = current\n\t\t\t? `GitNexus: connected — ${current.name} (${current.symbols} symbols, indexed ${current.indexedAt}), ${inventory.repos.length} repos available.`\n\t\t\t: `GitNexus: connected — current directory is not indexed; ${inventory.repos.length} indexed repos remain queryable. Index this repo from the Hub dashboard to unlock local graph context.`;\n\t}\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tawait connect();\n\t\tupdateCreditStatus(ctx);\n\t\tif (startupNotice) ctx.ui.notify(startupNotice, inventory ? \"info\" : \"warning\");\n\t});\n\n\tpi.on(\"agent_settled\", async (_event, ctx) => {\n\t\tif (!gatewayPolicy || ctx.model?.provider !== \"gitnexus\") return;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\tupdateCreditStatus(ctx);\n\t});\n\n\t// Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,\n\t// refactoring, pr-review, guide) — same SKILL.md content the Claude plugin\n\t// ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.\n\t// Skipped entirely when the user already has gitnexus skills (project or\n\t// global) so the startup screen doesn't report shadowed duplicates.\n\tpi.on(\"resources_discover\", (event) => {\n\t\tconst hasOwnGitnexusSkills =\n\t\t\texistsSync(join(event.cwd, \".agents\", \"skills\", \"gitnexus\")) ||\n\t\t\texistsSync(join(homedir(), \".agents\", \"skills\", \"gitnexus-debugging\"));\n\t\tif (hasOwnGitnexusSkills) return;\n\t\tconst skillsDir = resolveGitNexusSkillsDir();\n\t\tif (!skillsDir) return;\n\t\treturn { skillPaths: [skillsDir] };\n\t});\n\n\tpi.on(\"before_agent_start\", (event) => {\n\t\tif (!inventory) return;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n\\n${buildGitNexusPrompt(inventory, current)}` };\n\t});\n\n\tpi.registerCommand(\"gitnexus-login\", {\n\t\tdescription: \"Sign in to GitNexus (implementation of /login → GitNexus account; accepts a pasted token)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst hubUrl = process.env.GITNEXUS_HUB_URL ?? DEFAULT_HUB_URL;\n\t\t\tconst pasted = args.trim();\n\n\t\t\t// Pasting a token stays supported for CI and headless installs.\n\t\t\tif (pasted) {\n\t\t\t\tawait new GitNexusClient({ hubUrl, token: pasted }).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig({ hubUrl, token: pasted });\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`GitNexus token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst deviceName = defaultDeviceName();\n\t\t\t\tconst fingerprint = deviceFingerprint();\n\t\t\t\tconst start = await startDeviceAuth(hubUrl, { deviceName, deviceFingerprint: fingerprint });\n\t\t\t\tconst link = start.verificationUrlComplete ?? start.verificationUrl;\n\t\t\t\t// The link carries the code, so an opened browser needs no typing.\n\t\t\t\t// Print it too: the launcher is best effort and can be headless.\n\t\t\t\tctx.ui.notify(`Code ${start.userCode} — opening ${link}`, \"info\");\n\t\t\t\topenBrowser(link);\n\n\t\t\t\tconst result = await pollDeviceAuth(hubUrl, start);\n\t\t\t\tconst config = {\n\t\t\t\t\thubUrl: result.hubUrl,\n\t\t\t\t\ttoken: result.token,\n\t\t\t\t\tdeviceFingerprint: fingerprint,\n\t\t\t\t\tdeviceName,\n\t\t\t\t};\n\t\t\t\tawait new GitNexusClient(config).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig(config);\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`Signed in. Token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-status\", {\n\t\tdescription: \"Show GitNexus connection status\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tconst config = resolveGitNexusConfig();\n\t\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\t\tupdateCreditStatus(ctx);\n\t\t\tif (!inventory) {\n\t\t\t\tconst message = loginRequired\n\t\t\t\t\t? \"GitNexus session expired. Run /login to sign in again.\"\n\t\t\t\t\t: (startupNotice ?? \"GitNexus: not signed in. Run /login.\");\n\t\t\t\tctx.ui.notify(message, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst repoLine = current ? `current repo: ${current.name}` : \"current repo: not indexed\";\n\t\t\tconst creditLine = formatCreditBalance(gatewayPolicy);\n\t\t\tctx.ui.notify(\n\t\t\t\t`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}${creditLine ? `, ${creditLine}` : \"\"}`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n}\n"]}
@@ -9,7 +9,7 @@ import { registerChangeTracking } from "./changes.js";
9
9
  import { GitNexusClient, GitNexusClientError } from "./client.js";
10
10
  import { DEFAULT_HUB_URL, resolveGitNexusConfig, saveGitNexusConfig } from "./config.js";
11
11
  import { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from "./device-auth.js";
12
- import { readGatewayCache, registerAutoProvider } from "./gateway.js";
12
+ import { formatCreditBalance, readGatewayCache, refreshGatewayPolicy, registerAutoProvider } from "./gateway.js";
13
13
  import { spawnObservatoryFetch } from "./observatory.js";
14
14
  import { buildGitNexusPrompt } from "./prompt.js";
15
15
  import { withGitNexusRenderer } from "./render.js";
@@ -43,7 +43,11 @@ export default function gitnexusExtension(pi) {
43
43
  // Auto mode must also register at factory time: the initial model is
44
44
  // resolved before session_start fires, and a provider that appears after
45
45
  // that is invisible to it. Reads the policy cache the startup gate wrote.
46
- registerAutoProvider(pi, resolveGitNexusConfig(), readGatewayCache());
46
+ let gatewayPolicy = readGatewayCache();
47
+ registerAutoProvider(pi, resolveGitNexusConfig(), gatewayPolicy);
48
+ function updateCreditStatus(ctx) {
49
+ ctx.ui.setStatus("nexus-credits", formatCreditBalance(gatewayPolicy));
50
+ }
47
51
  // Built-in tool overrides must happen at factory time (like the bash-spawn-hook
48
52
  // example) — session_start registrations only add NEW names reliably. The wrapper
49
53
  // behaves as plain grep until connect() provides a client + current repo.
@@ -108,9 +112,18 @@ export default function gitnexusExtension(pi) {
108
112
  }
109
113
  pi.on("session_start", async (_event, ctx) => {
110
114
  await connect();
115
+ updateCreditStatus(ctx);
111
116
  if (startupNotice)
112
117
  ctx.ui.notify(startupNotice, inventory ? "info" : "warning");
113
118
  });
119
+ pi.on("agent_settled", async (_event, ctx) => {
120
+ if (!gatewayPolicy || ctx.model?.provider !== "gitnexus")
121
+ return;
122
+ const config = resolveGitNexusConfig();
123
+ if (config)
124
+ gatewayPolicy = await refreshGatewayPolicy(config);
125
+ updateCreditStatus(ctx);
126
+ });
114
127
  // Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,
115
128
  // refactoring, pr-review, guide) — same SKILL.md content the Claude plugin
116
129
  // ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.
@@ -174,6 +187,10 @@ export default function gitnexusExtension(pi) {
174
187
  pi.registerCommand("gitnexus-status", {
175
188
  description: "Show GitNexus connection status",
176
189
  handler: async (_args, ctx) => {
190
+ const config = resolveGitNexusConfig();
191
+ if (config)
192
+ gatewayPolicy = await refreshGatewayPolicy(config);
193
+ updateCreditStatus(ctx);
177
194
  if (!inventory) {
178
195
  const message = loginRequired
179
196
  ? "GitNexus session expired. Run /login to sign in again."
@@ -182,7 +199,8 @@ export default function gitnexusExtension(pi) {
182
199
  return;
183
200
  }
184
201
  const repoLine = current ? `current repo: ${current.name}` : "current repo: not indexed";
185
- ctx.ui.notify(`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}`, "info");
202
+ const creditLine = formatCreditBalance(gatewayPolicy);
203
+ ctx.ui.notify(`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}${creditLine ? `, ${creditLine}` : ""}`, "info");
186
204
  },
187
205
  });
188
206
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { graphRailStore } from \"../../core/graph-rail-store.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport { registerAugmentedGrep } from \"./augment.ts\";\nimport { registerChangeTracking } from \"./changes.ts\";\nimport { GitNexusClient, GitNexusClientError } from \"./client.ts\";\nimport { DEFAULT_HUB_URL, resolveGitNexusConfig, saveGitNexusConfig } from \"./config.ts\";\nimport { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from \"./device-auth.ts\";\nimport { readGatewayCache, registerAutoProvider } from \"./gateway.ts\";\nimport { spawnObservatoryFetch } from \"./observatory.ts\";\nimport { buildGitNexusPrompt } from \"./prompt.ts\";\nimport { withGitNexusRenderer } from \"./render.ts\";\nimport {\n\tgitRemoteSlug,\n\ttype IndexedRepo,\n\tmatchCurrentRepo,\n\tparseRepoInventory,\n\ttype RepoInventory,\n} from \"./resolve.ts\";\nimport { createGitNexusTools } from \"./tools.ts\";\n\n/** Resolve workflow skills in source mode and bundled dist/cli.js mode. */\nexport function resolveGitNexusSkillsDir(\n\tmoduleUrl: string = import.meta.url,\n\tpathExists: (path: string) => boolean = existsSync,\n): string | undefined {\n\tconst candidates = [\n\t\tfileURLToPath(new URL(\"./skills/\", moduleUrl)),\n\t\tfileURLToPath(new URL(\"./extensions/gitnexus/skills/\", moduleUrl)),\n\t];\n\treturn candidates.find(pathExists);\n}\n\n/**\n * GitNexus built-in extension: connects nexus-cli to the GitNexus hub.\n *\n * - session_start: resolve config + repo inventory, register the six graph\n * tools and the augmented grep. No token / hub down / repo unindexed all\n * degrade to a plain coding agent (graph is additive, never load-bearing).\n * - before_agent_start: append the GitNexus guidance block (ported from the\n * CLAUDE.md generator) to the system prompt.\n */\nexport default function gitnexusExtension(pi: ExtensionAPI): void {\n\tlet inventory: RepoInventory | undefined;\n\tlet current: IndexedRepo | undefined;\n\tlet activeClient: GitNexusClient | undefined;\n\tlet toolsRegistered = false;\n\tlet startupNotice: string | undefined;\n\tlet loginRequired = false;\n\n\tconst cwd = process.cwd();\n\n\t// Auto mode must also register at factory time: the initial model is\n\t// resolved before session_start fires, and a provider that appears after\n\t// that is invisible to it. Reads the policy cache the startup gate wrote.\n\tregisterAutoProvider(pi, resolveGitNexusConfig(), readGatewayCache());\n\n\t// Built-in tool overrides must happen at factory time (like the bash-spawn-hook\n\t// example) — session_start registrations only add NEW names reliably. The wrapper\n\t// behaves as plain grep until connect() provides a client + current repo.\n\tregisterAugmentedGrep(\n\t\tpi,\n\t\tcwd,\n\t\t() => activeClient,\n\t\t() => current?.name,\n\t);\n\tregisterChangeTracking(pi, cwd);\n\n\tasync function connect(): Promise<void> {\n\t\tinventory = undefined;\n\t\tcurrent = undefined;\n\t\tactiveClient = undefined;\n\t\tstartupNotice = undefined;\n\t\tloginRequired = false;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) return;\n\t\tconst client = new GitNexusClient(config);\n\t\ttry {\n\t\t\tconst listResult = await client.callTool(\"list_repos\", {});\n\t\t\tinventory = parseRepoInventory(GitNexusClient.text(listResult));\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof GitNexusClientError ? error.message : String(error);\n\t\t\tif (error instanceof GitNexusClientError && error.kind === \"auth\") {\n\t\t\t\tloginRequired = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstartupNotice = `GitNexus unavailable: ${reason}`;\n\t\t\treturn;\n\t\t}\n\n\t\tcurrent = matchCurrentRepo(inventory, gitRemoteSlug(cwd));\n\t\tactiveClient = client;\n\t\tgraphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));\n\t\t// Observatory (community map) rides a detached subprocess + temp-file\n\t\t// handoff — in-process hub calls made after startup can starve in some\n\t\t// environments, a fresh process never does. The UI picks the file up\n\t\t// lazily via tryLoadObservatoryCache.\n\t\tif (current) spawnObservatoryFetch(config, current.name);\n\t\tgraphRailStore.setRepo(\n\t\t\tcurrent\n\t\t\t\t? {\n\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\tsymbols: current.symbols,\n\t\t\t\t\t\trelationships: current.relationships,\n\t\t\t\t\t\tindexedAt: current.indexedAt,\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tname: \"\",\n\t\t\t\t\t\tsymbols: \"0\",\n\t\t\t\t\t\trelationships: \"0\",\n\t\t\t\t\t\tindexedAt: \"\",\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t},\n\t\t\tcurrent !== undefined,\n\t\t);\n\t\tif (!toolsRegistered) {\n\t\t\tconst ctx = { client, currentRepo: () => current?.name, cwd };\n\t\t\tfor (const tool of createGitNexusTools(ctx)) pi.registerTool(withGitNexusRenderer(tool));\n\t\t\ttoolsRegistered = true;\n\t\t}\n\n\t\tstartupNotice = current\n\t\t\t? `GitNexus: connected — ${current.name} (${current.symbols} symbols, indexed ${current.indexedAt}), ${inventory.repos.length} repos available.`\n\t\t\t: `GitNexus: connected — current directory is not indexed; ${inventory.repos.length} indexed repos remain queryable. Index this repo from the Hub dashboard to unlock local graph context.`;\n\t}\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tawait connect();\n\t\tif (startupNotice) ctx.ui.notify(startupNotice, inventory ? \"info\" : \"warning\");\n\t});\n\n\t// Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,\n\t// refactoring, pr-review, guide) — same SKILL.md content the Claude plugin\n\t// ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.\n\t// Skipped entirely when the user already has gitnexus skills (project or\n\t// global) so the startup screen doesn't report shadowed duplicates.\n\tpi.on(\"resources_discover\", (event) => {\n\t\tconst hasOwnGitnexusSkills =\n\t\t\texistsSync(join(event.cwd, \".agents\", \"skills\", \"gitnexus\")) ||\n\t\t\texistsSync(join(homedir(), \".agents\", \"skills\", \"gitnexus-debugging\"));\n\t\tif (hasOwnGitnexusSkills) return;\n\t\tconst skillsDir = resolveGitNexusSkillsDir();\n\t\tif (!skillsDir) return;\n\t\treturn { skillPaths: [skillsDir] };\n\t});\n\n\tpi.on(\"before_agent_start\", (event) => {\n\t\tif (!inventory) return;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n\\n${buildGitNexusPrompt(inventory, current)}` };\n\t});\n\n\tpi.registerCommand(\"gitnexus-login\", {\n\t\tdescription: \"Sign in to GitNexus (implementation of /login → GitNexus account; accepts a pasted token)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst hubUrl = process.env.GITNEXUS_HUB_URL ?? DEFAULT_HUB_URL;\n\t\t\tconst pasted = args.trim();\n\n\t\t\t// Pasting a token stays supported for CI and headless installs.\n\t\t\tif (pasted) {\n\t\t\t\tawait new GitNexusClient({ hubUrl, token: pasted }).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig({ hubUrl, token: pasted });\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`GitNexus token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst deviceName = defaultDeviceName();\n\t\t\t\tconst fingerprint = deviceFingerprint();\n\t\t\t\tconst start = await startDeviceAuth(hubUrl, { deviceName, deviceFingerprint: fingerprint });\n\t\t\t\tconst link = start.verificationUrlComplete ?? start.verificationUrl;\n\t\t\t\t// The link carries the code, so an opened browser needs no typing.\n\t\t\t\t// Print it too: the launcher is best effort and can be headless.\n\t\t\t\tctx.ui.notify(`Code ${start.userCode} — opening ${link}`, \"info\");\n\t\t\t\topenBrowser(link);\n\n\t\t\t\tconst result = await pollDeviceAuth(hubUrl, start);\n\t\t\t\tconst config = {\n\t\t\t\t\thubUrl: result.hubUrl,\n\t\t\t\t\ttoken: result.token,\n\t\t\t\t\tdeviceFingerprint: fingerprint,\n\t\t\t\t\tdeviceName,\n\t\t\t\t};\n\t\t\t\tawait new GitNexusClient(config).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig(config);\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`Signed in. Token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-status\", {\n\t\tdescription: \"Show GitNexus connection status\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (!inventory) {\n\t\t\t\tconst message = loginRequired\n\t\t\t\t\t? \"GitNexus session expired. Run /login to sign in again.\"\n\t\t\t\t\t: (startupNotice ?? \"GitNexus: not signed in. Run /login.\");\n\t\t\t\tctx.ui.notify(message, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst repoLine = current ? `current repo: ${current.name}` : \"current repo: not indexed\";\n\t\t\tctx.ui.notify(`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}`, \"info\");\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/gitnexus/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { graphRailStore } from \"../../core/graph-rail-store.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport { registerAugmentedGrep } from \"./augment.ts\";\nimport { registerChangeTracking } from \"./changes.ts\";\nimport { GitNexusClient, GitNexusClientError } from \"./client.ts\";\nimport { DEFAULT_HUB_URL, resolveGitNexusConfig, saveGitNexusConfig } from \"./config.ts\";\nimport { defaultDeviceName, deviceFingerprint, pollDeviceAuth, startDeviceAuth } from \"./device-auth.ts\";\nimport { formatCreditBalance, readGatewayCache, refreshGatewayPolicy, registerAutoProvider } from \"./gateway.ts\";\nimport { spawnObservatoryFetch } from \"./observatory.ts\";\nimport { buildGitNexusPrompt } from \"./prompt.ts\";\nimport { withGitNexusRenderer } from \"./render.ts\";\nimport {\n\tgitRemoteSlug,\n\ttype IndexedRepo,\n\tmatchCurrentRepo,\n\tparseRepoInventory,\n\ttype RepoInventory,\n} from \"./resolve.ts\";\nimport { createGitNexusTools } from \"./tools.ts\";\n\n/** Resolve workflow skills in source mode and bundled dist/cli.js mode. */\nexport function resolveGitNexusSkillsDir(\n\tmoduleUrl: string = import.meta.url,\n\tpathExists: (path: string) => boolean = existsSync,\n): string | undefined {\n\tconst candidates = [\n\t\tfileURLToPath(new URL(\"./skills/\", moduleUrl)),\n\t\tfileURLToPath(new URL(\"./extensions/gitnexus/skills/\", moduleUrl)),\n\t];\n\treturn candidates.find(pathExists);\n}\n\n/**\n * GitNexus built-in extension: connects nexus-cli to the GitNexus hub.\n *\n * - session_start: resolve config + repo inventory, register the six graph\n * tools and the augmented grep. No token / hub down / repo unindexed all\n * degrade to a plain coding agent (graph is additive, never load-bearing).\n * - before_agent_start: append the GitNexus guidance block (ported from the\n * CLAUDE.md generator) to the system prompt.\n */\nexport default function gitnexusExtension(pi: ExtensionAPI): void {\n\tlet inventory: RepoInventory | undefined;\n\tlet current: IndexedRepo | undefined;\n\tlet activeClient: GitNexusClient | undefined;\n\tlet toolsRegistered = false;\n\tlet startupNotice: string | undefined;\n\tlet loginRequired = false;\n\n\tconst cwd = process.cwd();\n\n\t// Auto mode must also register at factory time: the initial model is\n\t// resolved before session_start fires, and a provider that appears after\n\t// that is invisible to it. Reads the policy cache the startup gate wrote.\n\tlet gatewayPolicy = readGatewayCache();\n\tregisterAutoProvider(pi, resolveGitNexusConfig(), gatewayPolicy);\n\n\tfunction updateCreditStatus(ctx: { ui: { setStatus(key: string, text: string | undefined): void } }): void {\n\t\tctx.ui.setStatus(\"nexus-credits\", formatCreditBalance(gatewayPolicy));\n\t}\n\n\t// Built-in tool overrides must happen at factory time (like the bash-spawn-hook\n\t// example) — session_start registrations only add NEW names reliably. The wrapper\n\t// behaves as plain grep until connect() provides a client + current repo.\n\tregisterAugmentedGrep(\n\t\tpi,\n\t\tcwd,\n\t\t() => activeClient,\n\t\t() => current?.name,\n\t);\n\tregisterChangeTracking(pi, cwd);\n\n\tasync function connect(): Promise<void> {\n\t\tinventory = undefined;\n\t\tcurrent = undefined;\n\t\tactiveClient = undefined;\n\t\tstartupNotice = undefined;\n\t\tloginRequired = false;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (!config) return;\n\t\tconst client = new GitNexusClient(config);\n\t\ttry {\n\t\t\tconst listResult = await client.callTool(\"list_repos\", {});\n\t\t\tinventory = parseRepoInventory(GitNexusClient.text(listResult));\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof GitNexusClientError ? error.message : String(error);\n\t\t\tif (error instanceof GitNexusClientError && error.kind === \"auth\") {\n\t\t\t\tloginRequired = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstartupNotice = `GitNexus unavailable: ${reason}`;\n\t\t\treturn;\n\t\t}\n\n\t\tcurrent = matchCurrentRepo(inventory, gitRemoteSlug(cwd));\n\t\tactiveClient = client;\n\t\tgraphRailStore.setRepoList(inventory.repos.map((repo) => ({ name: repo.name, symbols: repo.symbols })));\n\t\t// Observatory (community map) rides a detached subprocess + temp-file\n\t\t// handoff — in-process hub calls made after startup can starve in some\n\t\t// environments, a fresh process never does. The UI picks the file up\n\t\t// lazily via tryLoadObservatoryCache.\n\t\tif (current) spawnObservatoryFetch(config, current.name);\n\t\tgraphRailStore.setRepo(\n\t\t\tcurrent\n\t\t\t\t? {\n\t\t\t\t\t\tname: current.name,\n\t\t\t\t\t\tsymbols: current.symbols,\n\t\t\t\t\t\trelationships: current.relationships,\n\t\t\t\t\t\tindexedAt: current.indexedAt,\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tname: \"\",\n\t\t\t\t\t\tsymbols: \"0\",\n\t\t\t\t\t\trelationships: \"0\",\n\t\t\t\t\t\tindexedAt: \"\",\n\t\t\t\t\t\trepoCount: inventory.repos.length,\n\t\t\t\t\t},\n\t\t\tcurrent !== undefined,\n\t\t);\n\t\tif (!toolsRegistered) {\n\t\t\tconst ctx = { client, currentRepo: () => current?.name, cwd };\n\t\t\tfor (const tool of createGitNexusTools(ctx)) pi.registerTool(withGitNexusRenderer(tool));\n\t\t\ttoolsRegistered = true;\n\t\t}\n\n\t\tstartupNotice = current\n\t\t\t? `GitNexus: connected — ${current.name} (${current.symbols} symbols, indexed ${current.indexedAt}), ${inventory.repos.length} repos available.`\n\t\t\t: `GitNexus: connected — current directory is not indexed; ${inventory.repos.length} indexed repos remain queryable. Index this repo from the Hub dashboard to unlock local graph context.`;\n\t}\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tawait connect();\n\t\tupdateCreditStatus(ctx);\n\t\tif (startupNotice) ctx.ui.notify(startupNotice, inventory ? \"info\" : \"warning\");\n\t});\n\n\tpi.on(\"agent_settled\", async (_event, ctx) => {\n\t\tif (!gatewayPolicy || ctx.model?.provider !== \"gitnexus\") return;\n\t\tconst config = resolveGitNexusConfig();\n\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\tupdateCreditStatus(ctx);\n\t});\n\n\t// Bundled GitNexus workflow skills (debugging, exploring, impact-analysis,\n\t// refactoring, pr-review, guide) — same SKILL.md content the Claude plugin\n\t// ships, adapted for hub-based indexing. Loaded on-demand by pi's skill system.\n\t// Skipped entirely when the user already has gitnexus skills (project or\n\t// global) so the startup screen doesn't report shadowed duplicates.\n\tpi.on(\"resources_discover\", (event) => {\n\t\tconst hasOwnGitnexusSkills =\n\t\t\texistsSync(join(event.cwd, \".agents\", \"skills\", \"gitnexus\")) ||\n\t\t\texistsSync(join(homedir(), \".agents\", \"skills\", \"gitnexus-debugging\"));\n\t\tif (hasOwnGitnexusSkills) return;\n\t\tconst skillsDir = resolveGitNexusSkillsDir();\n\t\tif (!skillsDir) return;\n\t\treturn { skillPaths: [skillsDir] };\n\t});\n\n\tpi.on(\"before_agent_start\", (event) => {\n\t\tif (!inventory) return;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n\\n${buildGitNexusPrompt(inventory, current)}` };\n\t});\n\n\tpi.registerCommand(\"gitnexus-login\", {\n\t\tdescription: \"Sign in to GitNexus (implementation of /login → GitNexus account; accepts a pasted token)\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst hubUrl = process.env.GITNEXUS_HUB_URL ?? DEFAULT_HUB_URL;\n\t\t\tconst pasted = args.trim();\n\n\t\t\t// Pasting a token stays supported for CI and headless installs.\n\t\t\tif (pasted) {\n\t\t\t\tawait new GitNexusClient({ hubUrl, token: pasted }).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig({ hubUrl, token: pasted });\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`GitNexus token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst deviceName = defaultDeviceName();\n\t\t\t\tconst fingerprint = deviceFingerprint();\n\t\t\t\tconst start = await startDeviceAuth(hubUrl, { deviceName, deviceFingerprint: fingerprint });\n\t\t\t\tconst link = start.verificationUrlComplete ?? start.verificationUrl;\n\t\t\t\t// The link carries the code, so an opened browser needs no typing.\n\t\t\t\t// Print it too: the launcher is best effort and can be headless.\n\t\t\t\tctx.ui.notify(`Code ${start.userCode} — opening ${link}`, \"info\");\n\t\t\t\topenBrowser(link);\n\n\t\t\t\tconst result = await pollDeviceAuth(hubUrl, start);\n\t\t\t\tconst config = {\n\t\t\t\t\thubUrl: result.hubUrl,\n\t\t\t\t\ttoken: result.token,\n\t\t\t\t\tdeviceFingerprint: fingerprint,\n\t\t\t\t\tdeviceName,\n\t\t\t\t};\n\t\t\t\tawait new GitNexusClient(config).callTool(\"list_repos\", {});\n\t\t\t\tconst path = saveGitNexusConfig(config);\n\t\t\t\tawait connect();\n\t\t\t\tctx.ui.notify(`Signed in. Token saved to ${path}. ${startupNotice ?? \"\"}`, \"info\");\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tctx.ui.notify(`GitNexus login failed: ${message}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\tpi.registerCommand(\"gitnexus-status\", {\n\t\tdescription: \"Show GitNexus connection status\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tconst config = resolveGitNexusConfig();\n\t\t\tif (config) gatewayPolicy = await refreshGatewayPolicy(config);\n\t\t\tupdateCreditStatus(ctx);\n\t\t\tif (!inventory) {\n\t\t\t\tconst message = loginRequired\n\t\t\t\t\t? \"GitNexus session expired. Run /login to sign in again.\"\n\t\t\t\t\t: (startupNotice ?? \"GitNexus: not signed in. Run /login.\");\n\t\t\t\tctx.ui.notify(message, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst repoLine = current ? `current repo: ${current.name}` : \"current repo: not indexed\";\n\t\t\tconst creditLine = formatCreditBalance(gatewayPolicy);\n\t\t\tctx.ui.notify(\n\t\t\t\t`GitNexus: connected — ${inventory.repos.length} repos, ${repoLine}${creditLine ? `, ${creditLine}` : \"\"}`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n}\n"]}