innocode 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +27 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/innocode +84 -0
- package/bin/opencode +84 -0
- package/bunfig.toml +5 -0
- package/package.json +126 -0
- package/parsers-config.ts +253 -0
- package/script/build.ts +198 -0
- package/script/postinstall.mjs +125 -0
- package/script/publish.ts +186 -0
- package/script/schema.ts +47 -0
- package/script/seed-e2e.ts +50 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1676 -0
- package/src/acp/session.ts +117 -0
- package/src/acp/types.ts +23 -0
- package/src/agent/agent.ts +338 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +14 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +11 -0
- package/src/agent/prompt/title.txt +44 -0
- package/src/auth/index.ts +70 -0
- package/src/bun/index.ts +137 -0
- package/src/bun/registry.ts +48 -0
- package/src/bus/bus-event.ts +43 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +105 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/acp.ts +70 -0
- package/src/cli/cmd/agent.ts +257 -0
- package/src/cli/cmd/auth.ts +400 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/debug/agent.ts +167 -0
- package/src/cli/cmd/debug/config.ts +16 -0
- package/src/cli/cmd/debug/file.ts +97 -0
- package/src/cli/cmd/debug/index.ts +48 -0
- package/src/cli/cmd/debug/lsp.ts +52 -0
- package/src/cli/cmd/debug/ripgrep.ts +87 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +16 -0
- package/src/cli/cmd/debug/snapshot.ts +52 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1540 -0
- package/src/cli/cmd/import.ts +147 -0
- package/src/cli/cmd/mcp.ts +765 -0
- package/src/cli/cmd/models.ts +77 -0
- package/src/cli/cmd/pr.ts +113 -0
- package/src/cli/cmd/run.ts +598 -0
- package/src/cli/cmd/serve.ts +20 -0
- package/src/cli/cmd/session.ts +135 -0
- package/src/cli/cmd/stats.ts +426 -0
- package/src/cli/cmd/tui/app.tsx +812 -0
- package/src/cli/cmd/tui/attach.ts +60 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +148 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +165 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +243 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +167 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/logo.tsx +85 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +666 -0
- package/src/cli/cmd/tui/component/prompt/frecency.tsx +89 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1153 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/spinner.tsx +24 -0
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
- package/src/cli/cmd/tui/component/tips.tsx +153 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/context/args.tsx +15 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +54 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +100 -0
- package/src/cli/cmd/tui/context/kv.tsx +52 -0
- package/src/cli/cmd/tui/context/local.tsx +409 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +46 -0
- package/src/cli/cmd/tui/context/sdk.tsx +101 -0
- package/src/cli/cmd/tui/context/sync.tsx +470 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
- package/src/cli/cmd/tui/context/theme/innocode.json +245 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/orng.json +249 -0
- package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1154 -0
- package/src/cli/cmd/tui/event.ts +48 -0
- package/src/cli/cmd/tui/routes/home.tsx +145 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +135 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +2139 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +508 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +466 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
- package/src/cli/cmd/tui/thread.ts +188 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +59 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +85 -0
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +207 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +80 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +401 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +167 -0
- package/src/cli/cmd/tui/ui/link.tsx +28 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +100 -0
- package/src/cli/cmd/tui/util/clipboard.ts +159 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/signal.ts +7 -0
- package/src/cli/cmd/tui/util/terminal.ts +114 -0
- package/src/cli/cmd/tui/util/transcript.ts +98 -0
- package/src/cli/cmd/tui/win32.ts +129 -0
- package/src/cli/cmd/tui/worker.ts +152 -0
- package/src/cli/cmd/uninstall.ts +363 -0
- package/src/cli/cmd/upgrade.ts +73 -0
- package/src/cli/cmd/web.ts +81 -0
- package/src/cli/error.ts +57 -0
- package/src/cli/logo.ts +6 -0
- package/src/cli/network.ts +60 -0
- package/src/cli/ui.ts +113 -0
- package/src/cli/upgrade.ts +25 -0
- package/src/command/index.ts +150 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +101 -0
- package/src/config/config.ts +1517 -0
- package/src/config/markdown.ts +98 -0
- package/src/env/index.ts +28 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +583 -0
- package/src/file/ripgrep.ts +375 -0
- package/src/file/time.ts +69 -0
- package/src/file/watcher.ts +127 -0
- package/src/flag/flag.ts +148 -0
- package/src/format/formatter.ts +366 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +80 -0
- package/src/id/id.ts +83 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +160 -0
- package/src/installation/index.ts +268 -0
- package/src/lsp/client.ts +252 -0
- package/src/lsp/index.ts +485 -0
- package/src/lsp/language.ts +119 -0
- package/src/lsp/server.ts +2046 -0
- package/src/mcp/auth.ts +132 -0
- package/src/mcp/index.ts +937 -0
- package/src/mcp/oauth-callback.ts +200 -0
- package/src/mcp/oauth-provider.ts +154 -0
- package/src/patch/index.ts +680 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/index.ts +210 -0
- package/src/permission/next.ts +280 -0
- package/src/plugin/codex.ts +624 -0
- package/src/plugin/copilot.ts +327 -0
- package/src/plugin/index.ts +138 -0
- package/src/project/bootstrap.ts +35 -0
- package/src/project/instance.ts +114 -0
- package/src/project/project.ts +371 -0
- package/src/project/state.ts +70 -0
- package/src/project/vcs.ts +76 -0
- package/src/provider/auth.ts +147 -0
- package/src/provider/error.ts +189 -0
- package/src/provider/models.ts +133 -0
- package/src/provider/provider.ts +1370 -0
- package/src/provider/sdk/copilot/README.md +5 -0
- package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +164 -0
- package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
- package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +17 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +780 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +87 -0
- package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
- package/src/provider/sdk/copilot/index.ts +2 -0
- package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
- package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
- package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1732 -0
- package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/copilot/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/copilot/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/copilot/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/copilot/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +806 -0
- package/src/pty/index.ts +286 -0
- package/src/question/index.ts +171 -0
- package/src/scheduler/index.ts +61 -0
- package/src/server/error.ts +36 -0
- package/src/server/event.ts +7 -0
- package/src/server/mdns.ts +60 -0
- package/src/server/routes/config.ts +92 -0
- package/src/server/routes/experimental.ts +208 -0
- package/src/server/routes/file.ts +197 -0
- package/src/server/routes/global.ts +183 -0
- package/src/server/routes/mcp.ts +225 -0
- package/src/server/routes/permission.ts +68 -0
- package/src/server/routes/project.ts +82 -0
- package/src/server/routes/provider.ts +179 -0
- package/src/server/routes/pty.ts +176 -0
- package/src/server/routes/question.ts +98 -0
- package/src/server/routes/session.ts +939 -0
- package/src/server/routes/tui.ts +379 -0
- package/src/server/server.ts +621 -0
- package/src/session/compaction.ts +261 -0
- package/src/session/index.ts +543 -0
- package/src/session/instruction.ts +197 -0
- package/src/session/llm.ts +283 -0
- package/src/session/message-v2.ts +841 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +410 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +105 -0
- package/src/session/prompt/beast.txt +147 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex_header.txt +79 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
- package/src/session/prompt/plan.txt +26 -0
- package/src/session/prompt/qwen.txt +109 -0
- package/src/session/prompt/trinity.txt +97 -0
- package/src/session/prompt.ts +1964 -0
- package/src/session/retry.ts +101 -0
- package/src/session/revert.ts +121 -0
- package/src/session/status.ts +76 -0
- package/src/session/summary.ts +203 -0
- package/src/session/system.ts +54 -0
- package/src/session/todo.ts +37 -0
- package/src/share/share-next.ts +200 -0
- package/src/share/share.ts +92 -0
- package/src/shell/shell.ts +67 -0
- package/src/skill/discovery.ts +97 -0
- package/src/skill/index.ts +1 -0
- package/src/skill/skill.ts +188 -0
- package/src/snapshot/index.ts +255 -0
- package/src/storage/storage.ts +227 -0
- package/src/tool/apply_patch.ts +281 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/bash.ts +269 -0
- package/src/tool/bash.txt +115 -0
- package/src/tool/batch.ts +175 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/codesearch.ts +132 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +655 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +32 -0
- package/src/tool/glob.ts +80 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +150 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +121 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp.ts +96 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/plan-enter.txt +14 -0
- package/src/tool/plan-exit.txt +13 -0
- package/src/tool/plan.ts +130 -0
- package/src/tool/question.ts +33 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/read.ts +261 -0
- package/src/tool/read.txt +14 -0
- package/src/tool/registry.ts +160 -0
- package/src/tool/skill.ts +123 -0
- package/src/tool/task.ts +165 -0
- package/src/tool/task.txt +60 -0
- package/src/tool/todo.ts +53 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +89 -0
- package/src/tool/truncation.ts +106 -0
- package/src/tool/webfetch.ts +186 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +150 -0
- package/src/tool/websearch.txt +14 -0
- package/src/tool/write.ts +85 -0
- package/src/tool/write.txt +8 -0
- package/src/util/abort.ts +35 -0
- package/src/util/archive.ts +16 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +93 -0
- package/src/util/fn.ts +11 -0
- package/src/util/format.ts +20 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +103 -0
- package/src/util/lazy.ts +18 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +180 -0
- package/src/util/proxied.ts +3 -0
- package/src/util/queue.ts +32 -0
- package/src/util/rpc.ts +66 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +56 -0
- package/src/worktree/index.ts +612 -0
- package/sst-env.d.ts +9 -0
- package/test/acp/agent-interface.test.ts +51 -0
- package/test/acp/event-subscription.test.ts +436 -0
- package/test/agent/agent.test.ts +675 -0
- package/test/bun.test.ts +53 -0
- package/test/cli/github-action.test.ts +161 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/cli/import.test.ts +38 -0
- package/test/cli/tui/transcript.test.ts +322 -0
- package/test/config/agent-color.test.ts +71 -0
- package/test/config/config.test.ts +1802 -0
- package/test/config/fixtures/empty-frontmatter.md +4 -0
- package/test/config/fixtures/frontmatter.md +28 -0
- package/test/config/fixtures/markdown-header.md +11 -0
- package/test/config/fixtures/no-frontmatter.md +1 -0
- package/test/config/fixtures/weird-model-id.md +13 -0
- package/test/config/markdown.test.ts +228 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/file/path-traversal.test.ts +198 -0
- package/test/file/ripgrep.test.ts +39 -0
- package/test/fixture/fixture.ts +45 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/keybind.test.ts +421 -0
- package/test/lsp/client.test.ts +95 -0
- package/test/mcp/headers.test.ts +153 -0
- package/test/mcp/oauth-browser.test.ts +249 -0
- package/test/memory/abort-leak.test.ts +136 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/next.test.ts +690 -0
- package/test/permission-task.test.ts +319 -0
- package/test/plugin/auth-override.test.ts +44 -0
- package/test/plugin/codex.test.ts +123 -0
- package/test/preload.ts +63 -0
- package/test/project/project.test.ts +120 -0
- package/test/provider/amazon-bedrock.test.ts +445 -0
- package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
- package/test/provider/gitlab-duo.test.ts +262 -0
- package/test/provider/provider.test.ts +2129 -0
- package/test/provider/transform.test.ts +1928 -0
- package/test/question/question.test.ts +300 -0
- package/test/scheduler.test.ts +73 -0
- package/test/server/session-list.test.ts +39 -0
- package/test/server/session-select.test.ts +78 -0
- package/test/session/compaction.test.ts +423 -0
- package/test/session/instruction.test.ts +170 -0
- package/test/session/llm.test.ts +667 -0
- package/test/session/message-v2.test.ts +924 -0
- package/test/session/prompt-missing-file.test.ts +53 -0
- package/test/session/prompt-special-chars.test.ts +56 -0
- package/test/session/prompt-variant.test.ts +68 -0
- package/test/session/retry.test.ts +188 -0
- package/test/session/revert-compact.test.ts +285 -0
- package/test/session/session.test.ts +71 -0
- package/test/session/structured-output-integration.test.ts +233 -0
- package/test/session/structured-output.test.ts +385 -0
- package/test/skill/discovery.test.ts +60 -0
- package/test/skill/skill.test.ts +388 -0
- package/test/snapshot/snapshot.test.ts +1040 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/apply_patch.test.ts +559 -0
- package/test/tool/bash.test.ts +399 -0
- package/test/tool/external-directory.test.ts +127 -0
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +38413 -0
- package/test/tool/grep.test.ts +110 -0
- package/test/tool/question.test.ts +107 -0
- package/test/tool/read.test.ts +421 -0
- package/test/tool/registry.test.ts +122 -0
- package/test/tool/skill.test.ts +112 -0
- package/test/tool/truncation.test.ts +159 -0
- package/test/util/filesystem.test.ts +39 -0
- package/test/util/format.test.ts +59 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/lock.test.ts +72 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +75 -0
- package/tsconfig.json +16 -0
package/src/flag/flag.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
function truthy(key: string) {
|
|
2
|
+
const value = process.env[key]?.toLowerCase()
|
|
3
|
+
return value === "true" || value === "1"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// Support both INNOCODE_ and OPENCODE_ prefixes, with INNOCODE_ taking precedence
|
|
7
|
+
function getEnv(innocodeKey: string, opencodeKey: string): string | undefined {
|
|
8
|
+
return process.env[innocodeKey] ?? process.env[opencodeKey]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getTruthy(innocodeKey: string, opencodeKey: string): boolean {
|
|
12
|
+
return truthy(innocodeKey) || truthy(opencodeKey)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export namespace Flag {
|
|
16
|
+
export const INNOCODE_AUTO_SHARE = getTruthy("INNOCODE_AUTO_SHARE", "OPENCODE_AUTO_SHARE")
|
|
17
|
+
export const INNOCODE_GIT_BASH_PATH = getEnv("INNOCODE_GIT_BASH_PATH", "OPENCODE_GIT_BASH_PATH")
|
|
18
|
+
export const INNOCODE_CONFIG = getEnv("INNOCODE_CONFIG", "OPENCODE_CONFIG")
|
|
19
|
+
export declare const INNOCODE_CONFIG_DIR: string | undefined
|
|
20
|
+
export declare const OPENCODE_CONFIG_DIR: string | undefined
|
|
21
|
+
export const INNOCODE_CONFIG_CONTENT = getEnv("INNOCODE_CONFIG_CONTENT", "OPENCODE_CONFIG_CONTENT")
|
|
22
|
+
export const INNOCODE_DISABLE_AUTOUPDATE = getTruthy("INNOCODE_DISABLE_AUTOUPDATE", "OPENCODE_DISABLE_AUTOUPDATE")
|
|
23
|
+
export const INNOCODE_DISABLE_PRUNE = getTruthy("INNOCODE_DISABLE_PRUNE", "OPENCODE_DISABLE_PRUNE")
|
|
24
|
+
export const INNOCODE_DISABLE_TERMINAL_TITLE = getTruthy("INNOCODE_DISABLE_TERMINAL_TITLE", "OPENCODE_DISABLE_TERMINAL_TITLE")
|
|
25
|
+
export const INNOCODE_PERMISSION = getEnv("INNOCODE_PERMISSION", "OPENCODE_PERMISSION")
|
|
26
|
+
export const INNOCODE_DISABLE_DEFAULT_PLUGINS = getTruthy("INNOCODE_DISABLE_DEFAULT_PLUGINS", "OPENCODE_DISABLE_DEFAULT_PLUGINS")
|
|
27
|
+
export const INNOCODE_DISABLE_LSP_DOWNLOAD = getTruthy("INNOCODE_DISABLE_LSP_DOWNLOAD", "OPENCODE_DISABLE_LSP_DOWNLOAD")
|
|
28
|
+
export const INNOCODE_ENABLE_EXPERIMENTAL_MODELS = getTruthy("INNOCODE_ENABLE_EXPERIMENTAL_MODELS", "OPENCODE_ENABLE_EXPERIMENTAL_MODELS")
|
|
29
|
+
export const INNOCODE_DISABLE_AUTOCOMPACT = getTruthy("INNOCODE_DISABLE_AUTOCOMPACT", "OPENCODE_DISABLE_AUTOCOMPACT")
|
|
30
|
+
export const INNOCODE_DISABLE_MODELS_FETCH = getTruthy("INNOCODE_DISABLE_MODELS_FETCH", "OPENCODE_DISABLE_MODELS_FETCH")
|
|
31
|
+
export const INNOCODE_DISABLE_CLAUDE_CODE = getTruthy("INNOCODE_DISABLE_CLAUDE_CODE", "OPENCODE_DISABLE_CLAUDE_CODE")
|
|
32
|
+
export const INNOCODE_DISABLE_CLAUDE_CODE_PROMPT =
|
|
33
|
+
INNOCODE_DISABLE_CLAUDE_CODE || getTruthy("INNOCODE_DISABLE_CLAUDE_CODE_PROMPT", "OPENCODE_DISABLE_CLAUDE_CODE_PROMPT")
|
|
34
|
+
export const INNOCODE_DISABLE_CLAUDE_CODE_SKILLS =
|
|
35
|
+
INNOCODE_DISABLE_CLAUDE_CODE || getTruthy("INNOCODE_DISABLE_CLAUDE_CODE_SKILLS", "OPENCODE_DISABLE_CLAUDE_CODE_SKILLS")
|
|
36
|
+
export const INNOCODE_DISABLE_EXTERNAL_SKILLS =
|
|
37
|
+
INNOCODE_DISABLE_CLAUDE_CODE_SKILLS || getTruthy("INNOCODE_DISABLE_EXTERNAL_SKILLS", "OPENCODE_DISABLE_EXTERNAL_SKILLS")
|
|
38
|
+
export declare const INNOCODE_DISABLE_PROJECT_CONFIG: boolean
|
|
39
|
+
export declare const OPENCODE_DISABLE_PROJECT_CONFIG: boolean
|
|
40
|
+
export const INNOCODE_FAKE_VCS = getEnv("INNOCODE_FAKE_VCS", "OPENCODE_FAKE_VCS")
|
|
41
|
+
export const INNOCODE_CLIENT = getEnv("INNOCODE_CLIENT", "OPENCODE_CLIENT") ?? "cli"
|
|
42
|
+
export const INNOCODE_SERVER_PASSWORD = getEnv("INNOCODE_SERVER_PASSWORD", "OPENCODE_SERVER_PASSWORD")
|
|
43
|
+
export const INNOCODE_SERVER_USERNAME = getEnv("INNOCODE_SERVER_USERNAME", "OPENCODE_SERVER_USERNAME")
|
|
44
|
+
|
|
45
|
+
// Experimental
|
|
46
|
+
export const INNOCODE_EXPERIMENTAL = getTruthy("INNOCODE_EXPERIMENTAL", "OPENCODE_EXPERIMENTAL")
|
|
47
|
+
export const INNOCODE_EXPERIMENTAL_FILEWATCHER = getTruthy("INNOCODE_EXPERIMENTAL_FILEWATCHER", "OPENCODE_EXPERIMENTAL_FILEWATCHER")
|
|
48
|
+
export const INNOCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = getTruthy("INNOCODE_EXPERIMENTAL_DISABLE_FILEWATCHER", "OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER")
|
|
49
|
+
export const INNOCODE_EXPERIMENTAL_ICON_DISCOVERY =
|
|
50
|
+
INNOCODE_EXPERIMENTAL || getTruthy("INNOCODE_EXPERIMENTAL_ICON_DISCOVERY", "OPENCODE_EXPERIMENTAL_ICON_DISCOVERY")
|
|
51
|
+
export const INNOCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT = getTruthy("INNOCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT", "OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT")
|
|
52
|
+
export const INNOCODE_ENABLE_EXA =
|
|
53
|
+
getTruthy("INNOCODE_ENABLE_EXA", "OPENCODE_ENABLE_EXA") || INNOCODE_EXPERIMENTAL || getTruthy("INNOCODE_EXPERIMENTAL_EXA", "OPENCODE_EXPERIMENTAL_EXA")
|
|
54
|
+
export const INNOCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH = number("INNOCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH", "OPENCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH")
|
|
55
|
+
export const INNOCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS = number("INNOCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS", "OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS")
|
|
56
|
+
export const INNOCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX = number("INNOCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX", "OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX")
|
|
57
|
+
export const INNOCODE_EXPERIMENTAL_OXFMT = INNOCODE_EXPERIMENTAL || getTruthy("INNOCODE_EXPERIMENTAL_OXFMT", "OPENCODE_EXPERIMENTAL_OXFMT")
|
|
58
|
+
export const INNOCODE_EXPERIMENTAL_LSP_TY = getTruthy("INNOCODE_EXPERIMENTAL_LSP_TY", "OPENCODE_EXPERIMENTAL_LSP_TY")
|
|
59
|
+
export const INNOCODE_EXPERIMENTAL_LSP_TOOL = INNOCODE_EXPERIMENTAL || getTruthy("INNOCODE_EXPERIMENTAL_LSP_TOOL", "OPENCODE_EXPERIMENTAL_LSP_TOOL")
|
|
60
|
+
export const INNOCODE_DISABLE_FILETIME_CHECK = getTruthy("INNOCODE_DISABLE_FILETIME_CHECK", "OPENCODE_DISABLE_FILETIME_CHECK")
|
|
61
|
+
export const INNOCODE_EXPERIMENTAL_PLAN_MODE = INNOCODE_EXPERIMENTAL || getTruthy("INNOCODE_EXPERIMENTAL_PLAN_MODE", "OPENCODE_EXPERIMENTAL_PLAN_MODE")
|
|
62
|
+
export const INNOCODE_EXPERIMENTAL_MARKDOWN = getTruthy("INNOCODE_EXPERIMENTAL_MARKDOWN", "OPENCODE_EXPERIMENTAL_MARKDOWN")
|
|
63
|
+
export const INNOCODE_MODELS_URL = getEnv("INNOCODE_MODELS_URL", "OPENCODE_MODELS_URL")
|
|
64
|
+
export const INNOCODE_MODELS_PATH = getEnv("INNOCODE_MODELS_PATH", "OPENCODE_MODELS_PATH")
|
|
65
|
+
|
|
66
|
+
// Legacy aliases (for backwards compatibility with OPENCODE_ prefix)
|
|
67
|
+
export const OPENCODE_AUTO_SHARE = INNOCODE_AUTO_SHARE
|
|
68
|
+
export const OPENCODE_GIT_BASH_PATH = INNOCODE_GIT_BASH_PATH
|
|
69
|
+
export const OPENCODE_CONFIG = INNOCODE_CONFIG
|
|
70
|
+
export const OPENCODE_CONFIG_CONTENT = INNOCODE_CONFIG_CONTENT
|
|
71
|
+
export const OPENCODE_DISABLE_AUTOUPDATE = INNOCODE_DISABLE_AUTOUPDATE
|
|
72
|
+
export const OPENCODE_DISABLE_PRUNE = INNOCODE_DISABLE_PRUNE
|
|
73
|
+
export const OPENCODE_DISABLE_TERMINAL_TITLE = INNOCODE_DISABLE_TERMINAL_TITLE
|
|
74
|
+
export const OPENCODE_PERMISSION = INNOCODE_PERMISSION
|
|
75
|
+
export const OPENCODE_DISABLE_DEFAULT_PLUGINS = INNOCODE_DISABLE_DEFAULT_PLUGINS
|
|
76
|
+
export const OPENCODE_DISABLE_LSP_DOWNLOAD = INNOCODE_DISABLE_LSP_DOWNLOAD
|
|
77
|
+
export const OPENCODE_ENABLE_EXPERIMENTAL_MODELS = INNOCODE_ENABLE_EXPERIMENTAL_MODELS
|
|
78
|
+
export const OPENCODE_DISABLE_AUTOCOMPACT = INNOCODE_DISABLE_AUTOCOMPACT
|
|
79
|
+
export const OPENCODE_DISABLE_MODELS_FETCH = INNOCODE_DISABLE_MODELS_FETCH
|
|
80
|
+
export const OPENCODE_DISABLE_CLAUDE_CODE = INNOCODE_DISABLE_CLAUDE_CODE
|
|
81
|
+
export const OPENCODE_DISABLE_CLAUDE_CODE_PROMPT = INNOCODE_DISABLE_CLAUDE_CODE_PROMPT
|
|
82
|
+
export const OPENCODE_DISABLE_CLAUDE_CODE_SKILLS = INNOCODE_DISABLE_CLAUDE_CODE_SKILLS
|
|
83
|
+
export const OPENCODE_DISABLE_EXTERNAL_SKILLS = INNOCODE_DISABLE_EXTERNAL_SKILLS
|
|
84
|
+
export const OPENCODE_FAKE_VCS = INNOCODE_FAKE_VCS
|
|
85
|
+
export const OPENCODE_CLIENT = INNOCODE_CLIENT
|
|
86
|
+
export const OPENCODE_SERVER_PASSWORD = INNOCODE_SERVER_PASSWORD
|
|
87
|
+
export const OPENCODE_SERVER_USERNAME = INNOCODE_SERVER_USERNAME
|
|
88
|
+
export const OPENCODE_EXPERIMENTAL = INNOCODE_EXPERIMENTAL
|
|
89
|
+
export const OPENCODE_EXPERIMENTAL_FILEWATCHER = INNOCODE_EXPERIMENTAL_FILEWATCHER
|
|
90
|
+
export const OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = INNOCODE_EXPERIMENTAL_DISABLE_FILEWATCHER
|
|
91
|
+
export const OPENCODE_EXPERIMENTAL_ICON_DISCOVERY = INNOCODE_EXPERIMENTAL_ICON_DISCOVERY
|
|
92
|
+
export const OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT = INNOCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT
|
|
93
|
+
export const OPENCODE_ENABLE_EXA = INNOCODE_ENABLE_EXA
|
|
94
|
+
export const OPENCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH = INNOCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH
|
|
95
|
+
export const OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS = INNOCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS
|
|
96
|
+
export const OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX = INNOCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX
|
|
97
|
+
export const OPENCODE_EXPERIMENTAL_OXFMT = INNOCODE_EXPERIMENTAL_OXFMT
|
|
98
|
+
export const OPENCODE_EXPERIMENTAL_LSP_TY = INNOCODE_EXPERIMENTAL_LSP_TY
|
|
99
|
+
export const OPENCODE_EXPERIMENTAL_LSP_TOOL = INNOCODE_EXPERIMENTAL_LSP_TOOL
|
|
100
|
+
export const OPENCODE_DISABLE_FILETIME_CHECK = INNOCODE_DISABLE_FILETIME_CHECK
|
|
101
|
+
export const OPENCODE_EXPERIMENTAL_PLAN_MODE = INNOCODE_EXPERIMENTAL_PLAN_MODE
|
|
102
|
+
export const OPENCODE_EXPERIMENTAL_MARKDOWN = INNOCODE_EXPERIMENTAL_MARKDOWN
|
|
103
|
+
export const OPENCODE_MODELS_URL = INNOCODE_MODELS_URL
|
|
104
|
+
export const OPENCODE_MODELS_PATH = INNOCODE_MODELS_PATH
|
|
105
|
+
|
|
106
|
+
function number(innocodeKey: string, opencodeKey: string) {
|
|
107
|
+
const value = getEnv(innocodeKey, opencodeKey)
|
|
108
|
+
if (!value) return undefined
|
|
109
|
+
const parsed = Number(value)
|
|
110
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Dynamic getter for INNOCODE_DISABLE_PROJECT_CONFIG
|
|
115
|
+
Object.defineProperty(Flag, "INNOCODE_DISABLE_PROJECT_CONFIG", {
|
|
116
|
+
get() {
|
|
117
|
+
return truthy("INNOCODE_DISABLE_PROJECT_CONFIG") || truthy("OPENCODE_DISABLE_PROJECT_CONFIG")
|
|
118
|
+
},
|
|
119
|
+
enumerable: true,
|
|
120
|
+
configurable: false,
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// Legacy alias
|
|
124
|
+
Object.defineProperty(Flag, "OPENCODE_DISABLE_PROJECT_CONFIG", {
|
|
125
|
+
get() {
|
|
126
|
+
return (Flag as any).INNOCODE_DISABLE_PROJECT_CONFIG
|
|
127
|
+
},
|
|
128
|
+
enumerable: true,
|
|
129
|
+
configurable: false,
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// Dynamic getter for INNOCODE_CONFIG_DIR
|
|
133
|
+
Object.defineProperty(Flag, "INNOCODE_CONFIG_DIR", {
|
|
134
|
+
get() {
|
|
135
|
+
return process.env["INNOCODE_CONFIG_DIR"] ?? process.env["OPENCODE_CONFIG_DIR"]
|
|
136
|
+
},
|
|
137
|
+
enumerable: true,
|
|
138
|
+
configurable: false,
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// Legacy alias
|
|
142
|
+
Object.defineProperty(Flag, "OPENCODE_CONFIG_DIR", {
|
|
143
|
+
get() {
|
|
144
|
+
return (Flag as any).INNOCODE_CONFIG_DIR
|
|
145
|
+
},
|
|
146
|
+
enumerable: true,
|
|
147
|
+
configurable: false,
|
|
148
|
+
})
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { readableStreamToText } from "bun"
|
|
2
|
+
import { BunProc } from "../bun"
|
|
3
|
+
import { Instance } from "../project/instance"
|
|
4
|
+
import { Filesystem } from "../util/filesystem"
|
|
5
|
+
import { Flag } from "@/flag/flag"
|
|
6
|
+
|
|
7
|
+
export interface Info {
|
|
8
|
+
name: string
|
|
9
|
+
command: string[]
|
|
10
|
+
environment?: Record<string, string>
|
|
11
|
+
extensions: string[]
|
|
12
|
+
enabled(): Promise<boolean>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const gofmt: Info = {
|
|
16
|
+
name: "gofmt",
|
|
17
|
+
command: ["gofmt", "-w", "$FILE"],
|
|
18
|
+
extensions: [".go"],
|
|
19
|
+
async enabled() {
|
|
20
|
+
return Bun.which("gofmt") !== null
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const mix: Info = {
|
|
25
|
+
name: "mix",
|
|
26
|
+
command: ["mix", "format", "$FILE"],
|
|
27
|
+
extensions: [".ex", ".exs", ".eex", ".heex", ".leex", ".neex", ".sface"],
|
|
28
|
+
async enabled() {
|
|
29
|
+
return Bun.which("mix") !== null
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const prettier: Info = {
|
|
34
|
+
name: "prettier",
|
|
35
|
+
command: [BunProc.which(), "x", "prettier", "--write", "$FILE"],
|
|
36
|
+
environment: {
|
|
37
|
+
BUN_BE_BUN: "1",
|
|
38
|
+
},
|
|
39
|
+
extensions: [
|
|
40
|
+
".js",
|
|
41
|
+
".jsx",
|
|
42
|
+
".mjs",
|
|
43
|
+
".cjs",
|
|
44
|
+
".ts",
|
|
45
|
+
".tsx",
|
|
46
|
+
".mts",
|
|
47
|
+
".cts",
|
|
48
|
+
".html",
|
|
49
|
+
".htm",
|
|
50
|
+
".css",
|
|
51
|
+
".scss",
|
|
52
|
+
".sass",
|
|
53
|
+
".less",
|
|
54
|
+
".vue",
|
|
55
|
+
".svelte",
|
|
56
|
+
".json",
|
|
57
|
+
".jsonc",
|
|
58
|
+
".yaml",
|
|
59
|
+
".yml",
|
|
60
|
+
".toml",
|
|
61
|
+
".xml",
|
|
62
|
+
".md",
|
|
63
|
+
".mdx",
|
|
64
|
+
".graphql",
|
|
65
|
+
".gql",
|
|
66
|
+
],
|
|
67
|
+
async enabled() {
|
|
68
|
+
const items = await Filesystem.findUp("package.json", Instance.directory, Instance.worktree)
|
|
69
|
+
for (const item of items) {
|
|
70
|
+
const json = await Bun.file(item).json()
|
|
71
|
+
if (json.dependencies?.prettier) return true
|
|
72
|
+
if (json.devDependencies?.prettier) return true
|
|
73
|
+
}
|
|
74
|
+
return false
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const oxfmt: Info = {
|
|
79
|
+
name: "oxfmt",
|
|
80
|
+
command: [BunProc.which(), "x", "oxfmt", "$FILE"],
|
|
81
|
+
environment: {
|
|
82
|
+
BUN_BE_BUN: "1",
|
|
83
|
+
},
|
|
84
|
+
extensions: [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts"],
|
|
85
|
+
async enabled() {
|
|
86
|
+
if (!Flag.OPENCODE_EXPERIMENTAL_OXFMT) return false
|
|
87
|
+
const items = await Filesystem.findUp("package.json", Instance.directory, Instance.worktree)
|
|
88
|
+
for (const item of items) {
|
|
89
|
+
const json = await Bun.file(item).json()
|
|
90
|
+
if (json.dependencies?.oxfmt) return true
|
|
91
|
+
if (json.devDependencies?.oxfmt) return true
|
|
92
|
+
}
|
|
93
|
+
return false
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const biome: Info = {
|
|
98
|
+
name: "biome",
|
|
99
|
+
command: [BunProc.which(), "x", "@biomejs/biome", "check", "--write", "$FILE"],
|
|
100
|
+
environment: {
|
|
101
|
+
BUN_BE_BUN: "1",
|
|
102
|
+
},
|
|
103
|
+
extensions: [
|
|
104
|
+
".js",
|
|
105
|
+
".jsx",
|
|
106
|
+
".mjs",
|
|
107
|
+
".cjs",
|
|
108
|
+
".ts",
|
|
109
|
+
".tsx",
|
|
110
|
+
".mts",
|
|
111
|
+
".cts",
|
|
112
|
+
".html",
|
|
113
|
+
".htm",
|
|
114
|
+
".css",
|
|
115
|
+
".scss",
|
|
116
|
+
".sass",
|
|
117
|
+
".less",
|
|
118
|
+
".vue",
|
|
119
|
+
".svelte",
|
|
120
|
+
".json",
|
|
121
|
+
".jsonc",
|
|
122
|
+
".yaml",
|
|
123
|
+
".yml",
|
|
124
|
+
".toml",
|
|
125
|
+
".xml",
|
|
126
|
+
".md",
|
|
127
|
+
".mdx",
|
|
128
|
+
".graphql",
|
|
129
|
+
".gql",
|
|
130
|
+
],
|
|
131
|
+
async enabled() {
|
|
132
|
+
const configs = ["biome.json", "biome.jsonc"]
|
|
133
|
+
for (const config of configs) {
|
|
134
|
+
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
|
|
135
|
+
if (found.length > 0) {
|
|
136
|
+
return true
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return false
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const zig: Info = {
|
|
144
|
+
name: "zig",
|
|
145
|
+
command: ["zig", "fmt", "$FILE"],
|
|
146
|
+
extensions: [".zig", ".zon"],
|
|
147
|
+
async enabled() {
|
|
148
|
+
return Bun.which("zig") !== null
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const clang: Info = {
|
|
153
|
+
name: "clang-format",
|
|
154
|
+
command: ["clang-format", "-i", "$FILE"],
|
|
155
|
+
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
|
|
156
|
+
async enabled() {
|
|
157
|
+
const items = await Filesystem.findUp(".clang-format", Instance.directory, Instance.worktree)
|
|
158
|
+
return items.length > 0
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const ktlint: Info = {
|
|
163
|
+
name: "ktlint",
|
|
164
|
+
command: ["ktlint", "-F", "$FILE"],
|
|
165
|
+
extensions: [".kt", ".kts"],
|
|
166
|
+
async enabled() {
|
|
167
|
+
return Bun.which("ktlint") !== null
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const ruff: Info = {
|
|
172
|
+
name: "ruff",
|
|
173
|
+
command: ["ruff", "format", "$FILE"],
|
|
174
|
+
extensions: [".py", ".pyi"],
|
|
175
|
+
async enabled() {
|
|
176
|
+
if (!Bun.which("ruff")) return false
|
|
177
|
+
const configs = ["pyproject.toml", "ruff.toml", ".ruff.toml"]
|
|
178
|
+
for (const config of configs) {
|
|
179
|
+
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
|
|
180
|
+
if (found.length > 0) {
|
|
181
|
+
if (config === "pyproject.toml") {
|
|
182
|
+
const content = await Bun.file(found[0]).text()
|
|
183
|
+
if (content.includes("[tool.ruff]")) return true
|
|
184
|
+
} else {
|
|
185
|
+
return true
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const deps = ["requirements.txt", "pyproject.toml", "Pipfile"]
|
|
190
|
+
for (const dep of deps) {
|
|
191
|
+
const found = await Filesystem.findUp(dep, Instance.directory, Instance.worktree)
|
|
192
|
+
if (found.length > 0) {
|
|
193
|
+
const content = await Bun.file(found[0]).text()
|
|
194
|
+
if (content.includes("ruff")) return true
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return false
|
|
198
|
+
},
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export const rlang: Info = {
|
|
202
|
+
name: "air",
|
|
203
|
+
command: ["air", "format", "$FILE"],
|
|
204
|
+
extensions: [".R"],
|
|
205
|
+
async enabled() {
|
|
206
|
+
const airPath = Bun.which("air")
|
|
207
|
+
if (airPath == null) return false
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
const proc = Bun.spawn(["air", "--help"], {
|
|
211
|
+
stdout: "pipe",
|
|
212
|
+
stderr: "pipe",
|
|
213
|
+
})
|
|
214
|
+
await proc.exited
|
|
215
|
+
const output = await readableStreamToText(proc.stdout)
|
|
216
|
+
|
|
217
|
+
// Check for "Air: An R language server and formatter"
|
|
218
|
+
const firstLine = output.split("\n")[0]
|
|
219
|
+
const hasR = firstLine.includes("R language")
|
|
220
|
+
const hasFormatter = firstLine.includes("formatter")
|
|
221
|
+
return hasR && hasFormatter
|
|
222
|
+
} catch (error) {
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const uvformat: Info = {
|
|
229
|
+
name: "uv",
|
|
230
|
+
command: ["uv", "format", "--", "$FILE"],
|
|
231
|
+
extensions: [".py", ".pyi"],
|
|
232
|
+
async enabled() {
|
|
233
|
+
if (await ruff.enabled()) return false
|
|
234
|
+
if (Bun.which("uv") !== null) {
|
|
235
|
+
const proc = Bun.spawn(["uv", "format", "--help"], { stderr: "pipe", stdout: "pipe" })
|
|
236
|
+
const code = await proc.exited
|
|
237
|
+
return code === 0
|
|
238
|
+
}
|
|
239
|
+
return false
|
|
240
|
+
},
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export const rubocop: Info = {
|
|
244
|
+
name: "rubocop",
|
|
245
|
+
command: ["rubocop", "--autocorrect", "$FILE"],
|
|
246
|
+
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
|
247
|
+
async enabled() {
|
|
248
|
+
return Bun.which("rubocop") !== null
|
|
249
|
+
},
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export const standardrb: Info = {
|
|
253
|
+
name: "standardrb",
|
|
254
|
+
command: ["standardrb", "--fix", "$FILE"],
|
|
255
|
+
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
|
256
|
+
async enabled() {
|
|
257
|
+
return Bun.which("standardrb") !== null
|
|
258
|
+
},
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const htmlbeautifier: Info = {
|
|
262
|
+
name: "htmlbeautifier",
|
|
263
|
+
command: ["htmlbeautifier", "$FILE"],
|
|
264
|
+
extensions: [".erb", ".html.erb"],
|
|
265
|
+
async enabled() {
|
|
266
|
+
return Bun.which("htmlbeautifier") !== null
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export const dart: Info = {
|
|
271
|
+
name: "dart",
|
|
272
|
+
command: ["dart", "format", "$FILE"],
|
|
273
|
+
extensions: [".dart"],
|
|
274
|
+
async enabled() {
|
|
275
|
+
return Bun.which("dart") !== null
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export const ocamlformat: Info = {
|
|
280
|
+
name: "ocamlformat",
|
|
281
|
+
command: ["ocamlformat", "-i", "$FILE"],
|
|
282
|
+
extensions: [".ml", ".mli"],
|
|
283
|
+
async enabled() {
|
|
284
|
+
if (!Bun.which("ocamlformat")) return false
|
|
285
|
+
const items = await Filesystem.findUp(".ocamlformat", Instance.directory, Instance.worktree)
|
|
286
|
+
return items.length > 0
|
|
287
|
+
},
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export const terraform: Info = {
|
|
291
|
+
name: "terraform",
|
|
292
|
+
command: ["terraform", "fmt", "$FILE"],
|
|
293
|
+
extensions: [".tf", ".tfvars"],
|
|
294
|
+
async enabled() {
|
|
295
|
+
return Bun.which("terraform") !== null
|
|
296
|
+
},
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export const latexindent: Info = {
|
|
300
|
+
name: "latexindent",
|
|
301
|
+
command: ["latexindent", "-w", "-s", "$FILE"],
|
|
302
|
+
extensions: [".tex"],
|
|
303
|
+
async enabled() {
|
|
304
|
+
return Bun.which("latexindent") !== null
|
|
305
|
+
},
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export const gleam: Info = {
|
|
309
|
+
name: "gleam",
|
|
310
|
+
command: ["gleam", "format", "$FILE"],
|
|
311
|
+
extensions: [".gleam"],
|
|
312
|
+
async enabled() {
|
|
313
|
+
return Bun.which("gleam") !== null
|
|
314
|
+
},
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export const shfmt: Info = {
|
|
318
|
+
name: "shfmt",
|
|
319
|
+
command: ["shfmt", "-w", "$FILE"],
|
|
320
|
+
extensions: [".sh", ".bash"],
|
|
321
|
+
async enabled() {
|
|
322
|
+
return Bun.which("shfmt") !== null
|
|
323
|
+
},
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export const nixfmt: Info = {
|
|
327
|
+
name: "nixfmt",
|
|
328
|
+
command: ["nixfmt", "$FILE"],
|
|
329
|
+
extensions: [".nix"],
|
|
330
|
+
async enabled() {
|
|
331
|
+
return Bun.which("nixfmt") !== null
|
|
332
|
+
},
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export const rustfmt: Info = {
|
|
336
|
+
name: "rustfmt",
|
|
337
|
+
command: ["rustfmt", "$FILE"],
|
|
338
|
+
extensions: [".rs"],
|
|
339
|
+
async enabled() {
|
|
340
|
+
return Bun.which("rustfmt") !== null
|
|
341
|
+
},
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export const pint: Info = {
|
|
345
|
+
name: "pint",
|
|
346
|
+
command: ["./vendor/bin/pint", "$FILE"],
|
|
347
|
+
extensions: [".php"],
|
|
348
|
+
async enabled() {
|
|
349
|
+
const items = await Filesystem.findUp("composer.json", Instance.directory, Instance.worktree)
|
|
350
|
+
for (const item of items) {
|
|
351
|
+
const json = await Bun.file(item).json()
|
|
352
|
+
if (json.require?.["laravel/pint"]) return true
|
|
353
|
+
if (json["require-dev"]?.["laravel/pint"]) return true
|
|
354
|
+
}
|
|
355
|
+
return false
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export const ormolu: Info = {
|
|
360
|
+
name: "ormolu",
|
|
361
|
+
command: ["ormolu", "-i", "$FILE"],
|
|
362
|
+
extensions: [".hs"],
|
|
363
|
+
async enabled() {
|
|
364
|
+
return Bun.which("ormolu") !== null
|
|
365
|
+
},
|
|
366
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Bus } from "../bus"
|
|
2
|
+
import { File } from "../file"
|
|
3
|
+
import { Log } from "../util/log"
|
|
4
|
+
import path from "path"
|
|
5
|
+
import z from "zod"
|
|
6
|
+
|
|
7
|
+
import * as Formatter from "./formatter"
|
|
8
|
+
import { Config } from "../config/config"
|
|
9
|
+
import { mergeDeep } from "remeda"
|
|
10
|
+
import { Instance } from "../project/instance"
|
|
11
|
+
|
|
12
|
+
export namespace Format {
|
|
13
|
+
const log = Log.create({ service: "format" })
|
|
14
|
+
|
|
15
|
+
export const Status = z
|
|
16
|
+
.object({
|
|
17
|
+
name: z.string(),
|
|
18
|
+
extensions: z.string().array(),
|
|
19
|
+
enabled: z.boolean(),
|
|
20
|
+
})
|
|
21
|
+
.meta({
|
|
22
|
+
ref: "FormatterStatus",
|
|
23
|
+
})
|
|
24
|
+
export type Status = z.infer<typeof Status>
|
|
25
|
+
|
|
26
|
+
const state = Instance.state(async () => {
|
|
27
|
+
const enabled: Record<string, boolean> = {}
|
|
28
|
+
const cfg = await Config.get()
|
|
29
|
+
|
|
30
|
+
const formatters: Record<string, Formatter.Info> = {}
|
|
31
|
+
if (cfg.formatter === false) {
|
|
32
|
+
log.info("all formatters are disabled")
|
|
33
|
+
return {
|
|
34
|
+
enabled,
|
|
35
|
+
formatters,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const item of Object.values(Formatter)) {
|
|
40
|
+
formatters[item.name] = item
|
|
41
|
+
}
|
|
42
|
+
for (const [name, item] of Object.entries(cfg.formatter ?? {})) {
|
|
43
|
+
if (item.disabled) {
|
|
44
|
+
delete formatters[name]
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
const result: Formatter.Info = mergeDeep(formatters[name] ?? {}, {
|
|
48
|
+
command: [],
|
|
49
|
+
extensions: [],
|
|
50
|
+
...item,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (result.command.length === 0) continue
|
|
54
|
+
|
|
55
|
+
result.enabled = async () => true
|
|
56
|
+
result.name = name
|
|
57
|
+
formatters[name] = result
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
enabled,
|
|
62
|
+
formatters,
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
async function isEnabled(item: Formatter.Info) {
|
|
67
|
+
const s = await state()
|
|
68
|
+
let status = s.enabled[item.name]
|
|
69
|
+
if (status === undefined) {
|
|
70
|
+
status = await item.enabled()
|
|
71
|
+
s.enabled[item.name] = status
|
|
72
|
+
}
|
|
73
|
+
return status
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function getFormatter(ext: string) {
|
|
77
|
+
const formatters = await state().then((x) => x.formatters)
|
|
78
|
+
const result = []
|
|
79
|
+
for (const item of Object.values(formatters)) {
|
|
80
|
+
log.info("checking", { name: item.name, ext })
|
|
81
|
+
if (!item.extensions.includes(ext)) continue
|
|
82
|
+
if (!(await isEnabled(item))) continue
|
|
83
|
+
log.info("enabled", { name: item.name, ext })
|
|
84
|
+
result.push(item)
|
|
85
|
+
}
|
|
86
|
+
return result
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function status() {
|
|
90
|
+
const s = await state()
|
|
91
|
+
const result: Status[] = []
|
|
92
|
+
for (const formatter of Object.values(s.formatters)) {
|
|
93
|
+
const enabled = await isEnabled(formatter)
|
|
94
|
+
result.push({
|
|
95
|
+
name: formatter.name,
|
|
96
|
+
extensions: formatter.extensions,
|
|
97
|
+
enabled,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
return result
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function init() {
|
|
104
|
+
log.info("init")
|
|
105
|
+
Bus.subscribe(File.Event.Edited, async (payload) => {
|
|
106
|
+
const file = payload.properties.file
|
|
107
|
+
log.info("formatting", { file })
|
|
108
|
+
const ext = path.extname(file)
|
|
109
|
+
|
|
110
|
+
for (const item of await getFormatter(ext)) {
|
|
111
|
+
log.info("running", { command: item.command })
|
|
112
|
+
try {
|
|
113
|
+
const proc = Bun.spawn({
|
|
114
|
+
cmd: item.command.map((x) => x.replace("$FILE", file)),
|
|
115
|
+
cwd: Instance.directory,
|
|
116
|
+
env: { ...process.env, ...item.environment },
|
|
117
|
+
stdout: "ignore",
|
|
118
|
+
stderr: "ignore",
|
|
119
|
+
})
|
|
120
|
+
const exit = await proc.exited
|
|
121
|
+
if (exit !== 0)
|
|
122
|
+
log.error("failed", {
|
|
123
|
+
command: item.command,
|
|
124
|
+
...item.environment,
|
|
125
|
+
})
|
|
126
|
+
} catch (error) {
|
|
127
|
+
log.error("failed to format file", {
|
|
128
|
+
error,
|
|
129
|
+
command: item.command,
|
|
130
|
+
...item.environment,
|
|
131
|
+
file,
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|