@ashx-j/lunr 0.2.8 → 0.2.9

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 (127) hide show
  1. package/dist/builtin-extensions/ashxj-spinners.d.ts +7 -0
  2. package/dist/builtin-extensions/ashxj-spinners.d.ts.map +1 -1
  3. package/dist/builtin-extensions/ashxj-spinners.js +40 -3
  4. package/dist/builtin-extensions/ashxj-spinners.js.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.d.ts +4 -0
  6. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  7. package/dist/builtin-extensions/ashxj-tui.js +44 -0
  8. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  9. package/dist/builtin-extensions/lunr-behavior.d.ts +2 -1
  10. package/dist/builtin-extensions/lunr-behavior.d.ts.map +1 -1
  11. package/dist/builtin-extensions/lunr-behavior.js +26 -14
  12. package/dist/builtin-extensions/lunr-behavior.js.map +1 -1
  13. package/dist/builtin-extensions/lunr-todos.d.ts +4 -7
  14. package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
  15. package/dist/builtin-extensions/lunr-todos.js +18 -10
  16. package/dist/builtin-extensions/lunr-todos.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js +3 -3
  19. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js.map +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +2 -2
  22. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  23. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +2 -2
  24. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +3 -4
  26. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  27. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +6 -18
  29. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
  31. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +13 -5
  32. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
  33. package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.d.ts +21 -0
  34. package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.d.ts.map +1 -0
  35. package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.js +22 -0
  36. package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.js.map +1 -0
  37. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
  38. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +2 -1
  39. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
  40. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  41. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +10 -18
  42. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  43. package/dist/builtin-extensions/pi-web-access/render-search-error.d.ts.map +1 -1
  44. package/dist/builtin-extensions/pi-web-access/render-search-error.js +1 -1
  45. package/dist/builtin-extensions/pi-web-access/render-search-error.js.map +1 -1
  46. package/dist/catalog/models.json +1 -1
  47. package/dist/catalog/providers/openrouter.json +1 -1
  48. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  49. package/dist/catalog/publication.json +3 -3
  50. package/dist/cli/update-cli.d.ts +16 -0
  51. package/dist/cli/update-cli.d.ts.map +1 -0
  52. package/dist/cli/update-cli.js +83 -0
  53. package/dist/cli/update-cli.js.map +1 -0
  54. package/dist/cli.d.ts.map +1 -1
  55. package/dist/cli.js +6 -0
  56. package/dist/cli.js.map +1 -1
  57. package/dist/core/behavior-preset.d.ts +60 -0
  58. package/dist/core/behavior-preset.d.ts.map +1 -0
  59. package/dist/core/behavior-preset.js +257 -0
  60. package/dist/core/behavior-preset.js.map +1 -0
  61. package/dist/core/customize.d.ts +3 -0
  62. package/dist/core/customize.d.ts.map +1 -1
  63. package/dist/core/customize.js +9 -0
  64. package/dist/core/customize.js.map +1 -1
  65. package/dist/core/footer-data-provider.d.ts +12 -1
  66. package/dist/core/footer-data-provider.d.ts.map +1 -1
  67. package/dist/core/footer-data-provider.js +70 -5
  68. package/dist/core/footer-data-provider.js.map +1 -1
  69. package/dist/core/keybindings.d.ts +2 -2
  70. package/dist/core/keybindings.d.ts.map +1 -1
  71. package/dist/core/keybindings.js +1 -1
  72. package/dist/core/keybindings.js.map +1 -1
  73. package/dist/core/model-tiers.d.ts +9 -0
  74. package/dist/core/model-tiers.d.ts.map +1 -1
  75. package/dist/core/model-tiers.js +16 -0
  76. package/dist/core/model-tiers.js.map +1 -1
  77. package/dist/core/settings-manager.d.ts +23 -0
  78. package/dist/core/settings-manager.d.ts.map +1 -1
  79. package/dist/core/settings-manager.js +66 -0
  80. package/dist/core/settings-manager.js.map +1 -1
  81. package/dist/core/tools/bash.d.ts.map +1 -1
  82. package/dist/core/tools/bash.js +1 -3
  83. package/dist/core/tools/bash.js.map +1 -1
  84. package/dist/core/update-check.d.ts +32 -0
  85. package/dist/core/update-check.d.ts.map +1 -0
  86. package/dist/core/update-check.js +112 -0
  87. package/dist/core/update-check.js.map +1 -0
  88. package/dist/core/usage-service.d.ts +24 -1
  89. package/dist/core/usage-service.d.ts.map +1 -1
  90. package/dist/core/usage-service.js +91 -14
  91. package/dist/core/usage-service.js.map +1 -1
  92. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  93. package/dist/gateway/agent-bridge.js +5 -1
  94. package/dist/gateway/agent-bridge.js.map +1 -1
  95. package/dist/gateway/cron.d.ts.map +1 -1
  96. package/dist/gateway/cron.js +5 -1
  97. package/dist/gateway/cron.js.map +1 -1
  98. package/dist/main.d.ts.map +1 -1
  99. package/dist/main.js +13 -1
  100. package/dist/main.js.map +1 -1
  101. package/dist/modes/interactive/components/assistant-message.d.ts +4 -0
  102. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  103. package/dist/modes/interactive/components/assistant-message.js +68 -10
  104. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  105. package/dist/modes/interactive/components/settings-selector.d.ts +13 -0
  106. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  107. package/dist/modes/interactive/components/settings-selector.js +157 -10
  108. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  109. package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  110. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  111. package/dist/modes/interactive/components/tool-execution.js +9 -0
  112. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  113. package/dist/modes/interactive/interactive-mode.d.ts +4 -1
  114. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  115. package/dist/modes/interactive/interactive-mode.js +82 -3
  116. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  117. package/docs/keybindings.md +1 -1
  118. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  119. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  120. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  121. package/examples/extensions/gondolin/package-lock.json +2 -2
  122. package/examples/extensions/gondolin/package.json +1 -1
  123. package/examples/extensions/sandbox/package-lock.json +2 -2
  124. package/examples/extensions/sandbox/package.json +1 -1
  125. package/examples/extensions/with-deps/package-lock.json +2 -2
  126. package/examples/extensions/with-deps/package.json +1 -1
  127. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport type { AgentTool } from \"@ashx-j/lunr-agent\";\nimport { Container, Text, truncateToWidth } from \"@ashx-j/lunr-tui\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { markExited as markProcessExited, register as registerProcess } from \"../process-registry.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { formatGroupedCall, getTextOutput, invalidArgText, str, toolStatusDotFromContext } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string; sessionId?: string }): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = getShellConfig(options?.shellPath);\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\t// lunr: register the process for /processes tracking.\n\t\t\tif (child.pid) {\n\t\t\t\ttry {\n\t\t\t\t\tregisterProcess(child.pid, command, cwd, options?.sessionId);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\t// lunr: unregister from /processes if the process has exited; keep it if still\n\t\t\t\t// alive (detached/backgrounded dev servers survive the shell call).\n\t\t\t\tif (child.pid) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// lunr: keep finished processes visible briefly so /processes can show\n\t\t\t\t\t\t// their exit state; markExited deletes trivial fast commands immediately.\n\t\t\t\t\t\tmarkProcessExited(child.pid, child.exitCode);\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(command: string, cwd: string, spawnHook?: BashSpawnHook): BashSpawnContext {\n\tconst baseContext: BashSpawnContext = { command, cwd, env: { ...getShellEnv() } };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\n// lunr: slim header — collapsed calls show only the first line of the command,\n// capped at this many chars; an ellipsis marks either kind of truncation.\nconst MAX_COLLAPSED_COMMAND_CHARS = 100;\n\nfunction formatBashCall(\n\targs: { command?: string; timeout?: number } | undefined,\n\toptions?: { expanded?: boolean; compact?: boolean },\n): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\t// lunr: compact-by-default — the timeout suffix is noise on a one-line header;\n\t// it stays visible while streaming and in the expanded view.\n\tconst timeoutSuffix = timeout && !options?.compact ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tlet commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\tif (!options?.expanded && command) {\n\t\tconst firstLine = command.split(\"\\n\")[0];\n\t\tconst capped = firstLine.length > MAX_COLLAPSED_COMMAND_CHARS;\n\t\tconst base = capped ? firstLine.slice(0, MAX_COLLAPSED_COMMAND_CHARS) : firstLine;\n\t\tcommandDisplay = capped || base.length < command.length ? `${base} …` : base;\n\t}\n\tif (command) {\n\t\tcommandDisplay = theme.fg(\"toolTitle\", theme.bold(commandDisplay));\n\t}\n\treturn commandDisplay + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n\t// lunr: compact-by-default — finished, successful, non-expanded calls skip the\n\t// output preview and the \"Took\" footer (duration moves into the call header).\n\tcompact = false,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (!compact && output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t// lunr: the truncation/full-output notice is intentionally NOT rendered in\n\t// the TUI — the model still gets it in the result text (formatOutput), and\n\t// the temp-log path is noise on screen.\n\n\tif (!compact && startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"lunr-bash\" }); // lunr: renamed from pi-bash\n\t\t\tlet acceptingOutput = true;\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\tif (!acceptingOutput) return;\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\tacceptingOutput = false;\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\t// lunr: compact-by-default — stamp endedAt here too: renderCall runs before\n\t\t\t// renderResult on the final update, and the header needs the duration.\n\t\t\tif (!context.isPartial && state.startedAt !== undefined) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t}\n\t\t\t// lunr: compact-by-default — a finished, successful, non-expanded call\n\t\t\t// renders as a single slim header line with the duration folded in.\n\t\t\tconst compact = !context.isPartial && !context.expanded && !context.isError;\n\t\t\tlet detail = formatBashCall(args, { expanded: context.expanded, compact });\n\t\t\tif (compact && state.startedAt !== undefined && state.endedAt !== undefined) {\n\t\t\t\tdetail += theme.fg(\"muted\", ` — Took ${formatDuration(state.endedAt - state.startedAt)}`);\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tformatGroupedCall({\n\t\t\t\t\trole: context.groupRole ?? \"singleton\",\n\t\t\t\t\tcompact,\n\t\t\t\t\tdot: toolStatusDotFromContext(context, theme),\n\t\t\t\t\ttitle: theme.fg(\"toolTitle\", theme.bold(\"$\")),\n\t\t\t\t\tdetail,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\t// lunr: compact-by-default — suppresses the output preview + \"Took\" footer.\n\t\t\tconst compact = !options.isPartial && !options.expanded && !context.isError;\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t\tcompact,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport type { AgentTool } from \"@ashx-j/lunr-agent\";\nimport { Container, Text, truncateToWidth } from \"@ashx-j/lunr-tui\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\n\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { markExited as markProcessExited, register as registerProcess } from \"../process-registry.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { formatGroupedCall, getTextOutput, invalidArgText, str, toolStatusDotFromContext } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string; sessionId?: string }): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = getShellConfig(options?.shellPath);\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(command);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\t// lunr: register the process for /processes tracking.\n\t\t\tif (child.pid) {\n\t\t\t\ttry {\n\t\t\t\t\tregisterProcess(child.pid, command, cwd, options?.sessionId);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\t// lunr: unregister from /processes if the process has exited; keep it if still\n\t\t\t\t// alive (detached/backgrounded dev servers survive the shell call).\n\t\t\t\tif (child.pid) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// lunr: keep finished processes visible briefly so /processes can show\n\t\t\t\t\t\t// their exit state; markExited deletes trivial fast commands immediately.\n\t\t\t\t\t\tmarkProcessExited(child.pid, child.exitCode);\n\t\t\t\t\t} catch {}\n\t\t\t\t}\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(command: string, cwd: string, spawnHook?: BashSpawnHook): BashSpawnContext {\n\tconst baseContext: BashSpawnContext = { command, cwd, env: { ...getShellEnv() } };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\n// lunr: slim header — collapsed calls show only the first line of the command,\n// capped at this many chars; an ellipsis marks either kind of truncation.\nconst MAX_COLLAPSED_COMMAND_CHARS = 100;\n\nfunction formatBashCall(\n\targs: { command?: string; timeout?: number } | undefined,\n\toptions?: { expanded?: boolean; compact?: boolean },\n): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\t// lunr: compact-by-default — the timeout suffix is noise on a one-line header;\n\t// it stays visible while streaming and in the expanded view.\n\tconst timeoutSuffix = timeout && !options?.compact ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tlet commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\tif (!options?.expanded && command) {\n\t\tconst firstLine = command.split(\"\\n\")[0];\n\t\tconst capped = firstLine.length > MAX_COLLAPSED_COMMAND_CHARS;\n\t\tconst base = capped ? firstLine.slice(0, MAX_COLLAPSED_COMMAND_CHARS) : firstLine;\n\t\tcommandDisplay = capped || base.length < command.length ? `${base} …` : base;\n\t}\n\tif (command) {\n\t\tcommandDisplay = theme.fg(\"toolTitle\", theme.bold(commandDisplay));\n\t}\n\treturn commandDisplay + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n\t// lunr: compact-by-default — finished, successful, non-expanded calls skip the\n\t// output preview and the \"Took\" footer (duration moves into the call header).\n\tcompact = false,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (!compact && output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint = theme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines)`);\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t// lunr: the truncation/full-output notice is intentionally NOT rendered in\n\t// the TUI — the model still gets it in the result text (formatOutput), and\n\t// the temp-log path is noise on screen.\n\n\tif (!compact && startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"lunr-bash\" }); // lunr: renamed from pi-bash\n\t\t\tlet acceptingOutput = true;\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\tif (!acceptingOutput) return;\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\tacceptingOutput = false;\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\t// lunr: compact-by-default — stamp endedAt here too: renderCall runs before\n\t\t\t// renderResult on the final update, and the header needs the duration.\n\t\t\tif (!context.isPartial && state.startedAt !== undefined) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t}\n\t\t\t// lunr: compact-by-default — a finished, successful, non-expanded call\n\t\t\t// renders as a single slim header line with the duration folded in.\n\t\t\tconst compact = !context.isPartial && !context.expanded && !context.isError;\n\t\t\tlet detail = formatBashCall(args, { expanded: context.expanded, compact });\n\t\t\tif (compact && state.startedAt !== undefined && state.endedAt !== undefined) {\n\t\t\t\tdetail += theme.fg(\"muted\", ` — Took ${formatDuration(state.endedAt - state.startedAt)}`);\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(\n\t\t\t\tformatGroupedCall({\n\t\t\t\t\trole: context.groupRole ?? \"singleton\",\n\t\t\t\t\tcompact,\n\t\t\t\t\tdot: toolStatusDotFromContext(context, theme),\n\t\t\t\t\ttitle: theme.fg(\"toolTitle\", theme.bold(\"$\")),\n\t\t\t\t\tdetail,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\t// lunr: compact-by-default — suppresses the output preview + \"Took\" footer.\n\t\t\tconst compact = !options.isPartial && !options.expanded && !context.isError;\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t\tcompact,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Published-install version check against the npm registry for @ashx-j/lunr.
