rird 2.1.231 → 2.3.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 +86 -0
- package/COMPLETED_TEST_SUITE.txt +280 -0
- package/Dockerfile +18 -0
- package/README.md +397 -6
- package/RIRD_ERROR_HANDLING_SUMMARY.md +307 -0
- package/TESTING.md +512 -0
- package/TEST_IMPLEMENTATION_REPORT.md +463 -0
- package/TEST_SUITE.md +307 -0
- package/TEST_SUMMARY.txt +380 -0
- package/bin/rird-perf.js +37 -0
- package/bin/rird.js +43 -8
- package/bunfig.toml +4 -0
- package/create-wrapper.ps1 +51 -0
- package/docs/ARCHITECTURE.md +768 -0
- package/docs/CLI_REFERENCE.md +681 -0
- package/docs/DOCUMENTATION_MANIFEST.md +392 -0
- package/docs/INDEX.md +295 -0
- package/docs/PRODUCTION_SETUP.md +633 -0
- package/docs/TROUBLESHOOTING.md +914 -0
- package/facebook_ads_library.png +0 -0
- package/nul +0 -0
- package/nul`nif +0 -0
- package/package.json +104 -15
- package/parsers-config.ts +239 -0
- package/rird-1.0.199.tgz +0 -0
- package/rird-1.0.205.tgz +0 -0
- package/script/build-windows.ts +56 -0
- package/script/build.ts +165 -0
- package/{postinstall.mjs → script/postinstall.mjs} +47 -68
- package/script/publish-registries.ts +187 -0
- package/script/publish.ts +85 -0
- package/script/schema.ts +47 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1063 -0
- package/src/acp/session.ts +101 -0
- package/src/acp/types.ts +22 -0
- package/src/agent/agent.ts +367 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +12 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +10 -0
- package/src/agent/prompt/title.txt +36 -0
- package/src/auth/index.ts +70 -0
- package/src/bun/index.ts +114 -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 +104 -0
- package/src/cli/cmd/activate.ts +50 -0
- package/src/cli/cmd/agent.ts +256 -0
- package/src/cli/cmd/auth.ts +412 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/debug/config.ts +15 -0
- package/src/cli/cmd/debug/file.ts +91 -0
- package/src/cli/cmd/debug/index.ts +43 -0
- package/src/cli/cmd/debug/lsp.ts +48 -0
- package/src/cli/cmd/debug/ripgrep.ts +83 -0
- package/src/cli/cmd/debug/scrap.ts +15 -0
- package/src/cli/cmd/debug/skill.ts +15 -0
- package/src/cli/cmd/debug/snapshot.ts +48 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1400 -0
- package/src/cli/cmd/import.ts +98 -0
- package/src/cli/cmd/mcp.ts +654 -0
- package/src/cli/cmd/models.ts +68 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +434 -0
- package/src/cli/cmd/serve.ts +31 -0
- package/src/cli/cmd/session.ts +106 -0
- package/src/cli/cmd/stats.ts +298 -0
- package/src/cli/cmd/tui/app.tsx +694 -0
- package/src/cli/cmd/tui/attach.ts +30 -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 +124 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +236 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +240 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +162 -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/did-you-know.tsx +85 -0
- package/src/cli/cmd/tui/component/logo.tsx +48 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +574 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1087 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/tips.ts +27 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/context/args.tsx +14 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +23 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +101 -0
- package/src/cli/cmd/tui/context/kv.tsx +49 -0
- package/src/cli/cmd/tui/context/local.tsx +345 -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 +74 -0
- package/src/cli/cmd/tui/context/sync.tsx +372 -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/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 +95 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -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 +245 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rird.json +245 -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 +1109 -0
- package/src/cli/cmd/tui/event.ts +40 -0
- package/src/cli/cmd/tui/hooks/use-safe-terminal-dimensions.ts +12 -0
- package/src/cli/cmd/tui/routes/home.tsx +138 -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 +88 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +125 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +1876 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +320 -0
- package/src/cli/cmd/tui/spawn.ts +60 -0
- package/src/cli/cmd/tui/thread.ts +142 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +333 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +171 -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 +127 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/terminal.ts +146 -0
- package/src/cli/cmd/tui/worker.ts +63 -0
- package/src/cli/cmd/uninstall.ts +344 -0
- package/src/cli/cmd/upgrade.ts +127 -0
- package/src/cli/cmd/web.ts +84 -0
- package/src/cli/error.ts +69 -0
- package/src/cli/ui.ts +101 -0
- package/src/cli/upgrade.ts +28 -0
- package/src/command/index.ts +80 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +97 -0
- package/src/config/config.ts +994 -0
- package/src/config/markdown.ts +41 -0
- package/src/env/index.ts +26 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +328 -0
- package/src/file/ripgrep.ts +393 -0
- package/src/file/time.ts +64 -0
- package/src/file/watcher.ts +103 -0
- package/src/flag/flag.ts +84 -0
- package/src/format/formatter.ts +315 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +101 -0
- package/src/id/id.ts +73 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +297 -0
- package/src/index.ts.backup +271 -0
- package/src/installation/index.ts +258 -0
- package/src/lib/IMPLEMENTATION_NOTES.md +345 -0
- package/src/lib/error-handler.ts +225 -0
- package/src/lib/error-testing-guide.md +258 -0
- package/src/lib/errors.ts +285 -0
- package/src/lib/performance.ts +70 -0
- package/src/lib/telemetry.ts +282 -0
- package/src/lsp/client.ts +229 -0
- package/src/lsp/index.ts +485 -0
- package/src/lsp/language.ts +116 -0
- package/src/lsp/server.ts +1895 -0
- package/src/mcp/auth.ts +135 -0
- package/src/mcp/index.ts +1117 -0
- package/src/mcp/intent-analyzer.ts +376 -0
- package/src/mcp/oauth-callback.ts +200 -0
- package/src/mcp/oauth-provider.ts +154 -0
- package/src/patch/index.ts +632 -0
- package/src/permission/index.ts +199 -0
- package/src/plugin/index.ts +91 -0
- package/src/project/bootstrap.ts +33 -0
- package/src/project/instance.ts +78 -0
- package/src/project/project.ts +236 -0
- package/src/project/state.ts +65 -0
- package/src/project/vcs.ts +76 -0
- package/src/provider/auth.ts +143 -0
- package/src/provider/models-macro.ts +55 -0
- package/src/provider/models.ts +161 -0
- package/src/provider/provider.ts +1109 -0
- package/src/provider/sdk/openai-compatible/src/README.md +5 -0
- package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
- package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
- package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +455 -0
- package/src/pty/index.ts +231 -0
- package/src/security/guardrails.test.ts +341 -0
- package/src/security/guardrails.ts +570 -0
- package/src/security/index.ts +19 -0
- package/src/server/error.ts +36 -0
- package/src/server/project.ts +79 -0
- package/src/server/server.ts +2641 -0
- package/src/server/tui.ts +71 -0
- package/src/session/compaction.ts +228 -0
- package/src/session/index.ts +464 -0
- package/src/session/llm.ts +201 -0
- package/src/session/message-v2.ts +695 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +409 -0
- package/src/session/prompt/act-switch.txt +5 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +63 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +76 -0
- package/src/session/prompt/codex.txt +304 -0
- package/src/session/prompt/copilot-gpt-5.txt +137 -0
- package/src/session/prompt/gemini.txt +62 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +35 -0
- package/src/session/prompt/plan.txt +24 -0
- package/src/session/prompt/polaris.txt +88 -0
- package/src/session/prompt/qwen.txt +59 -0
- package/src/session/prompt.ts +1552 -0
- package/src/session/retry.ts +86 -0
- package/src/session/revert.ts +108 -0
- package/src/session/sensitive-filter.test.ts +327 -0
- package/src/session/sensitive-filter.ts +466 -0
- package/src/session/status.ts +76 -0
- package/src/session/summary.ts +209 -0
- package/src/session/system.ts +122 -0
- package/src/session/todo.ts +37 -0
- package/src/share/share-next.ts +222 -0
- package/src/share/share.ts +87 -0
- package/src/shell/shell.ts +67 -0
- package/src/skill/index.ts +1 -0
- package/src/skill/skill.ts +83 -0
- package/src/snapshot/index.ts +197 -0
- package/src/storage/storage.ts +226 -0
- package/src/tests/agent.test.ts +308 -0
- package/src/tests/build-guards.test.ts +267 -0
- package/src/tests/config.test.ts +664 -0
- package/src/tests/tool-registry.test.ts +589 -0
- package/src/tool/bash.ts +314 -0
- package/src/tool/bash.txt +158 -0
- package/src/tool/batch.ts +175 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/codesearch.ts +184 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +675 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/glob.ts +65 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +121 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +110 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp-diagnostics.ts +26 -0
- package/src/tool/lsp-diagnostics.txt +1 -0
- package/src/tool/lsp-hover.ts +31 -0
- package/src/tool/lsp-hover.txt +1 -0
- package/src/tool/lsp.ts +87 -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/patch.ts +233 -0
- package/src/tool/patch.txt +1 -0
- package/src/tool/read.ts +219 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +162 -0
- package/src/tool/skill.ts +100 -0
- package/src/tool/task.ts +136 -0
- package/src/tool/task.txt +51 -0
- package/src/tool/todo.ts +39 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +71 -0
- package/src/tool/webfetch.ts +198 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +268 -0
- package/src/tool/websearch.txt +13 -0
- package/src/tool/write.ts +110 -0
- package/src/tool/write.txt +8 -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 +83 -0
- package/src/util/fn.ts +11 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +102 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/license.ts +362 -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/queue.ts +32 -0
- package/src/util/rpc.ts +42 -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 +54 -0
- package/sst-env.d.ts +9 -0
- package/test/agent/agent.test.ts +146 -0
- package/test/bun.test.ts +53 -0
- package/test/cli/cmd/acp.test.ts +144 -0
- package/test/cli/cmd/run.test.ts +250 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/config/agent-color.test.ts +66 -0
- package/test/config/config.test.ts +536 -0
- package/test/config/markdown.test.ts +89 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/fixture/fixture.ts +37 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/helpers.ts +172 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/installation/installation.test.ts +143 -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/patch/patch.test.ts +348 -0
- package/test/preload.ts +57 -0
- package/test/project/project.test.ts +74 -0
- package/test/provider/provider.test.ts +74 -0
- package/test/provider/transform.test.ts +411 -0
- package/test/session/retry.test.ts +111 -0
- package/test/session/session.test.ts +71 -0
- package/test/skill/skill.test.ts +131 -0
- package/test/snapshot/snapshot.test.ts +940 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/bash.test.ts +434 -0
- package/test/tool/grep.test.ts +108 -0
- package/test/tool/patch.test.ts +259 -0
- package/test/tool/read.test.ts +42 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/license.test.ts +235 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +55 -0
- package/tsconfig.json +16 -0
- package/update-versions.ps1 +65 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach, afterEach } from "bun:test"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { tmpdir } from "../../fixture/fixture"
|
|
4
|
+
import { Instance } from "../../../src/project/instance"
|
|
5
|
+
|
|
6
|
+
describe("ACP Command", () => {
|
|
7
|
+
test("should have acp command defined with correct options", async () => {
|
|
8
|
+
// Import the ACP command to verify it's defined
|
|
9
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
10
|
+
|
|
11
|
+
expect(AcpCommand).toBeDefined()
|
|
12
|
+
expect(AcpCommand.command).toBe("acp")
|
|
13
|
+
expect(AcpCommand.describe).toContain("ACP")
|
|
14
|
+
expect(AcpCommand.describe).toContain("Agent Client Protocol")
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test("acp command should have port option", async () => {
|
|
18
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
19
|
+
|
|
20
|
+
// Verify the builder sets up port option
|
|
21
|
+
expect(AcpCommand.builder).toBeDefined()
|
|
22
|
+
|
|
23
|
+
// The builder is a function that sets up yargs
|
|
24
|
+
// We test that it's callable
|
|
25
|
+
let hasPortOption = false
|
|
26
|
+
let hasHostnameOption = false
|
|
27
|
+
|
|
28
|
+
// Mock yargs to capture builder calls
|
|
29
|
+
const mockYargs = {
|
|
30
|
+
option: (name: string) => {
|
|
31
|
+
if (name === "port") hasPortOption = true
|
|
32
|
+
if (name === "hostname") hasHostnameOption = true
|
|
33
|
+
return mockYargs
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof AcpCommand.builder === "function") {
|
|
38
|
+
AcpCommand.builder(mockYargs as any)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
expect(hasPortOption).toBe(true)
|
|
42
|
+
expect(hasHostnameOption).toBe(true)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test("acp command handler should be async function", async () => {
|
|
46
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
47
|
+
|
|
48
|
+
expect(AcpCommand.handler).toBeDefined()
|
|
49
|
+
expect(typeof AcpCommand.handler).toBe("function")
|
|
50
|
+
|
|
51
|
+
// Verify it's async
|
|
52
|
+
const result = AcpCommand.handler({
|
|
53
|
+
cwd: process.cwd(),
|
|
54
|
+
port: 0,
|
|
55
|
+
hostname: "127.0.0.1",
|
|
56
|
+
_: [],
|
|
57
|
+
$0: "",
|
|
58
|
+
} as any)
|
|
59
|
+
|
|
60
|
+
expect(result).toBeInstanceOf(Promise)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("acp command should accept custom working directory", async () => {
|
|
64
|
+
await using tmp = await tmpdir()
|
|
65
|
+
|
|
66
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
67
|
+
|
|
68
|
+
expect(AcpCommand.builder).toBeDefined()
|
|
69
|
+
|
|
70
|
+
// Verify cwd option exists by checking the builder
|
|
71
|
+
let cwdOptionFound = false
|
|
72
|
+
const mockYargs = {
|
|
73
|
+
option: (name: string, config: any) => {
|
|
74
|
+
if (name === "cwd") {
|
|
75
|
+
cwdOptionFound = true
|
|
76
|
+
expect(config.describe).toContain("working directory")
|
|
77
|
+
expect(config.type).toBe("string")
|
|
78
|
+
}
|
|
79
|
+
return mockYargs
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof AcpCommand.builder === "function") {
|
|
84
|
+
AcpCommand.builder(mockYargs as any)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
expect(cwdOptionFound).toBe(true)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test("acp command should support custom port", async () => {
|
|
91
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
92
|
+
|
|
93
|
+
let portConfig: any = null
|
|
94
|
+
const mockYargs = {
|
|
95
|
+
option: (name: string, config: any) => {
|
|
96
|
+
if (name === "port") {
|
|
97
|
+
portConfig = config
|
|
98
|
+
}
|
|
99
|
+
return mockYargs
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof AcpCommand.builder === "function") {
|
|
104
|
+
AcpCommand.builder(mockYargs as any)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
expect(portConfig).toBeDefined()
|
|
108
|
+
expect(portConfig.type).toBe("number")
|
|
109
|
+
expect(portConfig.default).toBe(0) // 0 means auto-assign
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test("acp command should have default hostname", async () => {
|
|
113
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
114
|
+
|
|
115
|
+
let hostnameConfig: any = null
|
|
116
|
+
const mockYargs = {
|
|
117
|
+
option: (name: string, config: any) => {
|
|
118
|
+
if (name === "hostname") {
|
|
119
|
+
hostnameConfig = config
|
|
120
|
+
}
|
|
121
|
+
return mockYargs
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (typeof AcpCommand.builder === "function") {
|
|
126
|
+
AcpCommand.builder(mockYargs as any)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
expect(hostnameConfig).toBeDefined()
|
|
130
|
+
expect(hostnameConfig.type).toBe("string")
|
|
131
|
+
expect(hostnameConfig.default).toBe("127.0.0.1")
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test("acp command handler should unhandled rejection handler", async () => {
|
|
135
|
+
const { AcpCommand } = await import("../../../src/cli/cmd/acp")
|
|
136
|
+
|
|
137
|
+
// Verify there's error handling for unhandled rejections
|
|
138
|
+
expect(AcpCommand).toBeDefined()
|
|
139
|
+
|
|
140
|
+
// The module should have set up unhandledRejection listener
|
|
141
|
+
const listeners = process.listeners("unhandledRejection")
|
|
142
|
+
expect(listeners.length).toBeGreaterThan(0)
|
|
143
|
+
})
|
|
144
|
+
})
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach, afterEach } from "bun:test"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { tmpdir } from "../../fixture/fixture"
|
|
4
|
+
import { mockEnv } from "../../helpers"
|
|
5
|
+
|
|
6
|
+
describe("Run Command", () => {
|
|
7
|
+
let restoreEnv: (() => void) | undefined
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// Setup test environment
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
if (restoreEnv) {
|
|
15
|
+
restoreEnv()
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("should have run command defined", async () => {
|
|
20
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
21
|
+
|
|
22
|
+
expect(RunCommand).toBeDefined()
|
|
23
|
+
expect(RunCommand.command).toBe("run [message..]")
|
|
24
|
+
expect(RunCommand.describe).toContain("run rird")
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test("run command should accept message positional argument", async () => {
|
|
28
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
29
|
+
|
|
30
|
+
let messagePositionFound = false
|
|
31
|
+
const mockYargs = {
|
|
32
|
+
positional: (name: string, config: any) => {
|
|
33
|
+
if (name === "message") {
|
|
34
|
+
messagePositionFound = true
|
|
35
|
+
expect(config.type).toBe("string")
|
|
36
|
+
expect(config.array).toBe(true)
|
|
37
|
+
}
|
|
38
|
+
return mockYargs
|
|
39
|
+
},
|
|
40
|
+
option: () => mockYargs,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof RunCommand.builder === "function") {
|
|
44
|
+
RunCommand.builder(mockYargs as any)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
expect(messagePositionFound).toBe(true)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test("run command should have model option", async () => {
|
|
51
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
52
|
+
|
|
53
|
+
let modelOptionFound = false
|
|
54
|
+
const mockYargs = {
|
|
55
|
+
positional: () => mockYargs,
|
|
56
|
+
option: (name: string, config: any) => {
|
|
57
|
+
if (name === "model") {
|
|
58
|
+
modelOptionFound = true
|
|
59
|
+
expect(config.type).toBe("string")
|
|
60
|
+
expect(config.alias).toContain("m")
|
|
61
|
+
}
|
|
62
|
+
return mockYargs
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof RunCommand.builder === "function") {
|
|
67
|
+
RunCommand.builder(mockYargs as any)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
expect(modelOptionFound).toBe(true)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test("run command should have session options", async () => {
|
|
74
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
75
|
+
|
|
76
|
+
let sessionOptionFound = false
|
|
77
|
+
let continueOptionFound = false
|
|
78
|
+
|
|
79
|
+
const mockYargs = {
|
|
80
|
+
positional: () => mockYargs,
|
|
81
|
+
option: (name: string, config: any) => {
|
|
82
|
+
if (name === "session") {
|
|
83
|
+
sessionOptionFound = true
|
|
84
|
+
expect(config.type).toBe("string")
|
|
85
|
+
expect(config.alias).toContain("s")
|
|
86
|
+
}
|
|
87
|
+
if (name === "continue") {
|
|
88
|
+
continueOptionFound = true
|
|
89
|
+
expect(config.type).toBe("boolean")
|
|
90
|
+
}
|
|
91
|
+
return mockYargs
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (typeof RunCommand.builder === "function") {
|
|
96
|
+
RunCommand.builder(mockYargs as any)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
expect(sessionOptionFound).toBe(true)
|
|
100
|
+
expect(continueOptionFound).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("run command should have file option", async () => {
|
|
104
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
105
|
+
|
|
106
|
+
let fileOptionFound = false
|
|
107
|
+
const mockYargs = {
|
|
108
|
+
positional: () => mockYargs,
|
|
109
|
+
option: (name: string, config: any) => {
|
|
110
|
+
if (name === "file") {
|
|
111
|
+
fileOptionFound = true
|
|
112
|
+
expect(config.type).toBe("string")
|
|
113
|
+
expect(config.array).toBe(true)
|
|
114
|
+
}
|
|
115
|
+
return mockYargs
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (typeof RunCommand.builder === "function") {
|
|
120
|
+
RunCommand.builder(mockYargs as any)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
expect(fileOptionFound).toBe(true)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
test("run command should have title option", async () => {
|
|
127
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
128
|
+
|
|
129
|
+
let titleOptionFound = false
|
|
130
|
+
const mockYargs = {
|
|
131
|
+
positional: () => mockYargs,
|
|
132
|
+
option: (name: string, config: any) => {
|
|
133
|
+
if (name === "title") {
|
|
134
|
+
titleOptionFound = true
|
|
135
|
+
expect(config.type).toBe("string")
|
|
136
|
+
}
|
|
137
|
+
return mockYargs
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (typeof RunCommand.builder === "function") {
|
|
142
|
+
RunCommand.builder(mockYargs as any)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
expect(titleOptionFound).toBe(true)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
test("run command should support format option", async () => {
|
|
149
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
150
|
+
|
|
151
|
+
let formatOptionFound = false
|
|
152
|
+
const mockYargs = {
|
|
153
|
+
positional: () => mockYargs,
|
|
154
|
+
option: (name: string, config: any) => {
|
|
155
|
+
if (name === "format") {
|
|
156
|
+
formatOptionFound = true
|
|
157
|
+
expect(config.type).toBe("string")
|
|
158
|
+
expect(config.choices).toContain("default")
|
|
159
|
+
expect(config.choices).toContain("json")
|
|
160
|
+
}
|
|
161
|
+
return mockYargs
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (typeof RunCommand.builder === "function") {
|
|
166
|
+
RunCommand.builder(mockYargs as any)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
expect(formatOptionFound).toBe(true)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test("run command should have handler function", async () => {
|
|
173
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
174
|
+
|
|
175
|
+
expect(RunCommand.handler).toBeDefined()
|
|
176
|
+
expect(typeof RunCommand.handler).toBe("function")
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test("run command builder should return yargs instance", async () => {
|
|
180
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
181
|
+
|
|
182
|
+
expect(typeof RunCommand.builder === "function").toBe(true)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
test("run command should support agent option", async () => {
|
|
186
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
187
|
+
|
|
188
|
+
let agentOptionFound = false
|
|
189
|
+
const mockYargs = {
|
|
190
|
+
positional: () => mockYargs,
|
|
191
|
+
option: (name: string, config: any) => {
|
|
192
|
+
if (name === "agent") {
|
|
193
|
+
agentOptionFound = true
|
|
194
|
+
expect(config.type).toBe("string")
|
|
195
|
+
}
|
|
196
|
+
return mockYargs
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (typeof RunCommand.builder === "function") {
|
|
201
|
+
RunCommand.builder(mockYargs as any)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
expect(agentOptionFound).toBe(true)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
test("run command should support share option", async () => {
|
|
208
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
209
|
+
|
|
210
|
+
let shareOptionFound = false
|
|
211
|
+
const mockYargs = {
|
|
212
|
+
positional: () => mockYargs,
|
|
213
|
+
option: (name: string, config: any) => {
|
|
214
|
+
if (name === "share") {
|
|
215
|
+
shareOptionFound = true
|
|
216
|
+
expect(config.type).toBe("boolean")
|
|
217
|
+
}
|
|
218
|
+
return mockYargs
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (typeof RunCommand.builder === "function") {
|
|
223
|
+
RunCommand.builder(mockYargs as any)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
expect(shareOptionFound).toBe(true)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
test("run command should have command option", async () => {
|
|
230
|
+
const { RunCommand } = await import("../../../src/cli/cmd/run")
|
|
231
|
+
|
|
232
|
+
let commandOptionFound = false
|
|
233
|
+
const mockYargs = {
|
|
234
|
+
positional: () => mockYargs,
|
|
235
|
+
option: (name: string, config: any) => {
|
|
236
|
+
if (name === "command") {
|
|
237
|
+
commandOptionFound = true
|
|
238
|
+
expect(config.type).toBe("string")
|
|
239
|
+
}
|
|
240
|
+
return mockYargs
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (typeof RunCommand.builder === "function") {
|
|
245
|
+
RunCommand.builder(mockYargs as any)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
expect(commandOptionFound).toBe(true)
|
|
249
|
+
})
|
|
250
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { test, expect } from "bun:test"
|
|
2
|
+
import { parseGitHubRemote } from "../../src/cli/cmd/github"
|
|
3
|
+
|
|
4
|
+
test("parses https URL with .git suffix", () => {
|
|
5
|
+
expect(parseGitHubRemote("https://github.com/sst/opencode.git")).toEqual({ owner: "sst", repo: "opencode" })
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test("parses https URL without .git suffix", () => {
|
|
9
|
+
expect(parseGitHubRemote("https://github.com/sst/opencode")).toEqual({ owner: "sst", repo: "opencode" })
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test("parses git@ URL with .git suffix", () => {
|
|
13
|
+
expect(parseGitHubRemote("git@github.com:sst/opencode.git")).toEqual({ owner: "sst", repo: "opencode" })
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test("parses git@ URL without .git suffix", () => {
|
|
17
|
+
expect(parseGitHubRemote("git@github.com:sst/opencode")).toEqual({ owner: "sst", repo: "opencode" })
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test("parses ssh:// URL with .git suffix", () => {
|
|
21
|
+
expect(parseGitHubRemote("ssh://git@github.com/sst/opencode.git")).toEqual({ owner: "sst", repo: "opencode" })
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test("parses ssh:// URL without .git suffix", () => {
|
|
25
|
+
expect(parseGitHubRemote("ssh://git@github.com/sst/opencode")).toEqual({ owner: "sst", repo: "opencode" })
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test("parses http URL", () => {
|
|
29
|
+
expect(parseGitHubRemote("http://github.com/owner/repo")).toEqual({ owner: "owner", repo: "repo" })
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("parses URL with hyphenated owner and repo names", () => {
|
|
33
|
+
expect(parseGitHubRemote("https://github.com/my-org/my-repo.git")).toEqual({ owner: "my-org", repo: "my-repo" })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("parses URL with underscores in names", () => {
|
|
37
|
+
expect(parseGitHubRemote("git@github.com:my_org/my_repo.git")).toEqual({ owner: "my_org", repo: "my_repo" })
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test("parses URL with numbers in names", () => {
|
|
41
|
+
expect(parseGitHubRemote("https://github.com/org123/repo456")).toEqual({ owner: "org123", repo: "repo456" })
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test("parses repos with dots in the name", () => {
|
|
45
|
+
expect(parseGitHubRemote("https://github.com/socketio/socket.io.git")).toEqual({
|
|
46
|
+
owner: "socketio",
|
|
47
|
+
repo: "socket.io",
|
|
48
|
+
})
|
|
49
|
+
expect(parseGitHubRemote("https://github.com/vuejs/vue.js")).toEqual({
|
|
50
|
+
owner: "vuejs",
|
|
51
|
+
repo: "vue.js",
|
|
52
|
+
})
|
|
53
|
+
expect(parseGitHubRemote("git@github.com:mrdoob/three.js.git")).toEqual({
|
|
54
|
+
owner: "mrdoob",
|
|
55
|
+
repo: "three.js",
|
|
56
|
+
})
|
|
57
|
+
expect(parseGitHubRemote("https://github.com/jashkenas/backbone.git")).toEqual({
|
|
58
|
+
owner: "jashkenas",
|
|
59
|
+
repo: "backbone",
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("returns null for non-github URLs", () => {
|
|
64
|
+
expect(parseGitHubRemote("https://gitlab.com/owner/repo.git")).toBeNull()
|
|
65
|
+
expect(parseGitHubRemote("git@gitlab.com:owner/repo.git")).toBeNull()
|
|
66
|
+
expect(parseGitHubRemote("https://bitbucket.org/owner/repo")).toBeNull()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test("returns null for invalid URLs", () => {
|
|
70
|
+
expect(parseGitHubRemote("not-a-url")).toBeNull()
|
|
71
|
+
expect(parseGitHubRemote("")).toBeNull()
|
|
72
|
+
expect(parseGitHubRemote("github.com")).toBeNull()
|
|
73
|
+
expect(parseGitHubRemote("https://github.com/")).toBeNull()
|
|
74
|
+
expect(parseGitHubRemote("https://github.com/owner")).toBeNull()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test("returns null for URLs with extra path segments", () => {
|
|
78
|
+
expect(parseGitHubRemote("https://github.com/owner/repo/tree/main")).toBeNull()
|
|
79
|
+
expect(parseGitHubRemote("https://github.com/owner/repo/blob/main/file.ts")).toBeNull()
|
|
80
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { test, expect } from "bun:test"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { tmpdir } from "../fixture/fixture"
|
|
4
|
+
import { Instance } from "../../src/project/instance"
|
|
5
|
+
import { Config } from "../../src/config/config"
|
|
6
|
+
import { Agent as AgentSvc } from "../../src/agent/agent"
|
|
7
|
+
import { Color } from "../../src/util/color"
|
|
8
|
+
|
|
9
|
+
test("agent color parsed from project config", async () => {
|
|
10
|
+
await using tmp = await tmpdir({
|
|
11
|
+
init: async (dir) => {
|
|
12
|
+
await Bun.write(
|
|
13
|
+
path.join(dir, "opencode.json"),
|
|
14
|
+
JSON.stringify({
|
|
15
|
+
$schema: "https://rird.ai/config.json",
|
|
16
|
+
agent: {
|
|
17
|
+
act: { color: "#FFA500" },
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
)
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
await Instance.provide({
|
|
24
|
+
directory: tmp.path,
|
|
25
|
+
fn: async () => {
|
|
26
|
+
const cfg = await Config.get()
|
|
27
|
+
expect(cfg.agent?.["act"]?.color).toBe("#FFA500")
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("Agent.get includes color from config", async () => {
|
|
33
|
+
await using tmp = await tmpdir({
|
|
34
|
+
init: async (dir) => {
|
|
35
|
+
await Bun.write(
|
|
36
|
+
path.join(dir, "opencode.json"),
|
|
37
|
+
JSON.stringify({
|
|
38
|
+
$schema: "https://rird.ai/config.json",
|
|
39
|
+
agent: {
|
|
40
|
+
plan: { color: "#A855F7" },
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
)
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
await Instance.provide({
|
|
47
|
+
directory: tmp.path,
|
|
48
|
+
fn: async () => {
|
|
49
|
+
const plan = await AgentSvc.get("plan")
|
|
50
|
+
expect(plan?.color).toBe("#A855F7")
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test("Color.hexToAnsiBold converts valid hex to ANSI", () => {
|
|
56
|
+
const result = Color.hexToAnsiBold("#FFA500")
|
|
57
|
+
expect(result).toBe("\x1b[38;2;255;165;0m\x1b[1m")
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test("Color.hexToAnsiBold returns undefined for invalid hex", () => {
|
|
61
|
+
expect(Color.hexToAnsiBold(undefined)).toBeUndefined()
|
|
62
|
+
expect(Color.hexToAnsiBold("")).toBeUndefined()
|
|
63
|
+
expect(Color.hexToAnsiBold("#FFF")).toBeUndefined()
|
|
64
|
+
expect(Color.hexToAnsiBold("FFA500")).toBeUndefined()
|
|
65
|
+
expect(Color.hexToAnsiBold("#GGGGGG")).toBeUndefined()
|
|
66
|
+
})
|