rird 1.0.200
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/opencode +336 -0
- package/bin/pty-wrapper.js +285 -0
- package/bunfig.toml +4 -0
- package/facebook_ads_library.png +0 -0
- package/nul`nif +0 -0
- package/package.json +111 -0
- package/parsers-config.ts +239 -0
- package/rird-1.0.199.tgz +0 -0
- package/script/build-windows.ts +54 -0
- package/script/build.ts +167 -0
- package/script/postinstall.mjs +544 -0
- package/script/publish-registries.ts +187 -0
- package/script/publish.ts +72 -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 +88 -0
- package/src/cli/cmd/agent.ts +256 -0
- package/src/cli/cmd/auth.ts +391 -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 +77 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +368 -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 +696 -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 +245 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +224 -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 +35 -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 +1090 -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 +354 -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/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 +1864 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +318 -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 +332 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +170 -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 +114 -0
- package/src/cli/cmd/tui/worker.ts +63 -0
- package/src/cli/cmd/uninstall.ts +344 -0
- package/src/cli/cmd/upgrade.ts +100 -0
- package/src/cli/cmd/web.ts +84 -0
- package/src/cli/error.ts +56 -0
- package/src/cli/ui.ts +84 -0
- package/src/cli/upgrade.ts +25 -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 +995 -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 +46 -0
- package/src/format/formatter.ts +315 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +52 -0
- package/src/id/id.ts +73 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +240 -0
- package/src/installation/index.ts +239 -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 +690 -0
- package/src/mcp/oauth-callback.ts +200 -0
- package/src/mcp/oauth-provider.ts +154 -0
- package/src/patch/index.ts +622 -0
- package/src/permission/index.ts +199 -0
- package/src/plugin/index.ts +91 -0
- package/src/project/bootstrap.ts +31 -0
- package/src/project/instance.ts +78 -0
- package/src/project/project.ts +221 -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 +11 -0
- package/src/provider/models.ts +106 -0
- package/src/provider/provider.ts +1071 -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 +558 -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 +2642 -0
- package/src/server/tui.ts +71 -0
- package/src/session/compaction.ts +223 -0
- package/src/session/index.ts +461 -0
- package/src/session/llm.ts +201 -0
- package/src/session/message-v2.ts +690 -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 +85 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +103 -0
- package/src/session/prompt/codex.txt +304 -0
- package/src/session/prompt/copilot-gpt-5.txt +138 -0
- package/src/session/prompt/gemini.txt +85 -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 +84 -0
- package/src/session/prompt/qwen.txt +106 -0
- package/src/session/prompt.ts +1509 -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 +194 -0
- package/src/session/system.ts +120 -0
- package/src/session/todo.ts +37 -0
- package/src/share/share-next.ts +194 -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 +317 -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 +168 -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 +180 -0
- package/src/tool/websearch.txt +11 -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 +325 -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/github-remote.test.ts +80 -0
- package/test/config/agent-color.test.ts +66 -0
- package/test/config/config.test.ts +535 -0
- package/test/config/markdown.test.ts +89 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/fixture/fixture.ts +36 -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/patch/patch.test.ts +348 -0
- package/test/preload.ts +57 -0
- package/test/project/project.test.ts +72 -0
- package/test/provider/provider.test.ts +1809 -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 +939 -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/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +55 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test"
|
|
2
|
+
import z from "zod"
|
|
3
|
+
import { Agent } from "../agent/agent"
|
|
4
|
+
|
|
5
|
+
describe("Agent.Info schema", () => {
|
|
6
|
+
test("agent info schema has required fields", () => {
|
|
7
|
+
const shape = Agent.Info.shape
|
|
8
|
+
|
|
9
|
+
// Required fields
|
|
10
|
+
expect(shape.name).toBeDefined()
|
|
11
|
+
expect(shape.mode).toBeDefined()
|
|
12
|
+
expect(shape.permission).toBeDefined()
|
|
13
|
+
expect(shape.tools).toBeDefined()
|
|
14
|
+
expect(shape.options).toBeDefined()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test("agent mode enum has correct values", () => {
|
|
18
|
+
// Test that valid modes are accepted
|
|
19
|
+
const validModes = ["subagent", "primary", "all"]
|
|
20
|
+
|
|
21
|
+
for (const mode of validModes) {
|
|
22
|
+
const testAgent = {
|
|
23
|
+
name: "test",
|
|
24
|
+
mode,
|
|
25
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
26
|
+
tools: {},
|
|
27
|
+
options: {},
|
|
28
|
+
}
|
|
29
|
+
const result = Agent.Info.safeParse(testAgent)
|
|
30
|
+
expect(result.success).toBe(true)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Test that invalid mode is rejected
|
|
34
|
+
const invalidAgent = {
|
|
35
|
+
name: "test",
|
|
36
|
+
mode: "invalid",
|
|
37
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
38
|
+
tools: {},
|
|
39
|
+
options: {},
|
|
40
|
+
}
|
|
41
|
+
const result = Agent.Info.safeParse(invalidAgent)
|
|
42
|
+
expect(result.success).toBe(false)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test("agent permission structure is valid", () => {
|
|
46
|
+
const permissionSchema = Agent.Info.shape.permission
|
|
47
|
+
const permissionShape = (permissionSchema as z.ZodObject<any>).shape
|
|
48
|
+
|
|
49
|
+
expect(permissionShape.edit).toBeDefined()
|
|
50
|
+
expect(permissionShape.bash).toBeDefined()
|
|
51
|
+
expect(permissionShape.skill).toBeDefined()
|
|
52
|
+
expect(permissionShape.webfetch).toBeDefined()
|
|
53
|
+
expect(permissionShape.doom_loop).toBeDefined()
|
|
54
|
+
expect(permissionShape.external_directory).toBeDefined()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test("agent info validates correctly for valid data", () => {
|
|
58
|
+
const validAgent: z.input<typeof Agent.Info> = {
|
|
59
|
+
name: "test-agent",
|
|
60
|
+
mode: "primary",
|
|
61
|
+
permission: {
|
|
62
|
+
edit: "allow",
|
|
63
|
+
bash: { "*": "allow" },
|
|
64
|
+
skill: { "*": "allow" },
|
|
65
|
+
},
|
|
66
|
+
tools: {},
|
|
67
|
+
options: {},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const result = Agent.Info.safeParse(validAgent)
|
|
71
|
+
expect(result.success).toBe(true)
|
|
72
|
+
if (result.success) {
|
|
73
|
+
expect(result.data.name).toBe("test-agent")
|
|
74
|
+
expect(result.data.mode).toBe("primary")
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test("agent info rejects invalid mode", () => {
|
|
79
|
+
const invalidAgent = {
|
|
80
|
+
name: "test-agent",
|
|
81
|
+
mode: "invalid-mode",
|
|
82
|
+
permission: {
|
|
83
|
+
edit: "allow",
|
|
84
|
+
bash: { "*": "allow" },
|
|
85
|
+
skill: { "*": "allow" },
|
|
86
|
+
},
|
|
87
|
+
tools: {},
|
|
88
|
+
options: {},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const result = Agent.Info.safeParse(invalidAgent)
|
|
92
|
+
expect(result.success).toBe(false)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test("optional fields are optional", () => {
|
|
96
|
+
const minimalAgent: z.input<typeof Agent.Info> = {
|
|
97
|
+
name: "minimal",
|
|
98
|
+
mode: "subagent",
|
|
99
|
+
permission: {
|
|
100
|
+
edit: "deny",
|
|
101
|
+
bash: { "*": "deny" },
|
|
102
|
+
skill: { "*": "deny" },
|
|
103
|
+
},
|
|
104
|
+
tools: {},
|
|
105
|
+
options: {},
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = Agent.Info.safeParse(minimalAgent)
|
|
109
|
+
expect(result.success).toBe(true)
|
|
110
|
+
if (result.success) {
|
|
111
|
+
expect(result.data.description).toBeUndefined()
|
|
112
|
+
expect(result.data.native).toBeUndefined()
|
|
113
|
+
expect(result.data.hidden).toBeUndefined()
|
|
114
|
+
expect(result.data.default).toBeUndefined()
|
|
115
|
+
expect(result.data.topP).toBeUndefined()
|
|
116
|
+
expect(result.data.temperature).toBeUndefined()
|
|
117
|
+
expect(result.data.color).toBeUndefined()
|
|
118
|
+
expect(result.data.model).toBeUndefined()
|
|
119
|
+
expect(result.data.prompt).toBeUndefined()
|
|
120
|
+
expect(result.data.maxSteps).toBeUndefined()
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test("agent with all optional fields validates", () => {
|
|
125
|
+
const fullAgent: z.input<typeof Agent.Info> = {
|
|
126
|
+
name: "full-agent",
|
|
127
|
+
description: "A test agent",
|
|
128
|
+
mode: "all",
|
|
129
|
+
native: true,
|
|
130
|
+
hidden: false,
|
|
131
|
+
default: true,
|
|
132
|
+
topP: 0.9,
|
|
133
|
+
temperature: 0.7,
|
|
134
|
+
color: "#FF5733",
|
|
135
|
+
permission: {
|
|
136
|
+
edit: "ask",
|
|
137
|
+
bash: { "*": "ask", "echo *": "allow" },
|
|
138
|
+
skill: { "*": "allow" },
|
|
139
|
+
webfetch: "allow",
|
|
140
|
+
doom_loop: "ask",
|
|
141
|
+
external_directory: "deny",
|
|
142
|
+
},
|
|
143
|
+
model: {
|
|
144
|
+
modelID: "claude-3-opus",
|
|
145
|
+
providerID: "anthropic",
|
|
146
|
+
},
|
|
147
|
+
prompt: "You are a helpful assistant",
|
|
148
|
+
tools: { bash: true, read: true },
|
|
149
|
+
options: { customOption: "value" },
|
|
150
|
+
maxSteps: 100,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const result = Agent.Info.safeParse(fullAgent)
|
|
154
|
+
expect(result.success).toBe(true)
|
|
155
|
+
if (result.success) {
|
|
156
|
+
expect(result.data.description).toBe("A test agent")
|
|
157
|
+
expect(result.data.temperature).toBe(0.7)
|
|
158
|
+
expect(result.data.topP).toBe(0.9)
|
|
159
|
+
expect(result.data.maxSteps).toBe(100)
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test("permission values are valid enum values", () => {
|
|
164
|
+
const validPermissions = ["ask", "allow", "deny"]
|
|
165
|
+
|
|
166
|
+
const testAgent: z.input<typeof Agent.Info> = {
|
|
167
|
+
name: "perm-test",
|
|
168
|
+
mode: "primary",
|
|
169
|
+
permission: {
|
|
170
|
+
edit: "ask",
|
|
171
|
+
bash: { "*": "allow" },
|
|
172
|
+
skill: { "*": "deny" },
|
|
173
|
+
webfetch: "allow",
|
|
174
|
+
doom_loop: "ask",
|
|
175
|
+
external_directory: "deny",
|
|
176
|
+
},
|
|
177
|
+
tools: {},
|
|
178
|
+
options: {},
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const result = Agent.Info.safeParse(testAgent)
|
|
182
|
+
expect(result.success).toBe(true)
|
|
183
|
+
if (result.success) {
|
|
184
|
+
expect(validPermissions).toContain(result.data.permission.edit)
|
|
185
|
+
expect(validPermissions).toContain(result.data.permission.webfetch as string)
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test("maxSteps must be positive integer", () => {
|
|
190
|
+
const negativeSteps = {
|
|
191
|
+
name: "test",
|
|
192
|
+
mode: "primary",
|
|
193
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
194
|
+
tools: {},
|
|
195
|
+
options: {},
|
|
196
|
+
maxSteps: -1,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const result = Agent.Info.safeParse(negativeSteps)
|
|
200
|
+
expect(result.success).toBe(false)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test("temperature can be decimal number", () => {
|
|
204
|
+
const agent: z.input<typeof Agent.Info> = {
|
|
205
|
+
name: "temp-test",
|
|
206
|
+
mode: "primary",
|
|
207
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
208
|
+
tools: {},
|
|
209
|
+
options: {},
|
|
210
|
+
temperature: 0.5,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const result = Agent.Info.safeParse(agent)
|
|
214
|
+
expect(result.success).toBe(true)
|
|
215
|
+
if (result.success) {
|
|
216
|
+
expect(result.data.temperature).toBe(0.5)
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
describe("Agent mode definitions", () => {
|
|
222
|
+
test("subagent mode is valid", () => {
|
|
223
|
+
const agent: z.input<typeof Agent.Info> = {
|
|
224
|
+
name: "subagent-test",
|
|
225
|
+
mode: "subagent",
|
|
226
|
+
permission: { edit: "deny", bash: { "*": "deny" }, skill: { "*": "deny" } },
|
|
227
|
+
tools: {},
|
|
228
|
+
options: {},
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const result = Agent.Info.safeParse(agent)
|
|
232
|
+
expect(result.success).toBe(true)
|
|
233
|
+
if (result.success) {
|
|
234
|
+
expect(result.data.mode).toBe("subagent")
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
test("primary mode is valid", () => {
|
|
239
|
+
const agent: z.input<typeof Agent.Info> = {
|
|
240
|
+
name: "primary-test",
|
|
241
|
+
mode: "primary",
|
|
242
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
243
|
+
tools: {},
|
|
244
|
+
options: {},
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const result = Agent.Info.safeParse(agent)
|
|
248
|
+
expect(result.success).toBe(true)
|
|
249
|
+
if (result.success) {
|
|
250
|
+
expect(result.data.mode).toBe("primary")
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test("all mode is valid", () => {
|
|
255
|
+
const agent: z.input<typeof Agent.Info> = {
|
|
256
|
+
name: "all-test",
|
|
257
|
+
mode: "all",
|
|
258
|
+
permission: { edit: "ask", bash: { "*": "ask" }, skill: { "*": "ask" } },
|
|
259
|
+
tools: {},
|
|
260
|
+
options: {},
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const result = Agent.Info.safeParse(agent)
|
|
264
|
+
expect(result.success).toBe(true)
|
|
265
|
+
if (result.success) {
|
|
266
|
+
expect(result.data.mode).toBe("all")
|
|
267
|
+
}
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe("Agent model configuration", () => {
|
|
272
|
+
test("model requires both modelID and providerID", () => {
|
|
273
|
+
const agentWithModel: z.input<typeof Agent.Info> = {
|
|
274
|
+
name: "model-test",
|
|
275
|
+
mode: "primary",
|
|
276
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
277
|
+
tools: {},
|
|
278
|
+
options: {},
|
|
279
|
+
model: {
|
|
280
|
+
modelID: "gpt-4",
|
|
281
|
+
providerID: "openai",
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const result = Agent.Info.safeParse(agentWithModel)
|
|
286
|
+
expect(result.success).toBe(true)
|
|
287
|
+
if (result.success) {
|
|
288
|
+
expect(result.data.model?.modelID).toBe("gpt-4")
|
|
289
|
+
expect(result.data.model?.providerID).toBe("openai")
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
test("model with missing providerID fails", () => {
|
|
294
|
+
const agentInvalidModel = {
|
|
295
|
+
name: "model-test",
|
|
296
|
+
mode: "primary",
|
|
297
|
+
permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
|
|
298
|
+
tools: {},
|
|
299
|
+
options: {},
|
|
300
|
+
model: {
|
|
301
|
+
modelID: "gpt-4",
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const result = Agent.Info.safeParse(agentInvalidModel)
|
|
306
|
+
expect(result.success).toBe(false)
|
|
307
|
+
})
|
|
308
|
+
})
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 1 Build & Syntax Guards
|
|
3
|
+
*
|
|
4
|
+
* These tests run on every PR to catch build/syntax issues early.
|
|
5
|
+
* They verify:
|
|
6
|
+
* 1. TypeScript compiles without errors (imports resolve)
|
|
7
|
+
* 2. No circular import issues in key modules
|
|
8
|
+
* 3. Agent modes are properly defined
|
|
9
|
+
* 4. Tool definitions have required fields
|
|
10
|
+
* 5. Prompt template files exist and are non-empty
|
|
11
|
+
*
|
|
12
|
+
* Run with: bun test build-guards.test.ts
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect, test } from "bun:test"
|
|
16
|
+
import * as fs from "fs"
|
|
17
|
+
import * as path from "path"
|
|
18
|
+
|
|
19
|
+
// ------------------------------------------------------------------
|
|
20
|
+
// 1. TypeScript Compilation - Verify key imports resolve
|
|
21
|
+
// ------------------------------------------------------------------
|
|
22
|
+
describe("TypeScript Compilation", () => {
|
|
23
|
+
it("should import Tool namespace without errors", async () => {
|
|
24
|
+
const { Tool } = await import("../tool/tool")
|
|
25
|
+
expect(Tool).toBeDefined()
|
|
26
|
+
expect(Tool.define).toBeInstanceOf(Function)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it("should import Agent namespace without errors", async () => {
|
|
30
|
+
const { Agent } = await import("../agent/agent")
|
|
31
|
+
expect(Agent).toBeDefined()
|
|
32
|
+
expect(Agent.Info).toBeDefined()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("should import ToolRegistry without errors", async () => {
|
|
36
|
+
const { ToolRegistry } = await import("../tool/registry")
|
|
37
|
+
expect(ToolRegistry).toBeDefined()
|
|
38
|
+
expect(ToolRegistry.register).toBeInstanceOf(Function)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it("should import Config namespace without errors", async () => {
|
|
42
|
+
const { Config } = await import("../config/config")
|
|
43
|
+
expect(Config).toBeDefined()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it("should import Provider namespace without errors", async () => {
|
|
47
|
+
const { Provider } = await import("../provider/provider")
|
|
48
|
+
expect(Provider).toBeDefined()
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// ------------------------------------------------------------------
|
|
53
|
+
// 2. Circular Import Detection - Import key modules together
|
|
54
|
+
// ------------------------------------------------------------------
|
|
55
|
+
describe("Circular Import Detection", () => {
|
|
56
|
+
it("should import tool and agent modules without circular dependency errors", async () => {
|
|
57
|
+
// Import order matters for circular deps - test common patterns
|
|
58
|
+
const [toolModule, agentModule] = await Promise.all([
|
|
59
|
+
import("../tool/tool"),
|
|
60
|
+
import("../agent/agent"),
|
|
61
|
+
])
|
|
62
|
+
expect(toolModule.Tool).toBeDefined()
|
|
63
|
+
expect(agentModule.Agent).toBeDefined()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it("should import registry with all tools without circular dependency errors", async () => {
|
|
67
|
+
const { ToolRegistry } = await import("../tool/registry")
|
|
68
|
+
const { BashTool } = await import("../tool/bash")
|
|
69
|
+
const { ReadTool } = await import("../tool/read")
|
|
70
|
+
const { EditTool } = await import("../tool/edit")
|
|
71
|
+
const { WriteTool } = await import("../tool/write")
|
|
72
|
+
const { GlobTool } = await import("../tool/glob")
|
|
73
|
+
const { GrepTool } = await import("../tool/grep")
|
|
74
|
+
|
|
75
|
+
expect(ToolRegistry).toBeDefined()
|
|
76
|
+
expect(BashTool).toBeDefined()
|
|
77
|
+
expect(ReadTool).toBeDefined()
|
|
78
|
+
expect(EditTool).toBeDefined()
|
|
79
|
+
expect(WriteTool).toBeDefined()
|
|
80
|
+
expect(GlobTool).toBeDefined()
|
|
81
|
+
expect(GrepTool).toBeDefined()
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it("should import session and provider modules together", async () => {
|
|
85
|
+
const [sessionModule, providerModule] = await Promise.all([
|
|
86
|
+
import("../session"),
|
|
87
|
+
import("../provider/provider"),
|
|
88
|
+
])
|
|
89
|
+
expect(sessionModule.Session).toBeDefined()
|
|
90
|
+
expect(providerModule.Provider).toBeDefined()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// ------------------------------------------------------------------
|
|
95
|
+
// 3. Agent Mode Validation
|
|
96
|
+
// ------------------------------------------------------------------
|
|
97
|
+
describe("Agent Mode Validation", () => {
|
|
98
|
+
it("should have valid mode enum values in Agent.Info schema", async () => {
|
|
99
|
+
const { Agent } = await import("../agent/agent")
|
|
100
|
+
const validModes = ["subagent", "primary", "all"] as const
|
|
101
|
+
|
|
102
|
+
// The Info schema should have mode as an enum
|
|
103
|
+
const modeField = Agent.Info.shape.mode
|
|
104
|
+
expect(modeField).toBeDefined()
|
|
105
|
+
|
|
106
|
+
// Get the enum values from the zod schema
|
|
107
|
+
const enumValues = modeField.options
|
|
108
|
+
expect(enumValues).toBeDefined()
|
|
109
|
+
expect(Array.from(enumValues).sort()).toEqual([...validModes].sort())
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it("should have required permission fields in Agent.Info schema", async () => {
|
|
113
|
+
const { Agent } = await import("../agent/agent")
|
|
114
|
+
|
|
115
|
+
const permissionShape = Agent.Info.shape.permission.shape
|
|
116
|
+
expect(permissionShape).toBeDefined()
|
|
117
|
+
expect(permissionShape.edit).toBeDefined()
|
|
118
|
+
expect(permissionShape.bash).toBeDefined()
|
|
119
|
+
expect(permissionShape.skill).toBeDefined()
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// ------------------------------------------------------------------
|
|
124
|
+
// 4. Tool Definition Validation
|
|
125
|
+
// ------------------------------------------------------------------
|
|
126
|
+
describe("Tool Definition Validation", () => {
|
|
127
|
+
const toolFiles = [
|
|
128
|
+
"bash",
|
|
129
|
+
"read",
|
|
130
|
+
"edit",
|
|
131
|
+
"write",
|
|
132
|
+
"glob",
|
|
133
|
+
"grep",
|
|
134
|
+
"task",
|
|
135
|
+
"webfetch",
|
|
136
|
+
"websearch",
|
|
137
|
+
"skill",
|
|
138
|
+
"todo",
|
|
139
|
+
"ls",
|
|
140
|
+
"lsp",
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
for (const toolName of toolFiles) {
|
|
144
|
+
it(`should have valid Tool.define structure for ${toolName}`, async () => {
|
|
145
|
+
try {
|
|
146
|
+
const toolModule = await import(`../tool/${toolName}`)
|
|
147
|
+
|
|
148
|
+
// Find the exported tool (naming convention: XxxTool)
|
|
149
|
+
const toolExport = Object.values(toolModule).find(
|
|
150
|
+
(exp: any) => exp && typeof exp === "object" && "id" in exp && "init" in exp
|
|
151
|
+
) as any
|
|
152
|
+
|
|
153
|
+
if (toolExport) {
|
|
154
|
+
expect(toolExport.id).toBeDefined()
|
|
155
|
+
expect(typeof toolExport.id).toBe("string")
|
|
156
|
+
expect(toolExport.init).toBeInstanceOf(Function)
|
|
157
|
+
}
|
|
158
|
+
} catch (err: any) {
|
|
159
|
+
// Some tools may have optional dependencies - that's ok for build check
|
|
160
|
+
if (!err.message.includes("Cannot find module")) {
|
|
161
|
+
throw err
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
it("should have id and init for all core tools", async () => {
|
|
168
|
+
const { BashTool } = await import("../tool/bash")
|
|
169
|
+
const { ReadTool } = await import("../tool/read")
|
|
170
|
+
const { EditTool } = await import("../tool/edit")
|
|
171
|
+
const { WriteTool } = await import("../tool/write")
|
|
172
|
+
|
|
173
|
+
const tools = [BashTool, ReadTool, EditTool, WriteTool]
|
|
174
|
+
|
|
175
|
+
for (const tool of tools) {
|
|
176
|
+
expect(tool.id).toBeDefined()
|
|
177
|
+
expect(typeof tool.id).toBe("string")
|
|
178
|
+
expect(tool.id.length).toBeGreaterThan(0)
|
|
179
|
+
expect(tool.init).toBeInstanceOf(Function)
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// ------------------------------------------------------------------
|
|
185
|
+
// 5. Prompt Template File Validation
|
|
186
|
+
// ------------------------------------------------------------------
|
|
187
|
+
describe("Prompt Template File Validation", () => {
|
|
188
|
+
const srcDir = path.join(__dirname, "..")
|
|
189
|
+
|
|
190
|
+
const requiredPromptFiles = [
|
|
191
|
+
// Agent prompts
|
|
192
|
+
"agent/generate.txt",
|
|
193
|
+
"agent/prompt/compaction.txt",
|
|
194
|
+
"agent/prompt/summary.txt",
|
|
195
|
+
"agent/prompt/title.txt",
|
|
196
|
+
// Tool prompts (description files)
|
|
197
|
+
"tool/bash.txt",
|
|
198
|
+
"tool/read.txt",
|
|
199
|
+
"tool/edit.txt",
|
|
200
|
+
"tool/write.txt",
|
|
201
|
+
"tool/glob.txt",
|
|
202
|
+
"tool/grep.txt",
|
|
203
|
+
"tool/task.txt",
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
for (const file of requiredPromptFiles) {
|
|
207
|
+
it(`should have non-empty prompt file: ${file}`, () => {
|
|
208
|
+
const filePath = path.join(srcDir, file)
|
|
209
|
+
expect(fs.existsSync(filePath)).toBe(true)
|
|
210
|
+
|
|
211
|
+
const content = fs.readFileSync(filePath, "utf-8")
|
|
212
|
+
expect(content.length).toBeGreaterThan(0)
|
|
213
|
+
expect(content.trim().length).toBeGreaterThan(0)
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
// ------------------------------------------------------------------
|
|
219
|
+
// 6. Config Schema Validation
|
|
220
|
+
// ------------------------------------------------------------------
|
|
221
|
+
describe("Config Schema Validation", () => {
|
|
222
|
+
it("should have valid Permission enum values", async () => {
|
|
223
|
+
const { Config } = await import("../config/config")
|
|
224
|
+
|
|
225
|
+
// Permission should be a zod enum
|
|
226
|
+
expect(Config.Permission).toBeDefined()
|
|
227
|
+
const permissionValues = Config.Permission.options
|
|
228
|
+
expect(permissionValues).toContain("allow")
|
|
229
|
+
expect(permissionValues).toContain("deny")
|
|
230
|
+
expect(permissionValues).toContain("ask")
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it("should export core config functions", async () => {
|
|
234
|
+
const { Config } = await import("../config/config")
|
|
235
|
+
|
|
236
|
+
expect(Config.get).toBeInstanceOf(Function)
|
|
237
|
+
expect(Config.directories).toBeInstanceOf(Function)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
// ------------------------------------------------------------------
|
|
242
|
+
// 7. Export Structure Validation
|
|
243
|
+
// ------------------------------------------------------------------
|
|
244
|
+
describe("Export Structure Validation", () => {
|
|
245
|
+
it("should have Log utility with required methods", async () => {
|
|
246
|
+
const { Log } = await import("../util/log")
|
|
247
|
+
|
|
248
|
+
expect(Log).toBeDefined()
|
|
249
|
+
expect(Log.create).toBeInstanceOf(Function)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it("should have Instance with required properties", async () => {
|
|
253
|
+
const { Instance } = await import("../project/instance")
|
|
254
|
+
|
|
255
|
+
expect(Instance).toBeDefined()
|
|
256
|
+
expect(Instance.state).toBeInstanceOf(Function)
|
|
257
|
+
expect(Instance.provide).toBeInstanceOf(Function)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
it("should have Permission namespace with required exports", async () => {
|
|
261
|
+
const { Permission } = await import("../permission")
|
|
262
|
+
|
|
263
|
+
expect(Permission).toBeDefined()
|
|
264
|
+
expect(Permission.ask).toBeInstanceOf(Function)
|
|
265
|
+
expect(Permission.RejectedError).toBeDefined()
|
|
266
|
+
})
|
|
267
|
+
})
|