3
+ * Workspace checkouts (PACKAGE_NAME !== NPM_CLI_PACKAGE) never nag or self-update.
4
+ */
5
+ export declare const UPDATE_CHECK_TTL_MS: number;
6
+ export declare const UPDATE_CHECK_TIMEOUT_MS = 4000;
7
+ export declare const NPM_LATEST_URL = "https://registry.npmjs.org/@ashx-j/lunr/latest";
8
+ export interface UpdateCheckRecord {
9
+ checkedAt: number;
10
+ latest: string;
11
+ notifiedVersion?: string;
12
+ }
13
+ export interface UpdateCheckResult {
14
+ latest: string;
15
+ current: string;
16
+ newer: boolean;
17
+ notice?: string;
18
+ }
19
+ export declare function isPublishedInstall(packageName?: string, npmName?: string): boolean;
20
+ export declare function updateCheckPath(agentDir: string): string;
21
+ export declare function checkForUpdate(options: {
22
+ currentVersion: string;
23
+ agentDir: string;
24
+ now?: number;
25
+ fetchImpl?: typeof fetch;
26
+ published?: boolean;
27
+ offline?: boolean;
28
+ force?: boolean;
29
+ }): Promise<UpdateCheckResult | undefined>;
30
+ /** Persist that we already showed the TUI notice for this latest version. */
31
+ export declare function markUpdateNotified(agentDir: string, latest: string): void;
32
+ //# sourceMappingURL=update-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../../src/core/update-check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,eAAO,MAAM,mBAAmB,QAAsB,CAAC;AACvD,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,cAAc,mDAAyD,CAAC;AAErF,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CACjC,WAAW,GAAE,MAAqB,EAClC,OAAO,GAAE,MAAwB,GAC/B,OAAO,CAET;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD;AAyCD,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAqBzC;AAmBD,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUzE","sourcesContent":["/**\n * Published-install version check against the npm registry for @ashx-j/lunr.\n * Workspace checkouts (PACKAGE_NAME !== NPM_CLI_PACKAGE) never nag or self-update.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { gt } from \"semver\";\nimport { NPM_CLI_PACKAGE, PACKAGE_NAME } from \"../config.ts\";\n\nexport const UPDATE_CHECK_TTL_MS = 24 * 60 * 60 * 1000;\nexport const UPDATE_CHECK_TIMEOUT_MS = 4000;\nexport const NPM_LATEST_URL = `https://registry.npmjs.org/${NPM_CLI_PACKAGE}/latest`;\n\nexport interface UpdateCheckRecord {\n\tcheckedAt: number;\n\tlatest: string;\n\tnotifiedVersion?: string;\n}\n\nexport interface UpdateCheckResult {\n\tlatest: string;\n\tcurrent: string;\n\tnewer: boolean;\n\tnotice?: string;\n}\n\nexport function isPublishedInstall(\n\tpackageName: string = PACKAGE_NAME,\n\tnpmName: string = NPM_CLI_PACKAGE,\n): boolean {\n\treturn packageName === npmName;\n}\n\nexport function updateCheckPath(agentDir: string): string {\n\treturn join(agentDir, \"update-check.json\");\n}\n\nfunction readRecord(path: string): UpdateCheckRecord | undefined {\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(path, \"utf8\")) as UpdateCheckRecord;\n\t\tif (typeof raw.checkedAt !== \"number\" || typeof raw.latest !== \"string\" || !raw.latest.trim()) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tcheckedAt: raw.checkedAt,\n\t\t\tlatest: raw.latest.trim(),\n\t\t\tnotifiedVersion: typeof raw.notifiedVersion === \"string\" ? raw.notifiedVersion : undefined,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction writeRecord(path: string, record: UpdateCheckRecord): void {\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteFileSync(path, `${JSON.stringify(record)}\\n`, \"utf8\");\n}\n\nasync function fetchLatest(fetchImpl: typeof fetch): Promise<string | undefined> {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), UPDATE_CHECK_TIMEOUT_MS);\n\ttry {\n\t\tconst response = await fetchImpl(NPM_LATEST_URL, {\n\t\t\theaders: { Accept: \"application/json\" },\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!response.ok) return undefined;\n\t\tconst payload = (await response.json()) as { version?: unknown };\n\t\treturn typeof payload.version === \"string\" && payload.version.trim() ? payload.version.trim() : undefined;\n\t} catch {\n\t\treturn undefined;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\n\nexport async function checkForUpdate(options: {\n\tcurrentVersion: string;\n\tagentDir: string;\n\tnow?: number;\n\tfetchImpl?: typeof fetch;\n\tpublished?: boolean;\n\toffline?: boolean;\n\tforce?: boolean;\n}): Promise<UpdateCheckResult | undefined> {\n\tif (options.offline) return undefined;\n\tif (!(options.published ?? isPublishedInstall())) return undefined;\n\n\tconst now = options.now ?? Date.now();\n\tconst path = updateCheckPath(options.agentDir);\n\tlet record = existsSync(path) ? readRecord(path) : undefined;\n\tconst stale = !record || now - record.checkedAt >= UPDATE_CHECK_TTL_MS || options.force;\n\tif (stale) {\n\t\tconst latest = await fetchLatest(options.fetchImpl ?? fetch);\n\t\tif (!latest) return record ? toResult(options.currentVersion, record, false) : undefined;\n\t\trecord = { checkedAt: now, latest, notifiedVersion: record?.notifiedVersion };\n\t\ttry {\n\t\t\twriteRecord(path, record);\n\t\t} catch {\n\t\t\t// Cache write is best-effort.\n\t\t}\n\t}\n\n\tif (!record) return undefined;\n\treturn toResult(options.currentVersion, record, true);\n}\n\nfunction isNewer(latest: string, current: string): boolean {\n\ttry {\n\t\treturn gt(latest, current);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction toResult(current: string, record: UpdateCheckRecord, allowNotice: boolean): UpdateCheckResult {\n\tconst newer = isNewer(record.latest, current);\n\tconst notice =\n\t\tallowNotice && newer && record.notifiedVersion !== record.latest\n\t\t\t? `lunR ${record.latest} is available. Run lunr update.`\n\t\t\t: undefined;\n\treturn { latest: record.latest, current, newer, notice };\n}\n\n/** Persist that we already showed the TUI notice for this latest version. */\nexport function markUpdateNotified(agentDir: string, latest: string): void {\n\tconst path = updateCheckPath(agentDir);\n\tconst record = existsSync(path) ? readRecord(path) : undefined;\n\tif (!record) return;\n\trecord.notifiedVersion = latest;\n\ttry {\n\t\twriteRecord(path, record);\n\t} catch {\n\t\t// ignore\n\t}\n}\n"]}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Published-install version check against the npm registry for @ashx-j/lunr.
3
+ * Workspace checkouts (PACKAGE_NAME !== NPM_CLI_PACKAGE) never nag or self-update.
4
+ */
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { dirname, join } from "node:path";
7
+ import { gt } from "semver";
8
+ import { NPM_CLI_PACKAGE, PACKAGE_NAME } from "../config.js";
9
+ export const UPDATE_CHECK_TTL_MS = 24 * 60 * 60 * 1000;
10
+ export const UPDATE_CHECK_TIMEOUT_MS = 4000;
11
+ export const NPM_LATEST_URL = `https://registry.npmjs.org/${NPM_CLI_PACKAGE}/latest`;
12
+ export function isPublishedInstall(packageName = PACKAGE_NAME, npmName = NPM_CLI_PACKAGE) {
13
+ return packageName === npmName;
14
+ }
15
+ export function updateCheckPath(agentDir) {
16
+ return join(agentDir, "update-check.json");
17
+ }
18
+ function readRecord(path) {
19
+ try {
20
+ const raw = JSON.parse(readFileSync(path, "utf8"));
21
+ if (typeof raw.checkedAt !== "number" || typeof raw.latest !== "string" || !raw.latest.trim()) {
22
+ return undefined;
23
+ }
24
+ return {
25
+ checkedAt: raw.checkedAt,
26
+ latest: raw.latest.trim(),
27
+ notifiedVersion: typeof raw.notifiedVersion === "string" ? raw.notifiedVersion : undefined,
28
+ };
29
+ }
30
+ catch {
31
+ return undefined;
32
+ }
33
+ }
34
+ function writeRecord(path, record) {
35
+ mkdirSync(dirname(path), { recursive: true });
36
+ writeFileSync(path, `${JSON.stringify(record)}\n`, "utf8");
37
+ }
38
+ async function fetchLatest(fetchImpl) {
39
+ const controller = new AbortController();
40
+ const timeout = setTimeout(() => controller.abort(), UPDATE_CHECK_TIMEOUT_MS);
41
+ try {
42
+ const response = await fetchImpl(NPM_LATEST_URL, {
43
+ headers: { Accept: "application/json" },
44
+ signal: controller.signal,
45
+ });
46
+ if (!response.ok)
47
+ return undefined;
48
+ const payload = (await response.json());
49
+ return typeof payload.version === "string" && payload.version.trim() ? payload.version.trim() : undefined;
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ finally {
55
+ clearTimeout(timeout);
56
+ }
57
+ }
58
+ export async function checkForUpdate(options) {
59
+ if (options.offline)
60
+ return undefined;
61
+ if (!(options.published ?? isPublishedInstall()))
62
+ return undefined;
63
+ const now = options.now ?? Date.now();
64
+ const path = updateCheckPath(options.agentDir);
65
+ let record = existsSync(path) ? readRecord(path) : undefined;
66
+ const stale = !record || now - record.checkedAt >= UPDATE_CHECK_TTL_MS || options.force;
67
+ if (stale) {
68
+ const latest = await fetchLatest(options.fetchImpl ?? fetch);
69
+ if (!latest)
70
+ return record ? toResult(options.currentVersion, record, false) : undefined;
71
+ record = { checkedAt: now, latest, notifiedVersion: record?.notifiedVersion };
72
+ try {
73
+ writeRecord(path, record);
74
+ }
75
+ catch {
76
+ // Cache write is best-effort.
77
+ }
78
+ }
79
+ if (!record)
80
+ return undefined;
81
+ return toResult(options.currentVersion, record, true);
82
+ }
83
+ function isNewer(latest, current) {
84
+ try {
85
+ return gt(latest, current);
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ function toResult(current, record, allowNotice) {
92
+ const newer = isNewer(record.latest, current);
93
+ const notice = allowNotice && newer && record.notifiedVersion !== record.latest
94
+ ? `lunR ${record.latest} is available. Run lunr update.`
95
+ : undefined;
96
+ return { latest: record.latest, current, newer, notice };
97
+ }
98
+ /** Persist that we already showed the TUI notice for this latest version. */
99
+ export function markUpdateNotified(agentDir, latest) {
100
+ const path = updateCheckPath(agentDir);
101
+ const record = existsSync(path) ? readRecord(path) : undefined;
102
+ if (!record)
103
+ return;
104
+ record.notifiedVersion = latest;
105
+ try {
106
+ writeRecord(path, record);
107
+ }
108
+ catch {
109
+ // ignore
110
+ }
111
+ }
112
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/core/update-check.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Published-install version check against the npm registry for @ashx-j/lunr.\n * Workspace checkouts (PACKAGE_NAME !== NPM_CLI_PACKAGE) never nag or self-update.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { gt } from \"semver\";\nimport { NPM_CLI_PACKAGE, PACKAGE_NAME } from \"../config.ts\";\n\nexport const UPDATE_CHECK_TTL_MS = 24 * 60 * 60 * 1000;\nexport const UPDATE_CHECK_TIMEOUT_MS = 4000;\nexport const NPM_LATEST_URL = `https://registry.npmjs.org/${NPM_CLI_PACKAGE}/latest`;\n\nexport interface UpdateCheckRecord {\n\tcheckedAt: number;\n\tlatest: string;\n\tnotifiedVersion?: string;\n}\n\nexport interface UpdateCheckResult {\n\tlatest: string;\n\tcurrent: string;\n\tnewer: boolean;\n\tnotice?: string;\n}\n\nexport function isPublishedInstall(\n\tpackageName: string = PACKAGE_NAME,\n\tnpmName: string = NPM_CLI_PACKAGE,\n): boolean {\n\treturn packageName === npmName;\n}\n\nexport function updateCheckPath(agentDir: string): string {\n\treturn join(agentDir, \"update-check.json\");\n}\n\nfunction readRecord(path: string): UpdateCheckRecord | undefined {\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(path, \"utf8\")) as UpdateCheckRecord;\n\t\tif (typeof raw.checkedAt !== \"number\" || typeof raw.latest !== \"string\" || !raw.latest.trim()) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tcheckedAt: raw.checkedAt,\n\t\t\tlatest: raw.latest.trim(),\n\t\t\tnotifiedVersion: typeof raw.notifiedVersion === \"string\" ? raw.notifiedVersion : undefined,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction writeRecord(path: string, record: UpdateCheckRecord): void {\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteFileSync(path, `${JSON.stringify(record)}\\n`, \"utf8\");\n}\n\nasync function fetchLatest(fetchImpl: typeof fetch): Promise<string | undefined> {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), UPDATE_CHECK_TIMEOUT_MS);\n\ttry {\n\t\tconst response = await fetchImpl(NPM_LATEST_URL, {\n\t\t\theaders: { Accept: \"application/json\" },\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!response.ok) return undefined;\n\t\tconst payload = (await response.json()) as { version?: unknown };\n\t\treturn typeof payload.version === \"string\" && payload.version.trim() ? payload.version.trim() : undefined;\n\t} catch {\n\t\treturn undefined;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\n\nexport async function checkForUpdate(options: {\n\tcurrentVersion: string;\n\tagentDir: string;\n\tnow?: number;\n\tfetchImpl?: typeof fetch;\n\tpublished?: boolean;\n\toffline?: boolean;\n\tforce?: boolean;\n}): Promise<UpdateCheckResult | undefined> {\n\tif (options.offline) return undefined;\n\tif (!(options.published ?? isPublishedInstall())) return undefined;\n\n\tconst now = options.now ?? Date.now();\n\tconst path = updateCheckPath(options.agentDir);\n\tlet record = existsSync(path) ? readRecord(path) : undefined;\n\tconst stale = !record || now - record.checkedAt >= UPDATE_CHECK_TTL_MS || options.force;\n\tif (stale) {\n\t\tconst latest = await fetchLatest(options.fetchImpl ?? fetch);\n\t\tif (!latest) return record ? toResult(options.currentVersion, record, false) : undefined;\n\t\trecord = { checkedAt: now, latest, notifiedVersion: record?.notifiedVersion };\n\t\ttry {\n\t\t\twriteRecord(path, record);\n\t\t} catch {\n\t\t\t// Cache write is best-effort.\n\t\t}\n\t}\n\n\tif (!record) return undefined;\n\treturn toResult(options.currentVersion, record, true);\n}\n\nfunction isNewer(latest: string, current: string): boolean {\n\ttry {\n\t\treturn gt(latest, current);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction toResult(current: string, record: UpdateCheckRecord, allowNotice: boolean): UpdateCheckResult {\n\tconst newer = isNewer(record.latest, current);\n\tconst notice =\n\t\tallowNotice && newer && record.notifiedVersion !== record.latest\n\t\t\t? `lunR ${record.latest} is available. Run lunr update.`\n\t\t\t: undefined;\n\treturn { latest: record.latest, current, newer, notice };\n}\n\n/** Persist that we already showed the TUI notice for this latest version. */\nexport function markUpdateNotified(agentDir: string, latest: string): void {\n\tconst path = updateCheckPath(agentDir);\n\tconst record = existsSync(path) ? readRecord(path) : undefined;\n\tif (!record) return;\n\trecord.notifiedVersion = latest;\n\ttry {\n\t\twriteRecord(path, record);\n\t} catch {\n\t\t// ignore\n\t}\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Plan/subscription usage service. Per-provider adapters query provider quota
3
- * endpoints (5-minute cache each) so /usage can show subscription windows
3
+ * endpoints (60-second cache each) so /usage and the footer can show subscription windows
4
4
  * alongside session/context totals.
5
5
  *
6
6
  * Deliberately absent adapters:
@@ -13,6 +13,7 @@
13
13
  * Auth failures are different: they return `error` and are not cached as empty.
14
14
  */
15
15
  import type { ModelRuntime } from "./model-runtime.ts";
16
+ import type { SettingsManager } from "./settings-manager.ts";
16
17
  export interface PlanUsageWindow {
17
18
  label: string;
18
19
  usedPercent: number;
@@ -32,12 +33,34 @@ export interface PlanUsageResult {
32
33
  /** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */
33
34
  export declare function planUsageAuthError(error: unknown): string | undefined;
34
35
  export declare const PLAN_USAGE_CACHE_TTL_MS: number;
36
+ export type PlanUsageWindowPreference = "5h" | "weekly";
37
+ export declare function isWeeklyPlanWindow(window: PlanUsageWindow): boolean;
38
+ export declare function isFiveHourPlanWindow(window: PlanUsageWindow): boolean;
39
+ /** Preferred window, falling back to the other, skipping Extra/on-demand. */
40
+ export declare function pickPlanWindow(usage: PlanUsage | undefined, preferred: PlanUsageWindowPreference): PlanUsageWindow | undefined;
41
+ export declare function footerPlanLabel(window: PlanUsageWindow): string;
35
42
  /** Whether a plan-usage adapter exists for this provider. */
36
43
  export declare function hasPlanUsageAdapter(providerId: string): boolean;
37
44
  /** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */
38
45
  export declare function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined>;
39
46
  /** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */
40
47
  export declare function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult>;
48
+ /** Last fetched usage, including expired cache (footer can show stale while refetching). */
49
+ export declare function peekPlanUsage(providerId: string): PlanUsage | undefined;
41
50
  /** Clear the adapter cache (tests, /login changes). */
42
51
  export declare function clearPlanUsageCache(): void;
52
+ export declare const USAGE_SERVICE_BRIDGE_SYMBOL: unique symbol;
53
+ export interface FooterPlanSegment {
54
+ label: string;
55
+ usedPercent: number;
56
+ }
57
+ export interface UsageServiceBridge {
58
+ peek(providerId: string): PlanUsage | undefined;
59
+ prefetch(providerId: string): void;
60
+ getPreferredWindow(): PlanUsageWindowPreference;
61
+ pickForFooter(providerId: string): FooterPlanSegment | undefined;
62
+ setOnUpdate(fn: (() => void) | undefined): void;
63
+ }
64
+ export declare function registerUsageServiceBridge(runtime: ModelRuntime, settingsManager: SettingsManager): void;
65
+ export declare function getUsageServiceBridge(): UsageServiceBridge | undefined;
43
66
  //# sourceMappingURL=usage-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAoBD,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOrE;AAWD,eAAO,MAAM,uBAAuB,QAAgB,CAAC;AAIrD,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAE5G;AAED,sFAAsF;AACtF,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAgB5G;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (5-minute cache each) so /usage can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\tusage?: PlanUsage;\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain)) return undefined;\n\t// 403 on billing is often entitlement, not a dead refresh token.\n\tif (/xai billing rejected the session \\(HTTP 401\\)/i.test(chain)) return XAI_RELOGIN;\n\tif (/invalid_grant|refresh token revoked/i.test(chain)) return XAI_RELOGIN;\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 5 * 60 * 1000;\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value };\n\ttry {\n\t\tconst value = await adapter(runtime);\n\t\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });\n\t\treturn { usage: value };\n\t} catch (error) {\n\t\tconst authError = planUsageAuthError(error);\n\t\tif (authError) return { error: authError };\n\t\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value: undefined });\n\t\treturn {};\n\t}\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n"]}
1
+ {"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAM7D,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAoBD,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOrE;AAWD,eAAO,MAAM,uBAAuB,QAAY,CAAC;AAEjD,MAAM,MAAM,yBAAyB,GAAG,IAAI,GAAG,QAAQ,CAAC;AAExD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAEnE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAErE;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAC7B,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,SAAS,EAAE,yBAAyB,GAClC,eAAe,GAAG,SAAS,CAO7B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAI/D;AAKD,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAE5G;AAED,sFAAsF;AACtF,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAwB5G;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEvE;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAMD,eAAO,MAAM,2BAA2B,eAAoC,CAAC;AAE7E,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,kBAAkB,IAAI,yBAAyB,CAAC;IAChD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACjE,WAAW,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;CAChD;AA+BD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI,CAIxG;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,SAAS,CAEtE","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (60-second cache each) so /usage and the footer can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\tusage?: PlanUsage;\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/timed out|aborted|cancelled|ECONN|ENOTFOUND|network/i.test(chain)) return undefined;\n\t// 403 on billing is often entitlement, not a dead refresh token.\n\tif (/xai billing rejected the session \\(HTTP 401\\)/i.test(chain)) return XAI_RELOGIN;\n\tif (/invalid_grant|refresh token revoked/i.test(chain)) return XAI_RELOGIN;\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 60 * 1000;\n\nexport type PlanUsageWindowPreference = \"5h\" | \"weekly\";\n\nexport function isWeeklyPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /week/i.test(window.label);\n}\n\nexport function isFiveHourPlanWindow(window: PlanUsageWindow): boolean {\n\treturn /5h/i.test(window.label) || window.label === \"5h\";\n}\n\n/** Preferred window, falling back to the other, skipping Extra/on-demand. */\nexport function pickPlanWindow(\n\tusage: PlanUsage | undefined,\n\tpreferred: PlanUsageWindowPreference,\n): PlanUsageWindow | undefined {\n\tif (!usage?.windows.length) return undefined;\n\tconst usable = usage.windows.filter((w) => !/extra/i.test(w.label));\n\tconst weekly = usable.find(isWeeklyPlanWindow);\n\tconst fiveH = usable.find(isFiveHourPlanWindow);\n\tif (preferred === \"5h\") return fiveH ?? weekly ?? usable[0] ?? usage.windows[0];\n\treturn weekly ?? fiveH ?? usable[0] ?? usage.windows[0];\n}\n\nexport function footerPlanLabel(window: PlanUsageWindow): string {\n\tif (isFiveHourPlanWindow(window)) return \"5h\";\n\tif (isWeeklyPlanWindow(window)) return \"wk\";\n\treturn window.label.length <= 4 ? window.label : window.label.slice(0, 4);\n}\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\nconst inflight = new Map<string, Promise<PlanUsageResult>>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value };\n\tconst pending = inflight.get(providerId);\n\tif (pending) return pending;\n\tconst task = (async (): Promise<PlanUsageResult> => {\n\t\ttry {\n\t\t\tconst value = await adapter(runtime);\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value });\n\t\t\treturn { usage: value };\n\t\t} catch (error) {\n\t\t\tconst authError = planUsageAuthError(error);\n\t\t\tif (authError) return { error: authError };\n\t\t\tcache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: undefined });\n\t\t\treturn {};\n\t\t} finally {\n\t\t\tinflight.delete(providerId);\n\t\t}\n\t})();\n\tinflight.set(providerId, task);\n\treturn task;\n}\n\n/** Last fetched usage, including expired cache (footer can show stale while refetching). */\nexport function peekPlanUsage(providerId: string): PlanUsage | undefined {\n\treturn cache.get(providerId)?.value;\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n\tinflight.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n\nexport const USAGE_SERVICE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/usage-service\");\n\nexport interface FooterPlanSegment {\n\tlabel: string;\n\tusedPercent: number;\n}\n\nexport interface UsageServiceBridge {\n\tpeek(providerId: string): PlanUsage | undefined;\n\tprefetch(providerId: string): void;\n\tgetPreferredWindow(): PlanUsageWindowPreference;\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined;\n\tsetOnUpdate(fn: (() => void) | undefined): void;\n}\n\nlet activeRuntime: ModelRuntime | undefined;\nlet activeUsageSettings: SettingsManager | undefined;\nlet onUsageUpdate: (() => void) | undefined;\n\nfunction preferredWindow(): PlanUsageWindowPreference {\n\treturn activeUsageSettings?.getPlanUsageWindow() ?? \"weekly\";\n}\n\nconst usageBridge: UsageServiceBridge = {\n\tpeek(providerId: string): PlanUsage | undefined {\n\t\treturn peekPlanUsage(providerId);\n\t},\n\tprefetch(providerId: string): void {\n\t\tif (!activeRuntime || !hasPlanUsageAdapter(providerId)) return;\n\t\tvoid getPlanUsage(providerId, activeRuntime).then(() => onUsageUpdate?.());\n\t},\n\tsetOnUpdate(fn: (() => void) | undefined): void {\n\t\tonUsageUpdate = fn;\n\t},\n\tgetPreferredWindow(): PlanUsageWindowPreference {\n\t\treturn preferredWindow();\n\t},\n\tpickForFooter(providerId: string): FooterPlanSegment | undefined {\n\t\tconst window = pickPlanWindow(peekPlanUsage(providerId), preferredWindow());\n\t\tif (!window) return undefined;\n\t\treturn { label: footerPlanLabel(window), usedPercent: window.usedPercent };\n\t},\n};\n\nexport function registerUsageServiceBridge(runtime: ModelRuntime, settingsManager: SettingsManager): void {\n\tactiveRuntime = runtime;\n\tactiveUsageSettings = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] = usageBridge;\n}\n\nexport function getUsageServiceBridge(): UsageServiceBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE_SYMBOL] as UsageServiceBridge | undefined;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Plan/subscription usage service. Per-provider adapters query provider quota
3
- * endpoints (5-minute cache each) so /usage can show subscription windows
3
+ * endpoints (60-second cache each) so /usage and the footer can show subscription windows
4
4
  * alongside session/context totals.
5
5
  *
6
6
  * Deliberately absent adapters:
@@ -50,8 +50,33 @@ const ADAPTERS = {
50
50
  zai: fetchZaiPlanUsage,
51
51
  xai: fetchXaiPlanUsage,
52
52
  };
53
- export const PLAN_USAGE_CACHE_TTL_MS = 5 * 60 * 1000;
53
+ export const PLAN_USAGE_CACHE_TTL_MS = 60 * 1000;
54
+ export function isWeeklyPlanWindow(window) {
55
+ return /week/i.test(window.label);
56
+ }
57
+ export function isFiveHourPlanWindow(window) {
58
+ return /5h/i.test(window.label) || window.label === "5h";
59
+ }
60
+ /** Preferred window, falling back to the other, skipping Extra/on-demand. */
61
+ export function pickPlanWindow(usage, preferred) {
62
+ if (!usage?.windows.length)
63
+ return undefined;
64
+ const usable = usage.windows.filter((w) => !/extra/i.test(w.label));
65
+ const weekly = usable.find(isWeeklyPlanWindow);
66
+ const fiveH = usable.find(isFiveHourPlanWindow);
67
+ if (preferred === "5h")
68
+ return fiveH ?? weekly ?? usable[0] ?? usage.windows[0];
69
+ return weekly ?? fiveH ?? usable[0] ?? usage.windows[0];
70
+ }
71
+ export function footerPlanLabel(window) {
72
+ if (isFiveHourPlanWindow(window))
73
+ return "5h";
74
+ if (isWeeklyPlanWindow(window))
75
+ return "wk";
76
+ return window.label.length <= 4 ? window.label : window.label.slice(0, 4);
77
+ }
54
78
  const cache = new Map();
79
+ const inflight = new Map();
55
80
  /** Whether a plan-usage adapter exists for this provider. */
56
81
  export function hasPlanUsageAdapter(providerId) {
57
82
  return providerId in ADAPTERS;
@@ -69,24 +94,76 @@ export async function getPlanUsageResult(providerId, runtime) {
69
94
  const cached = cache.get(providerId);
70
95
  if (cached && cached.expiresAt > now)
71
96
  return { usage: cached.value };
72
- try {
73
- const value = await adapter(runtime);
74
- cache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });
75
- return { usage: value };
76
- }
77
- catch (error) {
78
- const authError = planUsageAuthError(error);
79
- if (authError)
80
- return { error: authError };
81
- cache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value: undefined });
82
- return {};
83
- }
97
+ const pending = inflight.get(providerId);
98
+ if (pending)
99
+ return pending;
100
+ const task = (async () => {
101
+ try {
102
+ const value = await adapter(runtime);
103
+ cache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value });
104
+ return { usage: value };
105
+ }
106
+ catch (error) {
107
+ const authError = planUsageAuthError(error);
108
+ if (authError)
109
+ return { error: authError };
110
+ cache.set(providerId, { expiresAt: Date.now() + PLAN_USAGE_CACHE_TTL_MS, value: undefined });
111
+ return {};
112
+ }
113
+ finally {
114
+ inflight.delete(providerId);
115
+ }
116
+ })();
117
+ inflight.set(providerId, task);
118
+ return task;
119
+ }
120
+ /** Last fetched usage, including expired cache (footer can show stale while refetching). */
121
+ export function peekPlanUsage(providerId) {
122
+ return cache.get(providerId)?.value;
84
123
  }
85
124
  /** Clear the adapter cache (tests, /login changes). */
86
125
  export function clearPlanUsageCache() {
87
126
  cache.clear();
127
+ inflight.clear();
88
128
  }
89
129
  // ---------------------------------------------------------------------------
90
130
  // Extension bridge
91
131
  // ---------------------------------------------------------------------------
132
+ export const USAGE_SERVICE_BRIDGE_SYMBOL = Symbol.for("@lunr/usage-service");
133
+ let activeRuntime;
134
+ let activeUsageSettings;
135
+ let onUsageUpdate;
136
+ function preferredWindow() {
137
+ return activeUsageSettings?.getPlanUsageWindow() ?? "weekly";
138
+ }
139
+ const usageBridge = {
140
+ peek(providerId) {
141
+ return peekPlanUsage(providerId);
142
+ },
143
+ prefetch(providerId) {
144
+ if (!activeRuntime || !hasPlanUsageAdapter(providerId))
145
+ return;
146
+ void getPlanUsage(providerId, activeRuntime).then(() => onUsageUpdate?.());
147
+ },
148
+ setOnUpdate(fn) {
149
+ onUsageUpdate = fn;
150
+ },
151
+ getPreferredWindow() {
152
+ return preferredWindow();
153
+ },
154
+ pickForFooter(providerId) {
155
+ const window = pickPlanWindow(peekPlanUsage(providerId), preferredWindow());
156
+ if (!window)
157
+ return undefined;
158
+ return { label: footerPlanLabel(window), usedPercent: window.usedPercent };
159
+ },
160
+ };
161
+ export function registerUsageServiceBridge(runtime, settingsManager) {
162
+ activeRuntime = runtime;
163
+ activeUsageSettings = settingsManager;
164
+ globalThis[USAGE_SERVICE_BRIDGE_SYMBOL] = usageBridge;
165
+ }
166
+ export function getUsageServiceBridge() {
167
+ return globalThis[USAGE_SERVICE_BRIDGE_SYMBOL];
168
+ }
92
169
  //# sourceMappingURL=usage-service.js.map