@oxbit/cli 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/dist/assets/index-BrBnidfI.js +1954 -0
- package/agent/dist/index.js +5635 -0
- package/package.json +2 -1
- package/runtime/dist/index.js +460 -35
- package/runtime/package.json +1 -1
- package/web/dist/assets/index-CUIuo9fs.js +311 -0
- package/web/dist/assets/{index-DoZNi2PS.css → index-TC7_qqA1.css} +1 -1
- package/web/dist/assets/{typescript-BDEBNDpD.js → typescript-BU_Up1oE.js} +2 -2
- package/web/dist/index.html +2 -2
- package/web/dist/schemas/settings.v1.schema.json +66 -0
- package/web/dist/sdk/index.js +97 -0
- package/web/dist/assets/index-O78N-E-Z.js +0 -259
package/runtime/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { realpathSync, constants as constants$1, watch, createWriteStream } from "node:fs";
|
|
2
|
+
import { realpathSync, constants as constants$1, watch, createWriteStream, existsSync } from "node:fs";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import * as fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
@@ -933,11 +933,11 @@ const $id$1 = "https://oxbit.dev/schemas/settings.v1.schema.json";
|
|
|
933
933
|
const title$2 = "Oxbit Settings";
|
|
934
934
|
const description$2 = "User, private workspace and repository settings. Literal dotted IDs; objects merge recursively, arrays and scalar values replace. Unrecognized extension settings are preserved. Null is a value, not a reset, and must be valid for its setting.";
|
|
935
935
|
const type$2 = "object";
|
|
936
|
-
const properties$2 = /* @__PURE__ */ JSON.parse(`{"$schema":{"type":"string","description":"JSON Schema URI. Ignored when merging effective preferences."},"agentACP.provider":{"title":"Default agent","description":"A built-in agent ID, an ACP Registry agent ID, or custom.","type":"string","default":"codex"},"agentACP.useModifierToSend":{"title":"Send with Ctrl/Cmd+Enter only","description":"Enter inserts a new line and Ctrl/Cmd+Enter sends the message.","type":"boolean","default":false},"agentACP.notifications":{"title":"Agent desktop notifications","description":"Show a system notification when the agent needs input or finishes while Oxbit is in the background.","type":"string","default":"whenHidden","enum":["whenHidden","never"]},"agentACP.codex.command":{"title":"Codex ACP executable","type":"string","default":"npx"},"agentACP.codex.args":{"title":"Codex ACP arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@agentclientprotocol/codex-acp@2.2.2\\"]"},"agentACP.claude.command":{"title":"Claude Agent executable","type":"string","default":"npx"},"agentACP.claude.args":{"title":"Claude Agent arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@agentclientprotocol/claude-agent-acp@0.89.1\\"]"},"agentACP.gemini.command":{"title":"Gemini CLI executable","type":"string","default":"npx"},"agentACP.gemini.args":{"title":"Gemini CLI arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@google/gemini-cli@0.63.0\\",\\"--acp\\"]"},"agentACP.copilot.command":{"title":"GitHub Copilot executable","type":"string","default":"npx"},"agentACP.copilot.args":{"title":"GitHub Copilot arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@github/copilot@1.0.95\\",\\"--acp\\"]"},"agentACP.cursor.command":{"title":"Cursor ACP executable","type":"string","default":"agent"},"agentACP.cursor.args":{"title":"Cursor ACP arguments (JSON array)","type":"string","default":"[\\"acp\\"]"},"agentACP.amp.command":{"title":"Amp Agent ACP executable","type":"string","default":"npx"},"agentACP.amp.args":{"title":"Amp Agent ACP arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"amp-acp@0.10.0\\"]"},"agentACP.custom.name":{"title":"Custom agent name","type":"string","default":""},"agentACP.custom.command":{"title":"Custom agent executable","type":"string","default":""},"agentACP.custom.args":{"title":"Custom agent arguments (JSON array)","type":"string","default":"[]"},"workbench.keymap":{"title":"Keymap","description":"Keyboard layout applied on top of the Oxbit defaults. User keybindings always win.","type":"string","default":"default","enum":["default","vscode","jetbrains","macos","sublime","atom","visual-studio","emacs"]},"runtime.keepAlive":{"title":"Keep Runtime Alive","description":"How long a runtime Oxbit started keeps running after the last client disconnects or its connection heartbeats stop. Terminals and tasks continue while it runs.","type":"string","default":"75s","enum":["75s","15m","1h","8h","untilStopped"]},"runtime.autoReconnect":{"title":"Reconnect Automatically","description":"Reconnect to the runtime after the connection drops, including when the iOS app returns to the foreground.","type":"boolean","default":true},"workbench.tooltipDelay":{"title":"Tooltip Delay","description":"Delay in milliseconds before showing a tooltip on hover. Keyboard focus shows tooltips immediately.","type":"number","default":400,"minimum":0,"maximum":5000},"workbench.colorTheme":{"title":"Color Theme","description":"Specifies the color theme used in the workbench.","type":"string","default":"Graphite (dark)"},"workbench.density":{"title":"Layout Density","description":"Controls row heights, padding and label sizes across the workbench.","type":"string","default":"compact","enum":["compact","comfortable"]},"workbench.sidebarLocation":{"title":"Sidebar Location","description":"Where the primary sidebar is docked.","type":"string","default":"left","enum":["left","right"]},"editor.fontFamily":{"title":"Font Family","description":"Controls the font family of the editor.","type":"string","default":"'JetBrains Mono', ui-monospace, monospace"},"editor.fontSize":{"title":"Font Size","description":"Font size in pixels.","type":"number","default":13,"minimum":8,"maximum":32},"editor.lineHeight":{"title":"Line Height","description":"Line height in pixels. 0 uses 1.55 × font size.","type":"number","default":20,"minimum":0,"maximum":60},"editor.fontLigatures":{"title":"Font Ligatures","description":"Enables font ligatures when the font supports them.","type":"boolean","default":false},"editor.tabSize":{"title":"Tab Size","description":"The number of spaces a tab is equal to.","type":"number","default":2,"minimum":1,"maximum":8},"editor.insertSpaces":{"title":"Insert Spaces","description":"Insert spaces when pressing Tab.","type":"boolean","default":true},"editor.detectIndentation":{"title":"Detect Indentation","description":"Detect Tab Size and Insert Spaces from file contents on open.","type":"boolean","default":true},"editor.renderIndentGuides":{"title":"Indentation Guides","description":"Render vertical guides for each indent level.","type":"boolean","default":true},"editor.wordWrap":{"title":"Word Wrap","description":"Controls how lines should wrap.","type":"string","default":"off","enum":["off","on","bounded"]},"editor.renderWhitespace":{"title":"Render Whitespace","description":"Controls how the editor renders whitespace characters.","type":"string","default":"selection","enum":["none","boundary","selection","all"]},"editor.cursorBlinking":{"title":"Cursor Blinking","description":"Cursor animation style.","type":"string","default":"blink","enum":["blink","smooth","phase","solid"]},"editor.minimap":{"title":"Minimap","description":"Show a minimap of the document.","type":"boolean","default":false},"files.autoSave":{"title":"Auto Save","description":"Controls auto save of editors that have unsaved changes.","type":"string","default":"off","enum":["off","afterDelay","onFocusChange","onWindowChange"]},"files.autoSaveDelay":{"title":"Auto Save Delay","description":"Delay in milliseconds after which an editor is saved automatically. Applies when Auto Save is afterDelay.","type":"number","default":1000,"minimum":100,"maximum":60000},"files.trimTrailingWhitespace":{"title":"Trim Trailing Whitespace","description":"Remove trailing whitespace when saving.","type":"boolean","default":true},"editor.formatOnSave":{"title":"Format On Save","description":"Format a file on save. A formatter must be available.","type":"boolean","default":false},"editor.defaultFormatter":{"title":"Default Formatter","description":"Formatter used when several are available.","type":"string","default":"oxbit.prettier","anyOf":[{"enum":["oxbit.prettier","oxbit.builtin-ts"]},{"type":"string"}]},"terminal.fontSize":{"title":"Terminal Font Size","description":"Font size in pixels for the terminal.","type":"number","default":12,"minimum":8,"maximum":32},"terminal.scrollback":{"title":"Scrollback","description":"Maximum number of lines kept in the terminal buffer.","type":"number","default":5000,"minimum":100,"maximum":100000},"terminal.confirmOnKill":{"title":"Confirm On Kill","description":"Ask before killing a terminal with a running process.","type":"boolean","default":true},"scm.autoFetch":{"title":"Auto Fetch","description":"Periodically fetch from the default remote.","type":"boolean","default":true},"scm.diffLayout":{"title":"Diff Layout","description":"Default layout for diff editors.","type":"string","default":"side-by-side","enum":["side-by-side","inline"]},"files.associations":{"title":"File Associations","description":"Map filename or workspace-relative glob patterns to language IDs. Explicit associations take precedence over built-in detection.","type":"object","default":{},"propertyNames":{"minLength":1,"maxLength":1024},"additionalProperties":{"type":"string","pattern":"^[\\\\w+-]+$"}},"languageServers":{"title":"Language Servers","description":"Configure enabled state, selectors, rootMarkers, executable, args, env, initializationOptions, settings, and priority by server ID. Servers install on first use in a trusted runtime. License keys belong in the runtime-local credential file.","type":"object","default":{},"propertyNames":{"pattern":"^[a-zA-Z0-9._-]+$"},"additionalProperties":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable this language server."},"selectors":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string"},"pattern":{"type":"string"},"scheme":{"const":"file"}},"additionalProperties":false,"minProperties":1}},"rootMarkers":{"type":"array","items":{"type":"string","pattern":"^(?!/)(?!.*\\\\\\\\)(?!.*(?:^|/)\\\\.\\\\.(?:/|$))[^\\\\u0000]+$","minLength":1}},"executable":{"type":"string","pattern":"^[^\\\\u0000]*$","minLength":1},"args":{"type":"array","items":{"type":"string","pattern":"^[^\\\\u0000]*$"}},"env":{"type":"object","propertyNames":{"pattern":"^[A-Za-z_][A-Za-z0-9_]*$"},"additionalProperties":{"type":"string","pattern":"^[^\\\\u0000]*$"}},"initializationOptions":{"type":"object","additionalProperties":true,"description":"Server-specific initialization options. Store license credentials in the runtime credential file."},"settings":{"type":"object","additionalProperties":true,"description":"Server-specific configuration; nested objects merge across files."},"priority":{"type":"number"}},"additionalProperties":false}},"ui.fontFamily":{"title":"UI Font Family","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":""},"ui.fontSize":{"title":"UI Font Size","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":12,"minimum":8,"maximum":72},"ui.fontWeight":{"title":"UI Font Weight","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":400,"minimum":100,"maximum":900},"ui.fontStyle":{"title":"UI Font Style","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":"normal","enum":["normal","italic","oblique"]},"ui.lineHeight":{"title":"UI Line Height","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":1.4,"minimum":1,"maximum":3},"ui.letterSpacing":{"title":"UI Letter Spacing","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":0,"minimum":-3,"maximum":10},"ui.fontLigatures":{"title":"UI Font Ligatures","description":"Overrides theme typography. Reset restores the theme value.","type":"boolean","default":false},"terminal.fontFamily":{"title":"Terminal Font Family","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":""},"terminal.fontWeight":{"title":"Terminal Font Weight","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":400,"minimum":100,"maximum":900},"terminal.fontStyle":{"title":"Terminal Font Style","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":"normal","enum":["normal","italic","oblique"]},"terminal.lineHeight":{"title":"Terminal Line Height","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":1,"minimum":1,"maximum":3},"terminal.letterSpacing":{"title":"Terminal Letter Spacing","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":0,"minimum":-3,"maximum":10},"terminal.fontLigatures":{"title":"Terminal Font Ligatures","description":"Overrides theme typography. Reset restores the theme value.","type":"boolean","default":false},"workbench.iconTheme":{"title":"File Icon Theme","description":"Select a locally installed icon theme. Unavailable selections use Oxbit defaults until restored.","type":"string","default":"oxbit.default"},"workbench.productIconTheme":{"title":"Product Icon Theme","description":"Select a locally installed icon theme. Unavailable selections use Oxbit defaults until restored.","type":"string","default":"oxbit.default"},"editor.semanticHighlighting":{"title":"Semantic Highlighting","description":"Color symbols using language server information.","type":"boolean","default":true},"editor.inlayHints.types":{"title":"Type Inlay Hints","description":"Show supported type hints in the visible editor.","type":"boolean","default":true},"editor.inlayHints.parameters":{"title":"Parameter Inlay Hints","description":"Show supported parameter hints in the visible editor.","type":"boolean","default":true},"editor.largeFileIntelligence":{"title":"Large File Intelligence","description":"Allow full semantic highlighting and inlay hints for files larger than 1 MiB.","type":"boolean","default":false},"workbench.locale":{"title":"Display Language","type":"string","default":"en","enum":["en","de","es","ja","zh"]},"workbench.reducedMotion":{"title":"Reduced Motion","type":"boolean","default":false},"desktop.projects.openBehavior":{"title":"Open projects","type":"string","default":"currentWindow","enum":["currentWindow","newWindow"]},"desktop.tools.gitPath":{"title":"git executable path","type":"string","default":""},"desktop.tools.ghPath":{"title":"gh executable path","type":"string","default":""},"project.intelligence":{"type":"object","properties":{"enabled":{"type":"boolean","default":true,"description":"Index project dependencies, imports and related files."},"exclude":{"type":"array","items":{"type":"string","maxLength":1024},"default":[]},"maxFiles":{"type":"integer","minimum":1,"maximum":100000,"default":20000},"maxFileBytes":{"type":"integer","minimum":1,"maximum":5242880,"default":1048576}},"additionalProperties":false,"title":"Project Intelligence","description":"Partial overrides of project.json intelligence. Objects merge across files."},"project.schemas":{"type":"object","properties":{"catalog":{"type":"boolean","default":true,"description":"Discover file schemas through SchemaStore. Bundled Oxbit settings support remains available."},"download":{"type":"boolean","default":true,"description":"Allow remote schema downloads; cached and bundled schemas work offline."},"associations":{"type":"array","maxItems":1000,"default":[],"items":{"type":"object","properties":{"url":{"type":"string","minLength":1,"description":"Schema URL or workspace file URI."},"fileMatch":{"type":"array","items":{"type":"string","maxLength":1024}},"schema":{"type":["object","boolean"],"description":"An inline JSON Schema."}},"additionalProperties":false,"anyOf":[{"required":["url"]},{"required":["schema"]}]}}},"additionalProperties":false,"title":"JSON Schemas","description":"Partial overrides of project.json schemas. Association arrays replace lower arrays."}}`);
|
|
936
|
+
const properties$2 = /* @__PURE__ */ JSON.parse(`{"$schema":{"type":"string","description":"JSON Schema URI. Ignored when merging effective preferences."},"agentACP.provider":{"title":"Default agent","description":"A built-in agent ID, an ACP Registry agent ID, or custom.","type":"string","default":"codex"},"agentACP.useModifierToSend":{"title":"Send with Ctrl/Cmd+Enter only","description":"Enter inserts a new line and Ctrl/Cmd+Enter sends the message.","type":"boolean","default":false},"agentACP.notifications":{"title":"Agent desktop notifications","description":"Show a system notification when the agent needs input or finishes while Oxbit is in the background.","type":"string","default":"whenHidden","enum":["whenHidden","never"]},"agentACP.autoApplyEdits":{"title":"Auto-apply agent edits","description":"New conversations save agent file changes without review. Undo stays available, and permission prompts still ask.","type":"boolean","default":false},"agentACP.generateTitles":{"title":"Generate conversation titles","description":"When an agent does not name a conversation, ask the Oxbit Agent model for a short title after the first reply.","type":"boolean","default":true},"agentACP.oxbit-cli.command":{"title":"Oxbit Agent CLI executable","type":"string","default":"oxbit-agent"},"agentACP.oxbit-cli.args":{"title":"Oxbit Agent CLI arguments (JSON array)","type":"string","default":"[\\"acp\\"]"},"agentACP.codex.command":{"title":"Codex ACP executable","type":"string","default":"npx"},"agentACP.codex.args":{"title":"Codex ACP arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@agentclientprotocol/codex-acp@2.2.2\\"]"},"agentACP.claude.command":{"title":"Claude Agent executable","type":"string","default":"npx"},"agentACP.claude.args":{"title":"Claude Agent arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@agentclientprotocol/claude-agent-acp@0.89.1\\"]"},"agentACP.gemini.command":{"title":"Gemini CLI executable","type":"string","default":"npx"},"agentACP.gemini.args":{"title":"Gemini CLI arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@google/gemini-cli@0.63.0\\",\\"--acp\\"]"},"agentACP.copilot.command":{"title":"GitHub Copilot executable","type":"string","default":"npx"},"agentACP.copilot.args":{"title":"GitHub Copilot arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"@github/copilot@1.0.95\\",\\"--acp\\"]"},"agentACP.cursor.command":{"title":"Cursor ACP executable","type":"string","default":"agent"},"agentACP.cursor.args":{"title":"Cursor ACP arguments (JSON array)","type":"string","default":"[\\"acp\\"]"},"agentACP.amp.command":{"title":"Amp Agent ACP executable","type":"string","default":"npx"},"agentACP.amp.args":{"title":"Amp Agent ACP arguments (JSON array)","type":"string","default":"[\\"-y\\",\\"amp-acp@0.10.0\\"]"},"agentACP.custom.name":{"title":"Custom agent name","type":"string","default":""},"agentACP.custom.command":{"title":"Custom agent executable","type":"string","default":""},"agentACP.custom.args":{"title":"Custom agent arguments (JSON array)","type":"string","default":"[]"},"agentACP.oxbit.api":{"title":"Oxbit Agent API","description":"openai uses the Responses API, anthropic the Messages API, and openai-compatible Chat Completions at the base URL.","type":"string","default":"openai","enum":["openai","anthropic","openai-compatible"]},"agentACP.oxbit.baseUrl":{"title":"Oxbit Agent base URL","description":"Origin and path prefix for openai-compatible, for example https://openrouter.ai/api.","type":"string","default":""},"agentACP.oxbit.model":{"title":"Oxbit Agent model","description":"Model ID for new conversations.","type":"string","default":""},"workbench.keymap":{"title":"Keymap","description":"Keyboard layout applied on top of the Oxbit defaults. User keybindings always win.","type":"string","default":"default","enum":["default","vscode","jetbrains","macos","sublime","atom","visual-studio","emacs"]},"runtime.keepAlive":{"title":"Keep Runtime Alive","description":"How long a runtime Oxbit started keeps running after the last client disconnects or its connection heartbeats stop. Terminals and tasks continue while it runs.","type":"string","default":"75s","enum":["75s","15m","1h","8h","untilStopped"]},"runtime.autoReconnect":{"title":"Reconnect Automatically","description":"Reconnect to the runtime after the connection drops, including when the iOS app returns to the foreground.","type":"boolean","default":true},"workbench.tooltipDelay":{"title":"Tooltip Delay","description":"Delay in milliseconds before showing a tooltip on hover. Keyboard focus shows tooltips immediately.","type":"number","default":400,"minimum":0,"maximum":5000},"workbench.colorTheme":{"title":"Color Theme","description":"Specifies the color theme used in the workbench.","type":"string","default":"Graphite (dark)"},"workbench.density":{"title":"Layout Density","description":"Controls row heights, padding and label sizes across the workbench.","type":"string","default":"compact","enum":["compact","comfortable"]},"workbench.sidebarLocation":{"title":"Sidebar Location","description":"Where the primary sidebar is docked.","type":"string","default":"left","enum":["left","right"]},"editor.fontFamily":{"title":"Font Family","description":"Controls the font family of the editor.","type":"string","default":"'JetBrains Mono', ui-monospace, monospace"},"editor.fontSize":{"title":"Font Size","description":"Font size in pixels.","type":"number","default":13,"minimum":8,"maximum":32},"editor.lineHeight":{"title":"Line Height","description":"Line height in pixels. 0 uses 1.55 × font size.","type":"number","default":20,"minimum":0,"maximum":60},"editor.fontLigatures":{"title":"Font Ligatures","description":"Enables font ligatures when the font supports them.","type":"boolean","default":false},"editor.tabSize":{"title":"Tab Size","description":"The number of spaces a tab is equal to.","type":"number","default":2,"minimum":1,"maximum":8},"editor.insertSpaces":{"title":"Insert Spaces","description":"Insert spaces when pressing Tab.","type":"boolean","default":true},"editor.detectIndentation":{"title":"Detect Indentation","description":"Detect Tab Size and Insert Spaces from file contents on open.","type":"boolean","default":true},"editor.renderIndentGuides":{"title":"Indentation Guides","description":"Render vertical guides for each indent level.","type":"boolean","default":true},"editor.wordWrap":{"title":"Word Wrap","description":"Controls how lines should wrap.","type":"string","default":"off","enum":["off","on","bounded"]},"editor.renderWhitespace":{"title":"Render Whitespace","description":"Controls how the editor renders whitespace characters.","type":"string","default":"selection","enum":["none","boundary","selection","all"]},"editor.cursorBlinking":{"title":"Cursor Blinking","description":"Cursor animation style.","type":"string","default":"blink","enum":["blink","smooth","phase","solid"]},"editor.minimap":{"title":"Minimap","description":"Show a minimap of the document.","type":"boolean","default":false},"files.autoSave":{"title":"Auto Save","description":"Controls auto save of editors that have unsaved changes.","type":"string","default":"off","enum":["off","afterDelay","onFocusChange","onWindowChange"]},"files.autoSaveDelay":{"title":"Auto Save Delay","description":"Delay in milliseconds after which an editor is saved automatically. Applies when Auto Save is afterDelay.","type":"number","default":1000,"minimum":100,"maximum":60000},"files.trimTrailingWhitespace":{"title":"Trim Trailing Whitespace","description":"Remove trailing whitespace when saving.","type":"boolean","default":true},"editor.formatOnSave":{"title":"Format On Save","description":"Format a file on save. A formatter must be available.","type":"boolean","default":false},"editor.defaultFormatter":{"title":"Default Formatter","description":"Formatter used when several are available.","type":"string","default":"oxbit.prettier","anyOf":[{"enum":["oxbit.prettier","oxbit.builtin-ts"]},{"type":"string"}]},"terminal.fontSize":{"title":"Terminal Font Size","description":"Font size in pixels for the terminal.","type":"number","default":12,"minimum":8,"maximum":32},"terminal.scrollback":{"title":"Scrollback","description":"Maximum number of lines kept in the terminal buffer.","type":"number","default":5000,"minimum":100,"maximum":100000},"terminal.confirmOnKill":{"title":"Confirm On Kill","description":"Ask before killing a terminal with a running process.","type":"boolean","default":true},"scm.autoFetch":{"title":"Auto Fetch","description":"Periodically fetch from the default remote.","type":"boolean","default":true},"scm.diffLayout":{"title":"Diff Layout","description":"Default layout for diff editors.","type":"string","default":"side-by-side","enum":["side-by-side","inline"]},"files.associations":{"title":"File Associations","description":"Map filename or workspace-relative glob patterns to language IDs. Explicit associations take precedence over built-in detection.","type":"object","default":{},"propertyNames":{"minLength":1,"maxLength":1024},"additionalProperties":{"type":"string","pattern":"^[\\\\w+-]+$"}},"languageServers":{"title":"Language Servers","description":"Configure enabled state, selectors, rootMarkers, executable, args, env, initializationOptions, settings, and priority by server ID. Servers install on first use in a trusted runtime. License keys belong in the runtime-local credential file.","type":"object","default":{},"propertyNames":{"pattern":"^[a-zA-Z0-9._-]+$"},"additionalProperties":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable this language server."},"selectors":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string"},"pattern":{"type":"string"},"scheme":{"const":"file"}},"additionalProperties":false,"minProperties":1}},"rootMarkers":{"type":"array","items":{"type":"string","pattern":"^(?!/)(?!.*\\\\\\\\)(?!.*(?:^|/)\\\\.\\\\.(?:/|$))[^\\\\u0000]+$","minLength":1}},"executable":{"type":"string","pattern":"^[^\\\\u0000]*$","minLength":1},"args":{"type":"array","items":{"type":"string","pattern":"^[^\\\\u0000]*$"}},"env":{"type":"object","propertyNames":{"pattern":"^[A-Za-z_][A-Za-z0-9_]*$"},"additionalProperties":{"type":"string","pattern":"^[^\\\\u0000]*$"}},"initializationOptions":{"type":"object","additionalProperties":true,"description":"Server-specific initialization options. Store license credentials in the runtime credential file."},"settings":{"type":"object","additionalProperties":true,"description":"Server-specific configuration; nested objects merge across files."},"priority":{"type":"number"}},"additionalProperties":false}},"ui.fontFamily":{"title":"UI Font Family","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":""},"ui.fontSize":{"title":"UI Font Size","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":12,"minimum":8,"maximum":72},"ui.fontWeight":{"title":"UI Font Weight","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":400,"minimum":100,"maximum":900},"ui.fontStyle":{"title":"UI Font Style","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":"normal","enum":["normal","italic","oblique"]},"ui.lineHeight":{"title":"UI Line Height","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":1.4,"minimum":1,"maximum":3},"ui.letterSpacing":{"title":"UI Letter Spacing","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":0,"minimum":-3,"maximum":10},"ui.fontLigatures":{"title":"UI Font Ligatures","description":"Overrides theme typography. Reset restores the theme value.","type":"boolean","default":false},"terminal.fontFamily":{"title":"Terminal Font Family","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":""},"terminal.fontWeight":{"title":"Terminal Font Weight","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":400,"minimum":100,"maximum":900},"terminal.fontStyle":{"title":"Terminal Font Style","description":"Overrides theme typography. Reset restores the theme value.","type":"string","default":"normal","enum":["normal","italic","oblique"]},"terminal.lineHeight":{"title":"Terminal Line Height","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":1,"minimum":1,"maximum":3},"terminal.letterSpacing":{"title":"Terminal Letter Spacing","description":"Overrides theme typography. Reset restores the theme value.","type":"number","default":0,"minimum":-3,"maximum":10},"terminal.fontLigatures":{"title":"Terminal Font Ligatures","description":"Overrides theme typography. Reset restores the theme value.","type":"boolean","default":false},"workbench.iconTheme":{"title":"File Icon Theme","description":"Select a locally installed icon theme. Unavailable selections use Oxbit defaults until restored.","type":"string","default":"oxbit.default"},"workbench.productIconTheme":{"title":"Product Icon Theme","description":"Select a locally installed icon theme. Unavailable selections use Oxbit defaults until restored.","type":"string","default":"oxbit.default"},"editor.semanticHighlighting":{"title":"Semantic Highlighting","description":"Color symbols using language server information.","type":"boolean","default":true},"editor.inlayHints.types":{"title":"Type Inlay Hints","description":"Show supported type hints in the visible editor.","type":"boolean","default":true},"editor.inlayHints.parameters":{"title":"Parameter Inlay Hints","description":"Show supported parameter hints in the visible editor.","type":"boolean","default":true},"editor.largeFileIntelligence":{"title":"Large File Intelligence","description":"Allow full semantic highlighting and inlay hints for files larger than 1 MiB.","type":"boolean","default":false},"workbench.locale":{"title":"Display Language","type":"string","default":"en","enum":["en","de","es","ja","zh"]},"workbench.reducedMotion":{"title":"Reduced Motion","type":"boolean","default":false},"desktop.projects.openBehavior":{"title":"Open projects","type":"string","default":"currentWindow","enum":["currentWindow","newWindow"]},"desktop.tools.gitPath":{"title":"git executable path","type":"string","default":""},"desktop.tools.ghPath":{"title":"gh executable path","type":"string","default":""},"project.intelligence":{"type":"object","properties":{"enabled":{"type":"boolean","default":true,"description":"Index project dependencies, imports and related files."},"exclude":{"type":"array","items":{"type":"string","maxLength":1024},"default":[]},"maxFiles":{"type":"integer","minimum":1,"maximum":100000,"default":20000},"maxFileBytes":{"type":"integer","minimum":1,"maximum":5242880,"default":1048576}},"additionalProperties":false,"title":"Project Intelligence","description":"Partial overrides of project.json intelligence. Objects merge across files."},"project.schemas":{"type":"object","properties":{"catalog":{"type":"boolean","default":true,"description":"Discover file schemas through SchemaStore. Bundled Oxbit settings support remains available."},"download":{"type":"boolean","default":true,"description":"Allow remote schema downloads; cached and bundled schemas work offline."},"associations":{"type":"array","maxItems":1000,"default":[],"items":{"type":"object","properties":{"url":{"type":"string","minLength":1,"description":"Schema URL or workspace file URI."},"fileMatch":{"type":"array","items":{"type":"string","maxLength":1024}},"schema":{"type":["object","boolean"],"description":"An inline JSON Schema."}},"additionalProperties":false,"anyOf":[{"required":["url"]},{"required":["schema"]}]}}},"additionalProperties":false,"title":"JSON Schemas","description":"Partial overrides of project.json schemas. Association arrays replace lower arrays."}}`);
|
|
937
937
|
const propertyNames = { "anyOf": [{ "not": { "pattern": "^\\[.*\\]$" } }, { "pattern": "^\\[[^\\[\\]]+\\]$" }] };
|
|
938
938
|
const patternProperties = { "^\\[[^\\[\\]]+\\]$": { "$ref": "#/definitions/languageOverrides" } };
|
|
939
939
|
const additionalProperties$1 = true;
|
|
940
|
-
const definitions$1 = { "languageOverrides": { "type": "object", "properties": { "agentACP.provider": { "$ref": "#/properties/agentACP.provider" }, "agentACP.useModifierToSend": { "$ref": "#/properties/agentACP.useModifierToSend" }, "agentACP.notifications": { "$ref": "#/properties/agentACP.notifications" }, "agentACP.codex.command": { "$ref": "#/properties/agentACP.codex.command" }, "agentACP.codex.args": { "$ref": "#/properties/agentACP.codex.args" }, "agentACP.claude.command": { "$ref": "#/properties/agentACP.claude.command" }, "agentACP.claude.args": { "$ref": "#/properties/agentACP.claude.args" }, "agentACP.gemini.command": { "$ref": "#/properties/agentACP.gemini.command" }, "agentACP.gemini.args": { "$ref": "#/properties/agentACP.gemini.args" }, "agentACP.copilot.command": { "$ref": "#/properties/agentACP.copilot.command" }, "agentACP.copilot.args": { "$ref": "#/properties/agentACP.copilot.args" }, "agentACP.cursor.command": { "$ref": "#/properties/agentACP.cursor.command" }, "agentACP.cursor.args": { "$ref": "#/properties/agentACP.cursor.args" }, "agentACP.amp.command": { "$ref": "#/properties/agentACP.amp.command" }, "agentACP.amp.args": { "$ref": "#/properties/agentACP.amp.args" }, "agentACP.custom.name": { "$ref": "#/properties/agentACP.custom.name" }, "agentACP.custom.command": { "$ref": "#/properties/agentACP.custom.command" }, "agentACP.custom.args": { "$ref": "#/properties/agentACP.custom.args" }, "workbench.keymap": { "$ref": "#/properties/workbench.keymap" }, "runtime.keepAlive": { "$ref": "#/properties/runtime.keepAlive" }, "runtime.autoReconnect": { "$ref": "#/properties/runtime.autoReconnect" }, "workbench.tooltipDelay": { "$ref": "#/properties/workbench.tooltipDelay" }, "workbench.colorTheme": { "$ref": "#/properties/workbench.colorTheme" }, "workbench.density": { "$ref": "#/properties/workbench.density" }, "workbench.sidebarLocation": { "$ref": "#/properties/workbench.sidebarLocation" }, "editor.fontFamily": { "$ref": "#/properties/editor.fontFamily" }, "editor.fontSize": { "$ref": "#/properties/editor.fontSize" }, "editor.lineHeight": { "$ref": "#/properties/editor.lineHeight" }, "editor.fontLigatures": { "$ref": "#/properties/editor.fontLigatures" }, "editor.tabSize": { "$ref": "#/properties/editor.tabSize" }, "editor.insertSpaces": { "$ref": "#/properties/editor.insertSpaces" }, "editor.detectIndentation": { "$ref": "#/properties/editor.detectIndentation" }, "editor.renderIndentGuides": { "$ref": "#/properties/editor.renderIndentGuides" }, "editor.wordWrap": { "$ref": "#/properties/editor.wordWrap" }, "editor.renderWhitespace": { "$ref": "#/properties/editor.renderWhitespace" }, "editor.cursorBlinking": { "$ref": "#/properties/editor.cursorBlinking" }, "editor.minimap": { "$ref": "#/properties/editor.minimap" }, "files.autoSave": { "$ref": "#/properties/files.autoSave" }, "files.autoSaveDelay": { "$ref": "#/properties/files.autoSaveDelay" }, "files.trimTrailingWhitespace": { "$ref": "#/properties/files.trimTrailingWhitespace" }, "editor.formatOnSave": { "$ref": "#/properties/editor.formatOnSave" }, "editor.defaultFormatter": { "$ref": "#/properties/editor.defaultFormatter" }, "terminal.fontSize": { "$ref": "#/properties/terminal.fontSize" }, "terminal.scrollback": { "$ref": "#/properties/terminal.scrollback" }, "terminal.confirmOnKill": { "$ref": "#/properties/terminal.confirmOnKill" }, "scm.autoFetch": { "$ref": "#/properties/scm.autoFetch" }, "scm.diffLayout": { "$ref": "#/properties/scm.diffLayout" }, "files.associations": { "$ref": "#/properties/files.associations" }, "languageServers": { "$ref": "#/properties/languageServers" }, "ui.fontFamily": { "$ref": "#/properties/ui.fontFamily" }, "ui.fontSize": { "$ref": "#/properties/ui.fontSize" }, "ui.fontWeight": { "$ref": "#/properties/ui.fontWeight" }, "ui.fontStyle": { "$ref": "#/properties/ui.fontStyle" }, "ui.lineHeight": { "$ref": "#/properties/ui.lineHeight" }, "ui.letterSpacing": { "$ref": "#/properties/ui.letterSpacing" }, "ui.fontLigatures": { "$ref": "#/properties/ui.fontLigatures" }, "terminal.fontFamily": { "$ref": "#/properties/terminal.fontFamily" }, "terminal.fontWeight": { "$ref": "#/properties/terminal.fontWeight" }, "terminal.fontStyle": { "$ref": "#/properties/terminal.fontStyle" }, "terminal.lineHeight": { "$ref": "#/properties/terminal.lineHeight" }, "terminal.letterSpacing": { "$ref": "#/properties/terminal.letterSpacing" }, "terminal.fontLigatures": { "$ref": "#/properties/terminal.fontLigatures" }, "workbench.iconTheme": { "$ref": "#/properties/workbench.iconTheme" }, "workbench.productIconTheme": { "$ref": "#/properties/workbench.productIconTheme" }, "editor.semanticHighlighting": { "$ref": "#/properties/editor.semanticHighlighting" }, "editor.inlayHints.types": { "$ref": "#/properties/editor.inlayHints.types" }, "editor.inlayHints.parameters": { "$ref": "#/properties/editor.inlayHints.parameters" }, "editor.largeFileIntelligence": { "$ref": "#/properties/editor.largeFileIntelligence" }, "workbench.locale": { "$ref": "#/properties/workbench.locale" }, "workbench.reducedMotion": { "$ref": "#/properties/workbench.reducedMotion" }, "desktop.projects.openBehavior": { "$ref": "#/properties/desktop.projects.openBehavior" }, "desktop.tools.gitPath": { "$ref": "#/properties/desktop.tools.gitPath" }, "desktop.tools.ghPath": { "$ref": "#/properties/desktop.tools.ghPath" }, "project.intelligence": false, "project.schemas": false }, "additionalProperties": true, "description": "Settings for a language ID, such as [mdx] or [php]. Runtime project options belong at the top level.", "propertyNames": { "not": { "pattern": "^\\[.*\\]$" } } } };
|
|
940
|
+
const definitions$1 = { "languageOverrides": { "type": "object", "properties": { "agentACP.provider": { "$ref": "#/properties/agentACP.provider" }, "agentACP.useModifierToSend": { "$ref": "#/properties/agentACP.useModifierToSend" }, "agentACP.notifications": { "$ref": "#/properties/agentACP.notifications" }, "agentACP.autoApplyEdits": { "$ref": "#/properties/agentACP.autoApplyEdits" }, "agentACP.generateTitles": { "$ref": "#/properties/agentACP.generateTitles" }, "agentACP.oxbit-cli.command": { "$ref": "#/properties/agentACP.oxbit-cli.command" }, "agentACP.oxbit-cli.args": { "$ref": "#/properties/agentACP.oxbit-cli.args" }, "agentACP.codex.command": { "$ref": "#/properties/agentACP.codex.command" }, "agentACP.codex.args": { "$ref": "#/properties/agentACP.codex.args" }, "agentACP.claude.command": { "$ref": "#/properties/agentACP.claude.command" }, "agentACP.claude.args": { "$ref": "#/properties/agentACP.claude.args" }, "agentACP.gemini.command": { "$ref": "#/properties/agentACP.gemini.command" }, "agentACP.gemini.args": { "$ref": "#/properties/agentACP.gemini.args" }, "agentACP.copilot.command": { "$ref": "#/properties/agentACP.copilot.command" }, "agentACP.copilot.args": { "$ref": "#/properties/agentACP.copilot.args" }, "agentACP.cursor.command": { "$ref": "#/properties/agentACP.cursor.command" }, "agentACP.cursor.args": { "$ref": "#/properties/agentACP.cursor.args" }, "agentACP.amp.command": { "$ref": "#/properties/agentACP.amp.command" }, "agentACP.amp.args": { "$ref": "#/properties/agentACP.amp.args" }, "agentACP.custom.name": { "$ref": "#/properties/agentACP.custom.name" }, "agentACP.custom.command": { "$ref": "#/properties/agentACP.custom.command" }, "agentACP.custom.args": { "$ref": "#/properties/agentACP.custom.args" }, "agentACP.oxbit.api": { "$ref": "#/properties/agentACP.oxbit.api" }, "agentACP.oxbit.baseUrl": { "$ref": "#/properties/agentACP.oxbit.baseUrl" }, "agentACP.oxbit.model": { "$ref": "#/properties/agentACP.oxbit.model" }, "workbench.keymap": { "$ref": "#/properties/workbench.keymap" }, "runtime.keepAlive": { "$ref": "#/properties/runtime.keepAlive" }, "runtime.autoReconnect": { "$ref": "#/properties/runtime.autoReconnect" }, "workbench.tooltipDelay": { "$ref": "#/properties/workbench.tooltipDelay" }, "workbench.colorTheme": { "$ref": "#/properties/workbench.colorTheme" }, "workbench.density": { "$ref": "#/properties/workbench.density" }, "workbench.sidebarLocation": { "$ref": "#/properties/workbench.sidebarLocation" }, "editor.fontFamily": { "$ref": "#/properties/editor.fontFamily" }, "editor.fontSize": { "$ref": "#/properties/editor.fontSize" }, "editor.lineHeight": { "$ref": "#/properties/editor.lineHeight" }, "editor.fontLigatures": { "$ref": "#/properties/editor.fontLigatures" }, "editor.tabSize": { "$ref": "#/properties/editor.tabSize" }, "editor.insertSpaces": { "$ref": "#/properties/editor.insertSpaces" }, "editor.detectIndentation": { "$ref": "#/properties/editor.detectIndentation" }, "editor.renderIndentGuides": { "$ref": "#/properties/editor.renderIndentGuides" }, "editor.wordWrap": { "$ref": "#/properties/editor.wordWrap" }, "editor.renderWhitespace": { "$ref": "#/properties/editor.renderWhitespace" }, "editor.cursorBlinking": { "$ref": "#/properties/editor.cursorBlinking" }, "editor.minimap": { "$ref": "#/properties/editor.minimap" }, "files.autoSave": { "$ref": "#/properties/files.autoSave" }, "files.autoSaveDelay": { "$ref": "#/properties/files.autoSaveDelay" }, "files.trimTrailingWhitespace": { "$ref": "#/properties/files.trimTrailingWhitespace" }, "editor.formatOnSave": { "$ref": "#/properties/editor.formatOnSave" }, "editor.defaultFormatter": { "$ref": "#/properties/editor.defaultFormatter" }, "terminal.fontSize": { "$ref": "#/properties/terminal.fontSize" }, "terminal.scrollback": { "$ref": "#/properties/terminal.scrollback" }, "terminal.confirmOnKill": { "$ref": "#/properties/terminal.confirmOnKill" }, "scm.autoFetch": { "$ref": "#/properties/scm.autoFetch" }, "scm.diffLayout": { "$ref": "#/properties/scm.diffLayout" }, "files.associations": { "$ref": "#/properties/files.associations" }, "languageServers": { "$ref": "#/properties/languageServers" }, "ui.fontFamily": { "$ref": "#/properties/ui.fontFamily" }, "ui.fontSize": { "$ref": "#/properties/ui.fontSize" }, "ui.fontWeight": { "$ref": "#/properties/ui.fontWeight" }, "ui.fontStyle": { "$ref": "#/properties/ui.fontStyle" }, "ui.lineHeight": { "$ref": "#/properties/ui.lineHeight" }, "ui.letterSpacing": { "$ref": "#/properties/ui.letterSpacing" }, "ui.fontLigatures": { "$ref": "#/properties/ui.fontLigatures" }, "terminal.fontFamily": { "$ref": "#/properties/terminal.fontFamily" }, "terminal.fontWeight": { "$ref": "#/properties/terminal.fontWeight" }, "terminal.fontStyle": { "$ref": "#/properties/terminal.fontStyle" }, "terminal.lineHeight": { "$ref": "#/properties/terminal.lineHeight" }, "terminal.letterSpacing": { "$ref": "#/properties/terminal.letterSpacing" }, "terminal.fontLigatures": { "$ref": "#/properties/terminal.fontLigatures" }, "workbench.iconTheme": { "$ref": "#/properties/workbench.iconTheme" }, "workbench.productIconTheme": { "$ref": "#/properties/workbench.productIconTheme" }, "editor.semanticHighlighting": { "$ref": "#/properties/editor.semanticHighlighting" }, "editor.inlayHints.types": { "$ref": "#/properties/editor.inlayHints.types" }, "editor.inlayHints.parameters": { "$ref": "#/properties/editor.inlayHints.parameters" }, "editor.largeFileIntelligence": { "$ref": "#/properties/editor.largeFileIntelligence" }, "workbench.locale": { "$ref": "#/properties/workbench.locale" }, "workbench.reducedMotion": { "$ref": "#/properties/workbench.reducedMotion" }, "desktop.projects.openBehavior": { "$ref": "#/properties/desktop.projects.openBehavior" }, "desktop.tools.gitPath": { "$ref": "#/properties/desktop.tools.gitPath" }, "desktop.tools.ghPath": { "$ref": "#/properties/desktop.tools.ghPath" }, "project.intelligence": false, "project.schemas": false }, "additionalProperties": true, "description": "Settings for a language ID, such as [mdx] or [php]. Runtime project options belong at the top level.", "propertyNames": { "not": { "pattern": "^\\[.*\\]$" } } } };
|
|
941
941
|
const schema = {
|
|
942
942
|
$schema: $schema$2,
|
|
943
943
|
$id: $id$1,
|
|
@@ -1106,7 +1106,17 @@ function synchronization(capabilities) {
|
|
|
1106
1106
|
const sync = capabilities.textDocumentSync;
|
|
1107
1107
|
return typeof sync === "number" ? { openClose: true, change: sync } : sync ?? { openClose: false, change: 0 };
|
|
1108
1108
|
}
|
|
1109
|
+
const OXBIT_CLI_PROVIDER = "oxbit-cli";
|
|
1109
1110
|
const ACP_PROVIDERS = [
|
|
1111
|
+
{
|
|
1112
|
+
id: OXBIT_CLI_PROVIDER,
|
|
1113
|
+
name: "Oxbit Agent CLI",
|
|
1114
|
+
command: "oxbit-agent",
|
|
1115
|
+
args: ["acp"],
|
|
1116
|
+
setup: "Runs the oxbit-agent CLI that ships with Oxbit. It reads providers, keys, MCP servers, skills and hooks from ~/.oxbit/agent. Elsewhere, install @oxbit/agent from npm.",
|
|
1117
|
+
url: "https://github.com/yannelli/oxbit/tree/main/apps/agent",
|
|
1118
|
+
registryId: "oxbit-agent"
|
|
1119
|
+
},
|
|
1110
1120
|
{
|
|
1111
1121
|
id: "codex",
|
|
1112
1122
|
name: "Codex ACP",
|
|
@@ -1166,6 +1176,7 @@ const ACP_CUSTOM_PROVIDER = "custom";
|
|
|
1166
1176
|
const ACP_REGISTRY_URL = "https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json";
|
|
1167
1177
|
const acpPreset = (id) => ACP_PROVIDERS.find((provider) => provider.id === id);
|
|
1168
1178
|
const acpBuiltinForRegistry = (registryId) => ACP_PROVIDERS.find((provider) => provider.registryId === registryId);
|
|
1179
|
+
const PUSH_RELAY_URL = "https://oxbit-push.ryanyannelli.workers.dev";
|
|
1169
1180
|
const taskPhases = [
|
|
1170
1181
|
"preinit",
|
|
1171
1182
|
"init",
|
|
@@ -3456,6 +3467,8 @@ function bounded(value) {
|
|
|
3456
3467
|
);
|
|
3457
3468
|
return value;
|
|
3458
3469
|
}
|
|
3470
|
+
const BRANCH_DIFF_FILES = 50;
|
|
3471
|
+
const BRANCH_DIFF_TEXT = 2e5;
|
|
3459
3472
|
const conflicted = (index, working) => ["DD", "AU", "UD", "UA", "DU", "AA", "UU"].includes(index + working);
|
|
3460
3473
|
const digest$1 = (value) => createHash("sha256").update(value).digest("hex");
|
|
3461
3474
|
class Git {
|
|
@@ -3786,18 +3799,18 @@ class Git {
|
|
|
3786
3799
|
if (typeof params.path !== "string")
|
|
3787
3800
|
throw new RpcError("INVALID_PARAMS", "A file path is required");
|
|
3788
3801
|
await this.files.resolve(params.path, true);
|
|
3789
|
-
const
|
|
3802
|
+
const detail2 = await this.show(params.ref, signal), file = detail2.files.find((file2) => file2.path === params.path);
|
|
3790
3803
|
if (!file)
|
|
3791
3804
|
throw new RpcError("NOT_FOUND", "File is not part of this commit");
|
|
3792
|
-
const before =
|
|
3805
|
+
const before = detail2.commit.parents[0] ? await this.optional(
|
|
3793
3806
|
[
|
|
3794
3807
|
"show",
|
|
3795
|
-
`${
|
|
3808
|
+
`${detail2.commit.parents[0]}:${file.originalPath ?? file.path}`
|
|
3796
3809
|
],
|
|
3797
3810
|
signal
|
|
3798
3811
|
) : void 0;
|
|
3799
3812
|
const after = await this.optional(
|
|
3800
|
-
["show", `${
|
|
3813
|
+
["show", `${detail2.commit.id}:${file.path}`],
|
|
3801
3814
|
signal
|
|
3802
3815
|
);
|
|
3803
3816
|
const diff = await this.run(
|
|
@@ -3808,7 +3821,7 @@ class Git {
|
|
|
3808
3821
|
"--no-ext-diff",
|
|
3809
3822
|
"--no-textconv",
|
|
3810
3823
|
"--no-color",
|
|
3811
|
-
|
|
3824
|
+
detail2.commit.id,
|
|
3812
3825
|
"--",
|
|
3813
3826
|
file.path,
|
|
3814
3827
|
...file.originalPath ? [file.originalPath] : []
|
|
@@ -3866,6 +3879,88 @@ class Git {
|
|
|
3866
3879
|
)).stdout
|
|
3867
3880
|
});
|
|
3868
3881
|
}
|
|
3882
|
+
/** The upstream remote's default branch, then `origin/HEAD`, then local `main` or `master`. */
|
|
3883
|
+
async baseBranch(branch, signal) {
|
|
3884
|
+
const remote = branch ? (await this.optional(["config", "--get", `branch.${branch}.remote`], signal)).stdout.trim() : "";
|
|
3885
|
+
const candidates = [
|
|
3886
|
+
...remote && remote !== "." ? [`refs/remotes/${remote}/HEAD`] : [],
|
|
3887
|
+
"refs/remotes/origin/HEAD",
|
|
3888
|
+
"refs/heads/main",
|
|
3889
|
+
"refs/heads/master"
|
|
3890
|
+
];
|
|
3891
|
+
for (const ref of candidates) {
|
|
3892
|
+
const commit = await this.optional(
|
|
3893
|
+
["rev-parse", "--verify", "--quiet", "--end-of-options", `${ref}^{commit}`],
|
|
3894
|
+
signal
|
|
3895
|
+
);
|
|
3896
|
+
if (commit.exitCode) continue;
|
|
3897
|
+
const name = await this.optional(["rev-parse", "--abbrev-ref", ref], signal);
|
|
3898
|
+
return { name: name.stdout.trim() || ref, commit: commit.stdout.trim() };
|
|
3899
|
+
}
|
|
3900
|
+
return void 0;
|
|
3901
|
+
}
|
|
3902
|
+
async untrackedPatch(relative, signal) {
|
|
3903
|
+
const result = await this.run(
|
|
3904
|
+
["diff", "--no-index", "--no-ext-diff", "--no-textconv", "--no-color", "--src-prefix=a/", "--dst-prefix=b/", "--", "/dev/null", relative],
|
|
3905
|
+
signal,
|
|
3906
|
+
this.files.root,
|
|
3907
|
+
void 0,
|
|
3908
|
+
true
|
|
3909
|
+
);
|
|
3910
|
+
if (result.exitCode > 1)
|
|
3911
|
+
throw new RpcError("GIT_FAILED", result.stderr.trim() || `Git exited ${result.exitCode}`);
|
|
3912
|
+
return result.stdout;
|
|
3913
|
+
}
|
|
3914
|
+
/** Committed, staged, unstaged and untracked changes since the merge base with the base branch. */
|
|
3915
|
+
async branchDiff(params, signal) {
|
|
3916
|
+
const limit2 = Number(params.limit ?? BRANCH_DIFF_FILES);
|
|
3917
|
+
if (!Number.isInteger(limit2) || limit2 < 0 || limit2 > BRANCH_DIFF_FILES)
|
|
3918
|
+
throw new RpcError("INVALID_PARAMS", "Invalid file limit");
|
|
3919
|
+
const inside = await this.optional(["rev-parse", "--is-inside-work-tree"], signal);
|
|
3920
|
+
if (inside.exitCode || inside.stdout.trim() !== "true") {
|
|
3921
|
+
if (inside.exitCode && !inside.stderr.includes("not a git repository"))
|
|
3922
|
+
throw new RpcError("GIT_FAILED", inside.stderr.trim());
|
|
3923
|
+
return { repository: false };
|
|
3924
|
+
}
|
|
3925
|
+
const head = await this.head(signal);
|
|
3926
|
+
if (!head) throw new RpcError("NOT_FOUND", "This branch has no commits yet");
|
|
3927
|
+
const branch = (await this.optional(["symbolic-ref", "-q", "--short", "HEAD"], signal)).stdout.trim();
|
|
3928
|
+
const base = await this.baseBranch(branch, signal);
|
|
3929
|
+
if (!base) throw new RpcError("NOT_FOUND", "No base branch: origin/HEAD, main and master are missing");
|
|
3930
|
+
const mergeBase = await this.optional(["merge-base", base.commit, head], signal);
|
|
3931
|
+
if (mergeBase.exitCode)
|
|
3932
|
+
throw new RpcError("NOT_FOUND", `${branch || "HEAD"} has no common history with ${base.name}`);
|
|
3933
|
+
const from = mergeBase.stdout.trim();
|
|
3934
|
+
const names = async (args) => (await this.run(args, signal)).stdout.split("\0").filter(Boolean);
|
|
3935
|
+
const tracked = await names(["diff", "--name-only", "--relative", "-z", from, "--"]);
|
|
3936
|
+
const untracked = await names(["ls-files", "--others", "--exclude-standard", "-z", "--"]);
|
|
3937
|
+
const files = [];
|
|
3938
|
+
let size = 0, truncated = false;
|
|
3939
|
+
for (const [index, relative] of [...tracked, ...untracked].entries()) {
|
|
3940
|
+
if (files.length >= limit2 || size >= BRANCH_DIFF_TEXT) {
|
|
3941
|
+
truncated = true;
|
|
3942
|
+
break;
|
|
3943
|
+
}
|
|
3944
|
+
let diff = "";
|
|
3945
|
+
try {
|
|
3946
|
+
diff = index < tracked.length ? (await this.run(
|
|
3947
|
+
["diff", "--no-ext-diff", "--no-textconv", "--no-color", "--relative", "--src-prefix=a/", "--dst-prefix=b/", from, "--", relative],
|
|
3948
|
+
signal
|
|
3949
|
+
)).stdout : await this.untrackedPatch(relative, signal);
|
|
3950
|
+
} catch (error) {
|
|
3951
|
+
if (error.code !== "OUTPUT_LIMIT") throw error;
|
|
3952
|
+
truncated = true;
|
|
3953
|
+
}
|
|
3954
|
+
const binary2 = /^Binary files /m.test(diff);
|
|
3955
|
+
if (size + diff.length > BRANCH_DIFF_TEXT) {
|
|
3956
|
+
diff = diff.slice(0, BRANCH_DIFF_TEXT - size);
|
|
3957
|
+
truncated = true;
|
|
3958
|
+
}
|
|
3959
|
+
size += diff.length;
|
|
3960
|
+
files.push({ path: relative, diff, binary: binary2 });
|
|
3961
|
+
}
|
|
3962
|
+
return bounded({ base: base.name, head: branch || head.slice(0, 7), files, truncated });
|
|
3963
|
+
}
|
|
3869
3964
|
async action(method, params, signal, progress) {
|
|
3870
3965
|
const pending = this.queue.catch(() => {
|
|
3871
3966
|
}).then(() => this.execute(method, params, signal, progress));
|
|
@@ -4617,7 +4712,10 @@ class LanguageServer {
|
|
|
4617
4712
|
if (resume) this.paused = false;
|
|
4618
4713
|
if (!resume && this.phase === "failed") throw new RpcError("LSP_FAILED", this.error || "Language server failed. Retry from Language Servers.");
|
|
4619
4714
|
if (this.paused) throw new RpcError("LSP_STOPPED", "Language server is stopped. Start it from Language Servers.");
|
|
4620
|
-
if (this.starting)
|
|
4715
|
+
if (this.starting) {
|
|
4716
|
+
this.emit("oxbit/serverState", { state: this.phase });
|
|
4717
|
+
return this.starting;
|
|
4718
|
+
}
|
|
4621
4719
|
if (this.child && this.capabilities)
|
|
4622
4720
|
return { capabilities: this.capabilities, registrations: [...this.registrations.values()], rootUri: this.uri(""), projectRootUri: pathToFileURL(this.options.root ?? this.files.root).href, version: this.launchSpec?.version };
|
|
4623
4721
|
this.error = "";
|
|
@@ -5247,6 +5345,47 @@ function deferToRuff(spec) {
|
|
|
5247
5345
|
diagnostics: (diagnostics) => diagnostics.filter((item) => item.code !== void 0)
|
|
5248
5346
|
};
|
|
5249
5347
|
}
|
|
5348
|
+
const phpProbes = [
|
|
5349
|
+
{ command: ["herd", "which-php"], php: (output) => output.includes("No usable PHP version found") ? void 0 : [output.trim()] },
|
|
5350
|
+
{ command: ["valet", "which-php"], php: (output) => [output.trim()] },
|
|
5351
|
+
{ command: ["./vendor/bin/sail", "ps"], php: () => ["./vendor/bin/sail", "php"] },
|
|
5352
|
+
{ command: ["lando", "php", "-r", "echo PHP_BINARY;"], php: () => ["lando", "php"] },
|
|
5353
|
+
{ command: ["ddev", "php", "-r", "echo PHP_BINARY;"], php: () => ["ddev", "php"] },
|
|
5354
|
+
{ command: ["php", "-r", "echo PHP_BINARY;"], php: (output) => [output.trim()] }
|
|
5355
|
+
];
|
|
5356
|
+
function probe(command, cwd, env2, timeout, signal) {
|
|
5357
|
+
return new Promise((resolve) => {
|
|
5358
|
+
const child = spawn(command[0], command.slice(1), { cwd, env: env2, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "ignore"] });
|
|
5359
|
+
trackChild(child);
|
|
5360
|
+
let output = "";
|
|
5361
|
+
const finish = (value) => {
|
|
5362
|
+
clearTimeout(timer);
|
|
5363
|
+
signal?.removeEventListener("abort", stop2);
|
|
5364
|
+
resolve(value);
|
|
5365
|
+
};
|
|
5366
|
+
const stop2 = () => {
|
|
5367
|
+
killProcess(child);
|
|
5368
|
+
finish();
|
|
5369
|
+
};
|
|
5370
|
+
const timer = setTimeout(stop2, timeout);
|
|
5371
|
+
signal?.addEventListener("abort", stop2, { once: true });
|
|
5372
|
+
child.stdout.on("data", (data) => {
|
|
5373
|
+
output = (output + data.toString()).slice(-4096);
|
|
5374
|
+
});
|
|
5375
|
+
child.on("error", () => finish());
|
|
5376
|
+
child.on("close", (code) => finish(code === 0 ? output : void 0));
|
|
5377
|
+
});
|
|
5378
|
+
}
|
|
5379
|
+
async function laravelPhpCommand(root, env2, signal, timeout = 5e3) {
|
|
5380
|
+
for (const { command, php } of phpProbes) {
|
|
5381
|
+
signal?.throwIfAborted();
|
|
5382
|
+
const output = await probe(command, root, env2, timeout, signal);
|
|
5383
|
+
const found = output === void 0 ? void 0 : php(output);
|
|
5384
|
+
if (found?.[0]) return found;
|
|
5385
|
+
}
|
|
5386
|
+
signal?.throwIfAborted();
|
|
5387
|
+
throw new Error("Laravel needs PHP on the runtime host. No PHP was found through Herd, Valet, Sail, Lando, DDEV or php on PATH. Install PHP or set languageServers.laravel.initializationOptions.phpCommand.");
|
|
5388
|
+
}
|
|
5250
5389
|
const npmPresets = {
|
|
5251
5390
|
typescript: ["typescript-language-server", "lib/cli.mjs", ["typescript"]],
|
|
5252
5391
|
html: ["vscode-langservers-extracted", "bin/vscode-html-language-server"],
|
|
@@ -5487,19 +5626,22 @@ class ManagedInstaller {
|
|
|
5487
5626
|
}
|
|
5488
5627
|
}
|
|
5489
5628
|
} catch {
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
} catch {
|
|
5629
|
+
}
|
|
5630
|
+
try {
|
|
5631
|
+
if (Date.now() - (await fs.stat(lock)).mtimeMs > 6e4) {
|
|
5632
|
+
await fs.rm(lock, { recursive: true, force: true });
|
|
5633
|
+
continue;
|
|
5496
5634
|
}
|
|
5635
|
+
} catch {
|
|
5497
5636
|
}
|
|
5498
5637
|
if (Date.now() > deadline) throw new Error("Timed out waiting for another language server installation");
|
|
5499
5638
|
await setTimeout$1(100, void 0, { signal });
|
|
5500
5639
|
}
|
|
5501
5640
|
}
|
|
5502
5641
|
const stage = path.join(base, `.staging-${randomUUID()}`);
|
|
5642
|
+
const heartbeat = setInterval(() => void fs.utimes(lock, /* @__PURE__ */ new Date(), /* @__PURE__ */ new Date()).catch(() => {
|
|
5643
|
+
}), 1e4);
|
|
5644
|
+
heartbeat.unref();
|
|
5503
5645
|
try {
|
|
5504
5646
|
if (await complete()) return target;
|
|
5505
5647
|
for (const name of await fs.readdir(base)) if (name.startsWith(".staging-")) await fs.rm(path.join(base, name), { recursive: true, force: true });
|
|
@@ -5515,6 +5657,7 @@ class ManagedInstaller {
|
|
|
5515
5657
|
await fs.rename(stage, target);
|
|
5516
5658
|
return target;
|
|
5517
5659
|
} finally {
|
|
5660
|
+
clearInterval(heartbeat);
|
|
5518
5661
|
await fs.rm(stage, { recursive: true, force: true });
|
|
5519
5662
|
await fs.rm(lock, { recursive: true, force: true });
|
|
5520
5663
|
}
|
|
@@ -5813,6 +5956,8 @@ class LanguageServerManager {
|
|
|
5813
5956
|
else spec = await resolveLaunch(definition2.id, root, this.installer, signal);
|
|
5814
5957
|
spec = { ...spec, args: definition2.args ?? spec.args, env: { ...spec.env, ...definition2.env }, initializationOptions: merge(spec.initializationOptions, definition2.initializationOptions), settings: merge(spec.settings, definition2.settings) };
|
|
5815
5958
|
if (ruff) spec = deferToRuff(spec);
|
|
5959
|
+
if (definition2.id === "laravel" && !spec.initializationOptions?.phpCommand && (spec.initializationOptions?.phpEnvironment ?? "auto") === "auto")
|
|
5960
|
+
spec.initializationOptions = { ...spec.initializationOptions, phpCommand: await laravelPhpCommand(root, { ...process.env, ...spec.env }, signal) };
|
|
5816
5961
|
if (definition2.id === "json") {
|
|
5817
5962
|
const options2 = this.project ? (await this.project.reload()).schemas : { catalog: true, download: true, associations: [] };
|
|
5818
5963
|
spec.settings = await this.schemas.settings(spec.settings ?? {}, options2);
|
|
@@ -5853,7 +5998,7 @@ class LanguageServerManager {
|
|
|
5853
5998
|
if (!instance.attachments.size && !instance.idle) {
|
|
5854
5999
|
instance.idle = setTimeout(() => {
|
|
5855
6000
|
instance.idle = void 0;
|
|
5856
|
-
void this.stop(false, instance.id);
|
|
6001
|
+
if (this.instances.get(instance.id) === instance) void this.stop(false, instance.id);
|
|
5857
6002
|
}, this.idleMs);
|
|
5858
6003
|
instance.idle.unref();
|
|
5859
6004
|
}
|
|
@@ -7390,7 +7535,7 @@ class SubagentRegistry {
|
|
|
7390
7535
|
let cached;
|
|
7391
7536
|
function runtimeVersion() {
|
|
7392
7537
|
if (cached) return cached;
|
|
7393
|
-
return cached = "0.
|
|
7538
|
+
return cached = "0.10.0";
|
|
7394
7539
|
}
|
|
7395
7540
|
const MAX_REQUEST_BYTES = 1024 * 1024;
|
|
7396
7541
|
const MAX_CONCURRENT_REQUESTS = 16;
|
|
@@ -7979,6 +8124,9 @@ const MAX_IMAGE_DATA = Math.ceil(5 * 1024 * 1024 / 3) * 4;
|
|
|
7979
8124
|
const MAX_QUEUED_IMAGE_DATA = 16 * 1024 * 1024;
|
|
7980
8125
|
const withoutImageData = (key, value) => key === "data" ? void 0 : value;
|
|
7981
8126
|
const EDITOR_UNSUPPORTED = "The connected editor does not support this tool; update Oxbit";
|
|
8127
|
+
function bundledAgent(base = import.meta.url) {
|
|
8128
|
+
return ["./agent/index.js", "../../agent/dist/index.js"].map((relative) => fileURLToPath(new URL(relative, base))).find((file) => existsSync(file));
|
|
8129
|
+
}
|
|
7982
8130
|
function strings(value) {
|
|
7983
8131
|
if (!Array.isArray(value) || value.length > 128 || value.some(
|
|
7984
8132
|
(v) => typeof v !== "string" || v.length > 16384 || v.includes("\0")
|
|
@@ -7991,16 +8139,19 @@ function strings(value) {
|
|
|
7991
8139
|
}
|
|
7992
8140
|
class AgentACP {
|
|
7993
8141
|
constructor(files, emit, stateChanged = () => {
|
|
7994
|
-
}, acpRegistry) {
|
|
8142
|
+
}, acpRegistry, statusChanged = () => {
|
|
8143
|
+
}) {
|
|
7995
8144
|
this.files = files;
|
|
7996
8145
|
this.emit = emit;
|
|
7997
8146
|
this.stateChanged = stateChanged;
|
|
7998
8147
|
this.acpRegistry = acpRegistry;
|
|
8148
|
+
this.statusChanged = statusChanged;
|
|
7999
8149
|
}
|
|
8000
8150
|
files;
|
|
8001
8151
|
emit;
|
|
8002
8152
|
stateChanged;
|
|
8003
8153
|
acpRegistry;
|
|
8154
|
+
statusChanged;
|
|
8004
8155
|
agents = /* @__PURE__ */ new Map();
|
|
8005
8156
|
mcp = new AgentMCP((id, name, args) => this.tool(id, name, args));
|
|
8006
8157
|
get(owner, id) {
|
|
@@ -8050,6 +8201,20 @@ class AgentACP {
|
|
|
8050
8201
|
if (agent.client) this.emit(agent.client, event, payload);
|
|
8051
8202
|
this.stateChanged();
|
|
8052
8203
|
}
|
|
8204
|
+
report(agent, status2) {
|
|
8205
|
+
try {
|
|
8206
|
+
this.statusChanged({
|
|
8207
|
+
owner: agent.owner,
|
|
8208
|
+
agent: agent.connection.name ?? agent.connection.provider,
|
|
8209
|
+
status: status2,
|
|
8210
|
+
pending: agent.approvals.size,
|
|
8211
|
+
startedAt: agent.startedAt
|
|
8212
|
+
});
|
|
8213
|
+
} catch (error) {
|
|
8214
|
+
process.stderr.write(`Oxbit agent status listener failed: ${String(error)}
|
|
8215
|
+
`);
|
|
8216
|
+
}
|
|
8217
|
+
}
|
|
8053
8218
|
list(owner) {
|
|
8054
8219
|
return { sessions: [...this.agents.values()].filter((a) => a.owner === owner && !a.stopped).map((a) => ({
|
|
8055
8220
|
connection: a.connection,
|
|
@@ -8255,12 +8420,11 @@ class AgentACP {
|
|
|
8255
8420
|
if (!command.trim() || command.includes("\0"))
|
|
8256
8421
|
throw new RpcError("INVALID_PARAMS", "Invalid agent executable");
|
|
8257
8422
|
const custom = typeof launch.name === "string" ? launch.name.trim().slice(0, 80) : "";
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
};
|
|
8423
|
+
const name = preset2?.name ?? (custom || "Custom agent");
|
|
8424
|
+
const args = strings(launch.args ?? (preset2 ? [...preset2.args] : []));
|
|
8425
|
+
const bundled = provider === OXBIT_CLI_PROVIDER && command === preset2?.command ? bundledAgent() : void 0;
|
|
8426
|
+
if (bundled) return { provider, name, command: process.execPath, args: [bundled, ...args] };
|
|
8427
|
+
return { provider, name, command, args };
|
|
8264
8428
|
}
|
|
8265
8429
|
async call(owner, id, method, params = {}, signal) {
|
|
8266
8430
|
const agent = this.get(owner, id);
|
|
@@ -8305,11 +8469,16 @@ class AgentACP {
|
|
|
8305
8469
|
agent.busy = false;
|
|
8306
8470
|
}
|
|
8307
8471
|
}
|
|
8308
|
-
if (["session/new", "session/load", "session/resume"].includes(method)) {
|
|
8472
|
+
if (["session/new", "session/load", "session/resume", "session/fork"].includes(method)) {
|
|
8309
8473
|
if (method === "session/load" && !agent.connection.capabilities?.loadSession)
|
|
8310
8474
|
throw new Error("This agent does not support loading conversations");
|
|
8311
8475
|
if (method === "session/resume" && !agent.connection.capabilities?.sessionCapabilities?.resume)
|
|
8312
8476
|
throw new Error("This agent does not support resuming conversations");
|
|
8477
|
+
if (method === "session/fork" && !agent.connection.capabilities?.sessionCapabilities?.fork)
|
|
8478
|
+
throw new Error("This agent does not support forking conversations");
|
|
8479
|
+
const source2 = agent.connection.sessionId;
|
|
8480
|
+
if (method === "session/fork" && !source2)
|
|
8481
|
+
throw new Error("Start a conversation first");
|
|
8313
8482
|
if (agent.subagents?.activeCount)
|
|
8314
8483
|
throw new Error(
|
|
8315
8484
|
"Wait for active subagents or disconnect before changing conversations"
|
|
@@ -8321,7 +8490,7 @@ class AgentACP {
|
|
|
8321
8490
|
const previousBytes = agent.eventBytes;
|
|
8322
8491
|
const previousTitle = agent.title;
|
|
8323
8492
|
const previousTruncated = agent.truncated;
|
|
8324
|
-
const target = method === "session/new" ? void 0 : requireString(params, "sessionId");
|
|
8493
|
+
const target = method === "session/new" || method === "session/fork" ? void 0 : requireString(params, "sessionId");
|
|
8325
8494
|
if (agent.approvals.size)
|
|
8326
8495
|
throw new Error(
|
|
8327
8496
|
"Resolve pending requests before changing conversations"
|
|
@@ -8342,7 +8511,7 @@ class AgentACP {
|
|
|
8342
8511
|
const result = await this.request(agent, method, {
|
|
8343
8512
|
cwd: this.files.root,
|
|
8344
8513
|
mcpServers: [await this.mcp.server(agent.connection.id, !!agent.connection.capabilities?.mcpCapabilities?.http)],
|
|
8345
|
-
...target ? { sessionId: target } : {}
|
|
8514
|
+
...target ? { sessionId: target } : method === "session/fork" ? { sessionId: source2 } : {}
|
|
8346
8515
|
});
|
|
8347
8516
|
const sessionId2 = target ?? result?.sessionId;
|
|
8348
8517
|
if (typeof sessionId2 !== "string" || !sessionId2)
|
|
@@ -8418,12 +8587,14 @@ class AgentACP {
|
|
|
8418
8587
|
const messageId = params.messageId === void 0 ? randomUUID() : requireString(params, "messageId", 256);
|
|
8419
8588
|
agent.busy = true;
|
|
8420
8589
|
agent.turn++;
|
|
8590
|
+
agent.startedAt = Date.now();
|
|
8421
8591
|
if (agent.title === "New conversation") agent.title = text2.slice(0, 100);
|
|
8422
8592
|
this.publish(agent, "acp.turnStarted", {
|
|
8423
8593
|
messageId,
|
|
8424
8594
|
text: text2,
|
|
8425
8595
|
context: JSON.parse(JSON.stringify(params.context ?? [], withoutImageData))
|
|
8426
8596
|
});
|
|
8597
|
+
this.report(agent, "working");
|
|
8427
8598
|
const abort = () => this.stopAgent(agent, "Agent request interrupted");
|
|
8428
8599
|
signal?.addEventListener("abort", abort, { once: true });
|
|
8429
8600
|
let stopReason;
|
|
@@ -8448,6 +8619,8 @@ class AgentACP {
|
|
|
8448
8619
|
signal?.removeEventListener("abort", abort);
|
|
8449
8620
|
if (!agent.stopped) {
|
|
8450
8621
|
this.publish(agent, "acp.turnEnded", { stopReason, error: failure2 });
|
|
8622
|
+
if (failure2 !== void 0) this.report(agent, "failed");
|
|
8623
|
+
else if (stopReason !== "cancelled") this.report(agent, "finished");
|
|
8451
8624
|
this.publishQueue(agent);
|
|
8452
8625
|
queueMicrotask(() => this.runQueue(agent));
|
|
8453
8626
|
}
|
|
@@ -8530,6 +8703,14 @@ ${content}`
|
|
|
8530
8703
|
this.publishQueue(agent);
|
|
8531
8704
|
return { prompt };
|
|
8532
8705
|
}
|
|
8706
|
+
moveQueued(owner, id, promptId, index) {
|
|
8707
|
+
const agent = this.get(owner, id);
|
|
8708
|
+
const from = agent.queue.findIndex((p) => p.id === promptId);
|
|
8709
|
+
if (from < 0) throw new Error("The queued message has already started or was removed");
|
|
8710
|
+
const [prompt] = agent.queue.splice(from, 1);
|
|
8711
|
+
agent.queue.splice(Math.max(0, Math.min(index, agent.queue.length)), 0, prompt);
|
|
8712
|
+
return this.publishQueue(agent);
|
|
8713
|
+
}
|
|
8533
8714
|
resumeQueue(owner, id) {
|
|
8534
8715
|
const agent = this.get(owner, id);
|
|
8535
8716
|
agent.queuePaused = false;
|
|
@@ -8691,6 +8872,7 @@ ${content}`
|
|
|
8691
8872
|
if (method !== "fs/read_text_file" && !method.startsWith("oxbit/"))
|
|
8692
8873
|
registry.waiting(sessionId, requestId, true, params.toolCallId ?? params.toolCall?.toolCallId);
|
|
8693
8874
|
this.publish(agent, "acp.request", this.requestEvent(agent, requestId, request));
|
|
8875
|
+
if (method === "session/request_permission") this.report(agent, "waiting");
|
|
8694
8876
|
});
|
|
8695
8877
|
}
|
|
8696
8878
|
async tool(id, name, args) {
|
|
@@ -12209,6 +12391,215 @@ function loginShellEnvironment(cwd, inherited = process.env, platform = process.
|
|
|
12209
12391
|
child.on("close", (code) => finish(code === 0 ? parseShellEnvironment(Buffer.concat(chunks).toString(), mark) : void 0));
|
|
12210
12392
|
});
|
|
12211
12393
|
}
|
|
12394
|
+
const PUSH_DEVICES_FILE = "push-devices.json";
|
|
12395
|
+
const MAX_DEVICES = 16;
|
|
12396
|
+
const RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
12397
|
+
const WINDOW_SECONDS = 15 * 60;
|
|
12398
|
+
const RELAY_TIMEOUT_MS = 1e4;
|
|
12399
|
+
const HANDLE = /^[A-Za-z0-9_-]{1,2048}$/;
|
|
12400
|
+
const STATUSES = ["working", "waiting", "finished", "failed"];
|
|
12401
|
+
const TITLES = { waiting: "Agent needs your input", finished: "Agent finished", failed: "Agent turn failed" };
|
|
12402
|
+
const log = (message2) => process.stderr.write(`Oxbit push: ${message2}
|
|
12403
|
+
`);
|
|
12404
|
+
function deviceIdOf(params) {
|
|
12405
|
+
const value = requireString(params, "deviceId", 128);
|
|
12406
|
+
if (!value) throw new RpcError("INVALID_PARAMS", "Invalid deviceId");
|
|
12407
|
+
return value;
|
|
12408
|
+
}
|
|
12409
|
+
function handleOf(params, key) {
|
|
12410
|
+
const value = params[key];
|
|
12411
|
+
if (value === void 0 || value === null) return void 0;
|
|
12412
|
+
if (typeof value !== "string" || !HANDLE.test(value)) throw new RpcError("INVALID_PARAMS", `Invalid ${key}`);
|
|
12413
|
+
return value;
|
|
12414
|
+
}
|
|
12415
|
+
const text$1 = (value) => typeof value === "string" && value.length <= 1024;
|
|
12416
|
+
function activityOf(value) {
|
|
12417
|
+
if (value === null) return null;
|
|
12418
|
+
const v = value ?? {};
|
|
12419
|
+
const startedAt = v.startedAt;
|
|
12420
|
+
if (typeof value !== "object" || !text$1(v.agent) || !text$1(v.title) || !text$1(v.detail) || !STATUSES.includes(v.status) || !Number.isSafeInteger(v.pending) || v.pending < 0 || startedAt !== void 0 && (typeof startedAt !== "number" || !Number.isFinite(startedAt) || startedAt < 0))
|
|
12421
|
+
throw new RpcError("INVALID_PARAMS", "Invalid activity");
|
|
12422
|
+
return {
|
|
12423
|
+
agent: v.agent,
|
|
12424
|
+
title: v.title,
|
|
12425
|
+
status: v.status,
|
|
12426
|
+
detail: v.detail,
|
|
12427
|
+
pending: v.pending,
|
|
12428
|
+
...startedAt === void 0 ? {} : { startedAt }
|
|
12429
|
+
};
|
|
12430
|
+
}
|
|
12431
|
+
function restore(entry2) {
|
|
12432
|
+
try {
|
|
12433
|
+
const activity = entry2.activity === void 0 ? null : activityOf(entry2.activity);
|
|
12434
|
+
const device = {
|
|
12435
|
+
deviceId: deviceIdOf(entry2),
|
|
12436
|
+
session: requireString(entry2, "session", 128),
|
|
12437
|
+
alert: handleOf(entry2, "alert"),
|
|
12438
|
+
liveActivity: handleOf(entry2, "liveActivity"),
|
|
12439
|
+
active: false,
|
|
12440
|
+
...activity ? { activity } : {},
|
|
12441
|
+
updatedAt: entry2.updatedAt
|
|
12442
|
+
};
|
|
12443
|
+
return Number.isFinite(device.updatedAt) ? device : void 0;
|
|
12444
|
+
} catch {
|
|
12445
|
+
return void 0;
|
|
12446
|
+
}
|
|
12447
|
+
}
|
|
12448
|
+
function detail(status2, pending) {
|
|
12449
|
+
if (status2 === "working") return "Working";
|
|
12450
|
+
if (status2 === "waiting") return pending === 1 ? "1 request needs an answer" : `${pending} requests need an answer`;
|
|
12451
|
+
return TITLES[status2];
|
|
12452
|
+
}
|
|
12453
|
+
function activityState(snapshot, event) {
|
|
12454
|
+
return {
|
|
12455
|
+
status: event.status,
|
|
12456
|
+
title: snapshot.title,
|
|
12457
|
+
detail: detail(event.status, event.pending),
|
|
12458
|
+
pending: event.pending,
|
|
12459
|
+
...event.status === "working" && event.startedAt !== void 0 ? { startedAt: Math.floor(event.startedAt / 1e3) } : {}
|
|
12460
|
+
};
|
|
12461
|
+
}
|
|
12462
|
+
class PushDevices {
|
|
12463
|
+
constructor(file) {
|
|
12464
|
+
this.file = file;
|
|
12465
|
+
}
|
|
12466
|
+
file;
|
|
12467
|
+
devices = /* @__PURE__ */ new Map();
|
|
12468
|
+
/** Last Live Activity state sent per device. */
|
|
12469
|
+
sent = /* @__PURE__ */ new Map();
|
|
12470
|
+
persistence = Promise.resolve();
|
|
12471
|
+
static async open(dataDir) {
|
|
12472
|
+
const store = new PushDevices(path.join(dataDir, PUSH_DEVICES_FILE));
|
|
12473
|
+
try {
|
|
12474
|
+
const state2 = JSON.parse(await fs.readFile(store.file, "utf8"));
|
|
12475
|
+
if (state2?.version === 1 && Array.isArray(state2.devices))
|
|
12476
|
+
for (const entry2 of state2.devices) {
|
|
12477
|
+
const device = entry2 && typeof entry2 === "object" ? restore(entry2) : void 0;
|
|
12478
|
+
if (device) store.devices.set(device.deviceId, device);
|
|
12479
|
+
}
|
|
12480
|
+
} catch (error) {
|
|
12481
|
+
if (error.code !== "ENOENT") log(`ignoring unreadable ${PUSH_DEVICES_FILE}: ${String(error)}`);
|
|
12482
|
+
}
|
|
12483
|
+
store.prune();
|
|
12484
|
+
return store;
|
|
12485
|
+
}
|
|
12486
|
+
async register(session, connection, params) {
|
|
12487
|
+
const deviceId = deviceIdOf(params), alert = handleOf(params, "alert"), liveActivity = handleOf(params, "liveActivity");
|
|
12488
|
+
const previous = this.devices.get(deviceId);
|
|
12489
|
+
this.sent.delete(deviceId);
|
|
12490
|
+
this.devices.set(deviceId, {
|
|
12491
|
+
...previous,
|
|
12492
|
+
deviceId,
|
|
12493
|
+
session,
|
|
12494
|
+
alert,
|
|
12495
|
+
liveActivity,
|
|
12496
|
+
active: true,
|
|
12497
|
+
connection,
|
|
12498
|
+
updatedAt: Date.now()
|
|
12499
|
+
});
|
|
12500
|
+
await this.persist();
|
|
12501
|
+
return {};
|
|
12502
|
+
}
|
|
12503
|
+
async state(session, connection, params) {
|
|
12504
|
+
const deviceId = deviceIdOf(params);
|
|
12505
|
+
if (typeof params.active !== "boolean") throw new RpcError("INVALID_PARAMS", "active must be boolean");
|
|
12506
|
+
const activity = params.activity === void 0 ? void 0 : activityOf(params.activity);
|
|
12507
|
+
const device = this.devices.get(deviceId);
|
|
12508
|
+
if (!device || device.session !== session) throw new RpcError("NOT_FOUND", "Register the device first");
|
|
12509
|
+
device.active = params.active;
|
|
12510
|
+
if (params.active) device.connection = connection;
|
|
12511
|
+
if (activity) device.activity = activity;
|
|
12512
|
+
else if (activity === null) delete device.activity;
|
|
12513
|
+
device.updatedAt = Date.now();
|
|
12514
|
+
this.sent.delete(deviceId);
|
|
12515
|
+
await this.persist();
|
|
12516
|
+
return {};
|
|
12517
|
+
}
|
|
12518
|
+
async unregister(session, params) {
|
|
12519
|
+
const deviceId = deviceIdOf(params);
|
|
12520
|
+
if (this.devices.get(deviceId)?.session === session) {
|
|
12521
|
+
this.devices.delete(deviceId);
|
|
12522
|
+
this.sent.delete(deviceId);
|
|
12523
|
+
await this.persist();
|
|
12524
|
+
}
|
|
12525
|
+
return {};
|
|
12526
|
+
}
|
|
12527
|
+
/** Marks devices inactive when the connection that set them active closes. */
|
|
12528
|
+
disconnect(connection) {
|
|
12529
|
+
let changed = false;
|
|
12530
|
+
for (const device of this.devices.values())
|
|
12531
|
+
if (device.active && device.connection === connection) {
|
|
12532
|
+
device.active = false;
|
|
12533
|
+
changed = true;
|
|
12534
|
+
}
|
|
12535
|
+
if (changed) this.persist().catch((error) => log(`cannot save devices: ${String(error)}`));
|
|
12536
|
+
}
|
|
12537
|
+
/** Sends alert and Live Activity pushes to the owner's inactive devices; resolves after every send settles. */
|
|
12538
|
+
async notify(event) {
|
|
12539
|
+
const sends = [];
|
|
12540
|
+
for (const device of this.devices.values()) {
|
|
12541
|
+
if (device.active || device.session !== event.owner) continue;
|
|
12542
|
+
if (event.status !== "working" && device.alert)
|
|
12543
|
+
sends.push(this.send(device.deviceId, "alert", {
|
|
12544
|
+
handle: device.alert,
|
|
12545
|
+
alert: { title: TITLES[event.status], body: device.activity?.title || event.agent }
|
|
12546
|
+
}));
|
|
12547
|
+
if (!device.liveActivity || !device.activity) continue;
|
|
12548
|
+
const state2 = activityState(device.activity, event), end = event.status === "finished" || event.status === "failed";
|
|
12549
|
+
const key = JSON.stringify([end, state2]);
|
|
12550
|
+
if (this.sent.get(device.deviceId) === key) continue;
|
|
12551
|
+
this.sent.set(device.deviceId, key);
|
|
12552
|
+
const window = Math.floor(Date.now() / 1e3) + WINDOW_SECONDS;
|
|
12553
|
+
sends.push(this.send(device.deviceId, "liveActivity", {
|
|
12554
|
+
handle: device.liveActivity,
|
|
12555
|
+
activity: { event: end ? "end" : "update", state: state2, ...end ? { dismissalDate: window } : { staleDate: window } }
|
|
12556
|
+
}));
|
|
12557
|
+
}
|
|
12558
|
+
await Promise.all(sends);
|
|
12559
|
+
}
|
|
12560
|
+
flush() {
|
|
12561
|
+
return this.persistence.catch(() => {
|
|
12562
|
+
});
|
|
12563
|
+
}
|
|
12564
|
+
async send(deviceId, kind, request) {
|
|
12565
|
+
const relay = (process.env.OXBIT_PUSH_RELAY ?? PUSH_RELAY_URL).replace(/\/+$/, "");
|
|
12566
|
+
try {
|
|
12567
|
+
const response = await fetch(`${relay}/v1/push`, {
|
|
12568
|
+
method: "POST",
|
|
12569
|
+
headers: { "Content-Type": "application/json" },
|
|
12570
|
+
body: JSON.stringify(request),
|
|
12571
|
+
signal: AbortSignal.timeout(RELAY_TIMEOUT_MS)
|
|
12572
|
+
});
|
|
12573
|
+
const result = await response.json().catch(() => ({}));
|
|
12574
|
+
const device = this.devices.get(deviceId);
|
|
12575
|
+
if (result.gone && device?.[kind] === request.handle) {
|
|
12576
|
+
delete device[kind];
|
|
12577
|
+
if (kind === "liveActivity") this.sent.delete(deviceId);
|
|
12578
|
+
await this.persist();
|
|
12579
|
+
} else if (!response.ok || !result.sent)
|
|
12580
|
+
log(`relay did not send to ${deviceId}: ${result.reason ?? `HTTP ${response.status}`}`);
|
|
12581
|
+
} catch (error) {
|
|
12582
|
+
log(`push to ${deviceId} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
12583
|
+
}
|
|
12584
|
+
}
|
|
12585
|
+
prune(now = Date.now()) {
|
|
12586
|
+
for (const [id, device] of this.devices)
|
|
12587
|
+
if (now - device.updatedAt > RETENTION_MS) this.devices.delete(id);
|
|
12588
|
+
const oldest = [...this.devices.values()].sort((a, b) => a.updatedAt - b.updatedAt);
|
|
12589
|
+
for (const device of oldest.slice(0, Math.max(0, oldest.length - MAX_DEVICES))) this.devices.delete(device.deviceId);
|
|
12590
|
+
for (const id of this.sent.keys()) if (!this.devices.has(id)) this.sent.delete(id);
|
|
12591
|
+
}
|
|
12592
|
+
persist() {
|
|
12593
|
+
this.prune();
|
|
12594
|
+
const payload = JSON.stringify({ version: 1, devices: [...this.devices.values()] });
|
|
12595
|
+
this.persistence = this.persistence.catch(() => {
|
|
12596
|
+
}).then(async () => {
|
|
12597
|
+
await fs.writeFile(this.file + ".tmp", payload, { mode: 384 });
|
|
12598
|
+
await fs.rename(this.file + ".tmp", this.file);
|
|
12599
|
+
});
|
|
12600
|
+
return this.persistence;
|
|
12601
|
+
}
|
|
12602
|
+
}
|
|
12212
12603
|
const MAX_SOCKET_BACKLOG_BYTES = MAX_FILE_WRITE_MESSAGE_BYTES;
|
|
12213
12604
|
const allCapabilities = [
|
|
12214
12605
|
"filesystem.read",
|
|
@@ -12351,10 +12742,11 @@ async function createRuntime(options2) {
|
|
|
12351
12742
|
return session;
|
|
12352
12743
|
};
|
|
12353
12744
|
const acpRegistry = new ACPRegistry(dataDir, options2.acpRegistryUrl);
|
|
12745
|
+
const pushDevices = await PushDevices.open(dataDir);
|
|
12354
12746
|
const agents = new AgentACP(files, (connectionId, name, params) => {
|
|
12355
12747
|
const connection = connections.get(connectionId);
|
|
12356
12748
|
if (connection?.session && !connection.session.revoked && trusted) event(connection, name, params);
|
|
12357
|
-
}, () => updateIdle(), acpRegistry);
|
|
12749
|
+
}, () => updateIdle(), acpRegistry, (status2) => void pushDevices.notify(status2));
|
|
12358
12750
|
const processEvent = ({ event: name, params, stream, seq }, ownerId) => {
|
|
12359
12751
|
const cap = name.startsWith("terminal.") ? "terminal" : "tasks";
|
|
12360
12752
|
for (const c of connections.values()) {
|
|
@@ -12701,7 +13093,7 @@ async function createRuntime(options2) {
|
|
|
12701
13093
|
if (method.startsWith("terminal.")) return { cap: "terminal", trust: true };
|
|
12702
13094
|
if (method.startsWith("tasks.")) return { cap: "tasks", trust: !["tasks.catalog", "tasks.list", "tasks.attach", "tasks.worktrees"].includes(method) };
|
|
12703
13095
|
if (method.startsWith("git.")) return { cap: "git", trust: true };
|
|
12704
|
-
if (method.startsWith("acp.")) return { cap: "extensions", trust: true };
|
|
13096
|
+
if (method.startsWith("acp.") || method.startsWith("push.")) return { cap: "extensions", trust: true };
|
|
12705
13097
|
if (method.startsWith("lsp.")) return { cap: "lsp", trust: true };
|
|
12706
13098
|
if (method.startsWith("collab.")) return { cap: "collaboration" };
|
|
12707
13099
|
if (method.startsWith("extensions."))
|
|
@@ -12734,6 +13126,7 @@ async function createRuntime(options2) {
|
|
|
12734
13126
|
if (!["acp.start", "acp.list", "acp.attach", "acp.detach", "acp.stop", "acp.disconnect", "acp.registry"].includes(method) && !method.startsWith("acp.checkpoint."))
|
|
12735
13127
|
agents.control(session.id, requireString(params, "id"), connection.id);
|
|
12736
13128
|
}
|
|
13129
|
+
if (method.startsWith("push.")) owner(connection);
|
|
12737
13130
|
if (method.startsWith("project.")) owner(connection);
|
|
12738
13131
|
if (method.startsWith("settings.")) owner(connection);
|
|
12739
13132
|
switch (method) {
|
|
@@ -12768,6 +13161,9 @@ async function createRuntime(options2) {
|
|
|
12768
13161
|
return agents.enqueue(session.id, requireString(params, "id"), params, method === "acp.interrupt");
|
|
12769
13162
|
case "acp.dequeue":
|
|
12770
13163
|
return agents.dequeue(session.id, requireString(params, "id"), requireString(params, "promptId"));
|
|
13164
|
+
case "acp.moveQueued":
|
|
13165
|
+
if (!Number.isInteger(params.index)) throw new RpcError("INVALID_PARAMS", "index must be an integer");
|
|
13166
|
+
return agents.moveQueued(session.id, requireString(params, "id"), requireString(params, "promptId"), params.index);
|
|
12771
13167
|
case "acp.resumeQueue":
|
|
12772
13168
|
return agents.resumeQueue(session.id, requireString(params, "id"));
|
|
12773
13169
|
case "acp.call":
|
|
@@ -12784,6 +13180,12 @@ async function createRuntime(options2) {
|
|
|
12784
13180
|
case "acp.disconnect":
|
|
12785
13181
|
agents.disconnect(session.id, connection.id);
|
|
12786
13182
|
return {};
|
|
13183
|
+
case "push.register":
|
|
13184
|
+
return pushDevices.register(session.id, connection.id, params);
|
|
13185
|
+
case "push.state":
|
|
13186
|
+
return pushDevices.state(session.id, connection.id, params);
|
|
13187
|
+
case "push.unregister":
|
|
13188
|
+
return pushDevices.unregister(session.id, params);
|
|
12787
13189
|
case "acp.checkpoint.create":
|
|
12788
13190
|
return checkpoints.create(signal);
|
|
12789
13191
|
case "acp.checkpoint.diff":
|
|
@@ -12965,6 +13367,8 @@ async function createRuntime(options2) {
|
|
|
12965
13367
|
return git.show(params.ref, signal);
|
|
12966
13368
|
case "git.commitDiff":
|
|
12967
13369
|
return git.commitDiff(params, signal);
|
|
13370
|
+
case "git.branchDiff":
|
|
13371
|
+
return git.branchDiff(params, signal);
|
|
12968
13372
|
case "git.stashes":
|
|
12969
13373
|
return git.stashes(signal);
|
|
12970
13374
|
case "git.stashDiff":
|
|
@@ -13129,6 +13533,25 @@ async function createRuntime(options2) {
|
|
|
13129
13533
|
params.encoding,
|
|
13130
13534
|
params.eol
|
|
13131
13535
|
);
|
|
13536
|
+
case "search.files": {
|
|
13537
|
+
const term = requireString(params, "query", 1024).trim().toLowerCase();
|
|
13538
|
+
if (!term) return [];
|
|
13539
|
+
const result = await runCommand(options2.desktop?.rgPath ?? "rg", ["--files", "--hidden", "--glob", "!.git", "--glob", "!node_modules", "--glob", "!.oxbit-tmp-*"], {
|
|
13540
|
+
cwd: root,
|
|
13541
|
+
signal,
|
|
13542
|
+
maxBytes: 64 * MAX_BUFFER_BYTES
|
|
13543
|
+
});
|
|
13544
|
+
if (result.exitCode > 1) throw new RpcError("SEARCH_FAILED", result.stderr.trim());
|
|
13545
|
+
const matches = (path2) => {
|
|
13546
|
+
let at = 0;
|
|
13547
|
+
for (const char of term) {
|
|
13548
|
+
at = path2.indexOf(char, at) + 1;
|
|
13549
|
+
if (!at) return false;
|
|
13550
|
+
}
|
|
13551
|
+
return true;
|
|
13552
|
+
};
|
|
13553
|
+
return result.stdout.split("\n").filter((path2) => path2 && matches(path2.toLowerCase())).sort().slice(0, 1e3);
|
|
13554
|
+
}
|
|
13132
13555
|
case "search.query": {
|
|
13133
13556
|
const query = requireString(params, "query", 8192);
|
|
13134
13557
|
if (!query) return [];
|
|
@@ -13394,6 +13817,7 @@ async function createRuntime(options2) {
|
|
|
13394
13817
|
clearTimeout(authDeadline);
|
|
13395
13818
|
agents.detach(connection.id);
|
|
13396
13819
|
lsp.detach(connection.id);
|
|
13820
|
+
pushDevices.disconnect(connection.id);
|
|
13397
13821
|
connections.delete(connection.id);
|
|
13398
13822
|
updateIdle();
|
|
13399
13823
|
for (const pending of connection.edits.values()) {
|
|
@@ -13544,6 +13968,7 @@ async function createRuntime(options2) {
|
|
|
13544
13968
|
await Promise.allSettled([...inflight.values()]);
|
|
13545
13969
|
await collaboration.close();
|
|
13546
13970
|
await persistence;
|
|
13971
|
+
await pushDevices.flush();
|
|
13547
13972
|
await new Promise((resolve) => websocket.close(() => resolve()));
|
|
13548
13973
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
13549
13974
|
}
|
|
@@ -13741,7 +14166,7 @@ function lanAddresses() {
|
|
|
13741
14166
|
return { v4: of("IPv4"), v6: of("IPv6") };
|
|
13742
14167
|
}
|
|
13743
14168
|
const stderrLog = (line) => process.stderr.write(line + "\n");
|
|
13744
|
-
function advertise(ad,
|
|
14169
|
+
function advertise(ad, log2 = stderrLog) {
|
|
13745
14170
|
const instance = instanceLabel(ad.name, ad.id);
|
|
13746
14171
|
const current = (ttl) => records({ ...ad, ...(ad.addresses ?? lanAddresses)() }, ttl);
|
|
13747
14172
|
const timers = [];
|
|
@@ -13760,11 +14185,11 @@ function advertise(ad, log = stderrLog) {
|
|
|
13760
14185
|
};
|
|
13761
14186
|
const fail = (error) => {
|
|
13762
14187
|
if (closed) return;
|
|
13763
|
-
|
|
14188
|
+
log2(`mDNS advertising disabled: ${error.message}`);
|
|
13764
14189
|
stop2();
|
|
13765
14190
|
};
|
|
13766
14191
|
const sendFailure = (error) => {
|
|
13767
|
-
if (!sendFailed)
|
|
14192
|
+
if (!sendFailed) log2(`mDNS send failed: ${error.message}`);
|
|
13768
14193
|
sendFailed = true;
|
|
13769
14194
|
};
|
|
13770
14195
|
const send = (packet, port2 = PORT, address = GROUP, done) => {
|
|
@@ -14083,7 +14508,7 @@ Runtime id: ${daemon.id}
|
|
|
14083
14508
|
}
|
|
14084
14509
|
async function detach(invocation, target, dataDir, entry2) {
|
|
14085
14510
|
await fs.mkdir(dataDir, { recursive: true, mode: 448 });
|
|
14086
|
-
const
|
|
14511
|
+
const log2 = await fs.open(logFile(dataDir), "a", 384);
|
|
14087
14512
|
const args = [entry2, "--foreground", "--no-open", ...invocation.lan ? ["--lan"] : ["--host", invocation.host]];
|
|
14088
14513
|
if (invocation.port) args.push("--port", String(invocation.port));
|
|
14089
14514
|
args.push("--keep-alive", invocation.keepAlive ? String(invocation.keepAlive) : "forever");
|
|
@@ -14095,7 +14520,7 @@ async function detach(invocation, target, dataDir, entry2) {
|
|
|
14095
14520
|
delete env2.OXBIT_KEEP_ALIVE;
|
|
14096
14521
|
const child = spawn(process.execPath, args, {
|
|
14097
14522
|
detached: true,
|
|
14098
|
-
stdio: ["ignore",
|
|
14523
|
+
stdio: ["ignore", log2.fd, log2.fd],
|
|
14099
14524
|
env: env2
|
|
14100
14525
|
});
|
|
14101
14526
|
let exit;
|
|
@@ -14103,7 +14528,7 @@ async function detach(invocation, target, dataDir, entry2) {
|
|
|
14103
14528
|
exit = code ?? 1;
|
|
14104
14529
|
});
|
|
14105
14530
|
child.unref();
|
|
14106
|
-
await
|
|
14531
|
+
await log2.close();
|
|
14107
14532
|
const deadline = Date.now() + READY_TIMEOUT;
|
|
14108
14533
|
while (Date.now() < deadline) {
|
|
14109
14534
|
const daemon = await liveDaemon(dataDir);
|