@bloxystudios/bloxycode 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/LICENSE +21 -0
- package/README.md +256 -0
- package/bin/bloxycode +84 -0
- package/package.json +133 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1437 -0
- package/src/acp/session.ts +105 -0
- package/src/acp/types.ts +22 -0
- package/src/agent/agent.ts +356 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/bloxy.txt +46 -0
- package/src/agent/prompt/compaction.txt +12 -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 +73 -0
- package/src/bloxy/event.ts +41 -0
- package/src/bloxy/index.ts +5 -0
- package/src/bloxy/parser.ts +263 -0
- package/src/bloxy/prompt.ts +121 -0
- package/src/bloxy/runner.ts +193 -0
- package/src/bloxy/state.ts +246 -0
- package/src/bun/index.ts +134 -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 +69 -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 +1548 -0
- package/src/cli/cmd/import.ts +98 -0
- package/src/cli/cmd/mcp.ts +755 -0
- package/src/cli/cmd/models.ts +77 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +395 -0
- package/src/cli/cmd/serve.ts +20 -0
- package/src/cli/cmd/session.ts +135 -0
- package/src/cli/cmd/stats.ts +402 -0
- package/src/cli/cmd/tui/app.tsx +771 -0
- package/src/cli/cmd/tui/attach.ts +39 -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 +234 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +256 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +114 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +164 -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 +102 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +653 -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 +1138 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -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 +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 +52 -0
- package/src/cli/cmd/tui/context/local.tsx +402 -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 +94 -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/bloxycode.json +245 -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/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 +1152 -0
- package/src/cli/cmd/tui/event.ts +48 -0
- package/src/cli/cmd/tui/routes/home.tsx +140 -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 +142 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +2048 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +508 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +453 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
- package/src/cli/cmd/tui/thread.ts +165 -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-export-options.tsx +204 -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 +385 -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 +160 -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/worker.ts +152 -0
- package/src/cli/cmd/uninstall.ts +357 -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/network.ts +53 -0
- package/src/cli/ui.ts +86 -0
- package/src/cli/upgrade.ts +25 -0
- package/src/command/index.ts +173 -0
- package/src/command/template/bloxy-resume.txt +15 -0
- package/src/command/template/bloxy-status.txt +25 -0
- package/src/command/template/bloxy-validate.txt +22 -0
- package/src/command/template/bloxy.txt +14 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +99 -0
- package/src/config/config.ts +1367 -0
- package/src/config/markdown.ts +93 -0
- package/src/env/index.ts +26 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +415 -0
- package/src/file/ripgrep.ts +407 -0
- package/src/file/time.ts +69 -0
- package/src/file/watcher.ts +127 -0
- package/src/flag/flag.ts +79 -0
- package/src/format/formatter.ts +357 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +55 -0
- package/src/id/id.ts +83 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +159 -0
- package/src/installation/index.ts +246 -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 +135 -0
- package/src/mcp/index.ts +934 -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/antigravity.ts +378 -0
- package/src/plugin/codex.ts +506 -0
- package/src/plugin/copilot.ts +298 -0
- package/src/plugin/index.ts +136 -0
- package/src/project/bootstrap.ts +35 -0
- package/src/project/instance.ts +91 -0
- package/src/project/project.ts +371 -0
- package/src/project/state.ts +66 -0
- package/src/project/vcs.ts +76 -0
- package/src/provider/auth.ts +147 -0
- package/src/provider/models-snapshot.ts +2 -0
- package/src/provider/models.ts +133 -0
- package/src/provider/provider.ts +1241 -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 +1732 -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 +741 -0
- package/src/pty/index.ts +241 -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 +59 -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 +135 -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 +165 -0
- package/src/server/routes/pty.ts +169 -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 +604 -0
- package/src/session/compaction.ts +225 -0
- package/src/session/fallback.ts +246 -0
- package/src/session/index.ts +498 -0
- package/src/session/instruction.ts +164 -0
- package/src/session/llm.ts +298 -0
- package/src/session/message-v2.ts +747 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +450 -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.ts +1822 -0
- package/src/session/retry.ts +99 -0
- package/src/session/revert.ts +121 -0
- package/src/session/status.ts +100 -0
- package/src/session/summary.ts +217 -0
- package/src/session/system.ts +52 -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/index.ts +1 -0
- package/src/skill/skill.ts +135 -0
- package/src/snapshot/index.ts +236 -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 +258 -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/bloxy-control.ts +123 -0
- package/src/tool/bloxy-control.txt +13 -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 +77 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +154 -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 +211 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +161 -0
- package/src/tool/skill.ts +82 -0
- package/src/tool/task.ts +191 -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 +188 -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/archive.ts +16 -0
- package/src/util/binary.ts +41 -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/error.ts +54 -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 +23 -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 +66 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/slug.ts +74 -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 +549 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
You are a title generator. You output ONLY a thread title. Nothing else.
|
|
2
|
+
|
|
3
|
+
<task>
|
|
4
|
+
Generate a brief title that would help the user find this conversation later.
|
|
5
|
+
|
|
6
|
+
Follow all rules in <rules>
|
|
7
|
+
Use the <examples> so you know what a good title looks like.
|
|
8
|
+
Your output must be:
|
|
9
|
+
- A single line
|
|
10
|
+
- ≤50 characters
|
|
11
|
+
- No explanations
|
|
12
|
+
</task>
|
|
13
|
+
|
|
14
|
+
<rules>
|
|
15
|
+
- you MUST use the same language as the user message you are summarizing
|
|
16
|
+
- Title must be grammatically correct and read naturally - no word salad
|
|
17
|
+
- Never include tool names in the title (e.g. "read tool", "bash tool", "edit tool")
|
|
18
|
+
- Focus on the main topic or question the user needs to retrieve
|
|
19
|
+
- Vary your phrasing - avoid repetitive patterns like always starting with "Analyzing"
|
|
20
|
+
- When a file is mentioned, focus on WHAT the user wants to do WITH the file, not just that they shared it
|
|
21
|
+
- Keep exact: technical terms, numbers, filenames, HTTP codes
|
|
22
|
+
- Remove: the, this, my, a, an
|
|
23
|
+
- Never assume tech stack
|
|
24
|
+
- Never use tools
|
|
25
|
+
- NEVER respond to questions, just generate a title for the conversation
|
|
26
|
+
- The title should NEVER include "summarizing" or "generating" when generating a title
|
|
27
|
+
- DO NOT SAY YOU CANNOT GENERATE A TITLE OR COMPLAIN ABOUT THE INPUT
|
|
28
|
+
- Always output something meaningful, even if the input is minimal.
|
|
29
|
+
- If the user message is short or conversational (e.g. "hello", "lol", "what's up", "hey"):
|
|
30
|
+
→ create a title that reflects the user's tone or intent (such as Greeting, Quick check-in, Light chat, Intro message, etc.)
|
|
31
|
+
</rules>
|
|
32
|
+
|
|
33
|
+
<examples>
|
|
34
|
+
"debug 500 errors in production" → Debugging production 500 errors
|
|
35
|
+
"refactor user service" → Refactoring user service
|
|
36
|
+
"why is app.js failing" → app.js failure investigation
|
|
37
|
+
"implement rate limiting" → Rate limiting implementation
|
|
38
|
+
"how do I connect postgres to my API" → Postgres API connection
|
|
39
|
+
"best practices for React hooks" → React hooks best practices
|
|
40
|
+
"@src/auth.ts can you add refresh token support" → Auth refresh token support
|
|
41
|
+
"@utils/parser.ts this is broken" → Parser bug fix
|
|
42
|
+
"look at @config.json" → Config review
|
|
43
|
+
"@App.tsx add dark mode toggle" → Dark mode toggle in App
|
|
44
|
+
</examples>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
import { Global } from "../global"
|
|
3
|
+
import fs from "fs/promises"
|
|
4
|
+
import z from "zod"
|
|
5
|
+
|
|
6
|
+
export const OAUTH_DUMMY_KEY = "opencode-oauth-dummy-key"
|
|
7
|
+
|
|
8
|
+
export namespace Auth {
|
|
9
|
+
export const Oauth = z
|
|
10
|
+
.object({
|
|
11
|
+
type: z.literal("oauth"),
|
|
12
|
+
refresh: z.string(),
|
|
13
|
+
access: z.string(),
|
|
14
|
+
expires: z.number(),
|
|
15
|
+
accountId: z.string().optional(),
|
|
16
|
+
enterpriseUrl: z.string().optional(),
|
|
17
|
+
})
|
|
18
|
+
.meta({ ref: "OAuth" })
|
|
19
|
+
|
|
20
|
+
export const Api = z
|
|
21
|
+
.object({
|
|
22
|
+
type: z.literal("api"),
|
|
23
|
+
key: z.string(),
|
|
24
|
+
})
|
|
25
|
+
.meta({ ref: "ApiAuth" })
|
|
26
|
+
|
|
27
|
+
export const WellKnown = z
|
|
28
|
+
.object({
|
|
29
|
+
type: z.literal("wellknown"),
|
|
30
|
+
key: z.string(),
|
|
31
|
+
token: z.string(),
|
|
32
|
+
})
|
|
33
|
+
.meta({ ref: "WellKnownAuth" })
|
|
34
|
+
|
|
35
|
+
export const Info = z.discriminatedUnion("type", [Oauth, Api, WellKnown]).meta({ ref: "Auth" })
|
|
36
|
+
export type Info = z.infer<typeof Info>
|
|
37
|
+
|
|
38
|
+
const filepath = path.join(Global.Path.data, "auth.json")
|
|
39
|
+
|
|
40
|
+
export async function get(providerID: string) {
|
|
41
|
+
const auth = await all()
|
|
42
|
+
return auth[providerID]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function all(): Promise<Record<string, Info>> {
|
|
46
|
+
const file = Bun.file(filepath)
|
|
47
|
+
const data = await file.json().catch(() => ({}) as Record<string, unknown>)
|
|
48
|
+
return Object.entries(data).reduce(
|
|
49
|
+
(acc, [key, value]) => {
|
|
50
|
+
const parsed = Info.safeParse(value)
|
|
51
|
+
if (!parsed.success) return acc
|
|
52
|
+
acc[key] = parsed.data
|
|
53
|
+
return acc
|
|
54
|
+
},
|
|
55
|
+
{} as Record<string, Info>,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function set(key: string, info: Info) {
|
|
60
|
+
const file = Bun.file(filepath)
|
|
61
|
+
const data = await all()
|
|
62
|
+
await Bun.write(file, JSON.stringify({ ...data, [key]: info }, null, 2))
|
|
63
|
+
await fs.chmod(file.name!, 0o600)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function remove(key: string) {
|
|
67
|
+
const file = Bun.file(filepath)
|
|
68
|
+
const data = await all()
|
|
69
|
+
delete data[key]
|
|
70
|
+
await Bun.write(file, JSON.stringify(data, null, 2))
|
|
71
|
+
await fs.chmod(file.name!, 0o600)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import z from "zod"
|
|
2
|
+
import { BusEvent } from "../bus/bus-event"
|
|
3
|
+
|
|
4
|
+
export namespace BloxyEvent {
|
|
5
|
+
export const TaskComplete = BusEvent.define(
|
|
6
|
+
"bloxy.task.complete",
|
|
7
|
+
z.object({
|
|
8
|
+
sessionID: z.string(),
|
|
9
|
+
taskId: z.string(),
|
|
10
|
+
summary: z.string().optional(),
|
|
11
|
+
})
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
export const TaskFailed = BusEvent.define(
|
|
15
|
+
"bloxy.task.failed",
|
|
16
|
+
z.object({
|
|
17
|
+
sessionID: z.string(),
|
|
18
|
+
taskId: z.string(),
|
|
19
|
+
error: z.string().optional(),
|
|
20
|
+
})
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export const SessionStart = BusEvent.define(
|
|
24
|
+
"bloxy.session.start",
|
|
25
|
+
z.object({
|
|
26
|
+
sessionID: z.string(),
|
|
27
|
+
prdPath: z.string(),
|
|
28
|
+
taskCount: z.number(),
|
|
29
|
+
})
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
export const SessionComplete = BusEvent.define(
|
|
33
|
+
"bloxy.session.complete",
|
|
34
|
+
z.object({
|
|
35
|
+
sessionID: z.string(),
|
|
36
|
+
completed: z.number(),
|
|
37
|
+
failed: z.number(),
|
|
38
|
+
total: z.number(),
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import fs from "fs/promises"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { BloxyState } from "./state"
|
|
4
|
+
import { Log } from "../util/log"
|
|
5
|
+
|
|
6
|
+
export namespace BloxyParser {
|
|
7
|
+
const log = Log.create({ service: "bloxy.parser" })
|
|
8
|
+
|
|
9
|
+
export interface ParseOptions {
|
|
10
|
+
worktree: string
|
|
11
|
+
prdPath: string
|
|
12
|
+
config?: Partial<BloxyState.Config>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ParseResult {
|
|
16
|
+
tasks: BloxyState.Task[]
|
|
17
|
+
config: BloxyState.Config
|
|
18
|
+
prdPath: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parse a PRD file and extract tasks
|
|
23
|
+
* Supports markdown with checkbox format: `- [ ] task title`
|
|
24
|
+
*/
|
|
25
|
+
export async function parse(options: ParseOptions): Promise<ParseResult> {
|
|
26
|
+
const filepath = path.isAbsolute(options.prdPath)
|
|
27
|
+
? options.prdPath
|
|
28
|
+
: path.join(options.worktree, options.prdPath)
|
|
29
|
+
|
|
30
|
+
const content = await fs.readFile(filepath, "utf-8")
|
|
31
|
+
const ext = path.extname(filepath).toLowerCase()
|
|
32
|
+
|
|
33
|
+
let tasks: BloxyState.Task[]
|
|
34
|
+
|
|
35
|
+
if (ext === ".yaml" || ext === ".yml") {
|
|
36
|
+
tasks = parseYaml(content)
|
|
37
|
+
} else if (ext === ".json") {
|
|
38
|
+
tasks = parseJson(content)
|
|
39
|
+
} else {
|
|
40
|
+
// Default to markdown
|
|
41
|
+
tasks = parseMarkdown(content)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
log.info("Parsed PRD", { path: filepath, tasks: tasks.length })
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
tasks,
|
|
48
|
+
config: BloxyState.Config.parse(options.config ?? {}),
|
|
49
|
+
prdPath: filepath,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Parse markdown PRD with checkbox format
|
|
55
|
+
* Supports:
|
|
56
|
+
* - [ ] task title (pending)
|
|
57
|
+
* - [x] completed task (skipped)
|
|
58
|
+
* - [~] deferred task (included but skipped during execution)
|
|
59
|
+
* ## Task: title
|
|
60
|
+
*/
|
|
61
|
+
function parseMarkdown(content: string): BloxyState.Task[] {
|
|
62
|
+
const tasks: BloxyState.Task[] = []
|
|
63
|
+
const lines = content.split("\n")
|
|
64
|
+
|
|
65
|
+
let currentTask: Partial<BloxyState.Task> | null = null
|
|
66
|
+
let bodyLines: string[] = []
|
|
67
|
+
let taskIndex = 0
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < lines.length; i++) {
|
|
70
|
+
const line = lines[i]
|
|
71
|
+
|
|
72
|
+
// Check for checkbox format: - [ ] task, - [x] task, or - [~] task
|
|
73
|
+
const checkboxMatch = line.match(/^[-*]\s*\[([ xX~])\]\s*(.+)$/)
|
|
74
|
+
if (checkboxMatch) {
|
|
75
|
+
// Save previous task
|
|
76
|
+
if (currentTask) {
|
|
77
|
+
currentTask.body = bodyLines.join("\n").trim() || undefined
|
|
78
|
+
tasks.push(BloxyState.Task.parse(currentTask))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const marker = checkboxMatch[1].toLowerCase()
|
|
82
|
+
const title = checkboxMatch[2].trim()
|
|
83
|
+
|
|
84
|
+
if (marker === "x") {
|
|
85
|
+
// Completed task - skip entirely
|
|
86
|
+
currentTask = null
|
|
87
|
+
bodyLines = []
|
|
88
|
+
} else if (marker === "~") {
|
|
89
|
+
// Deferred task - include but mark as deferred
|
|
90
|
+
taskIndex++
|
|
91
|
+
currentTask = {
|
|
92
|
+
id: `task-${taskIndex}`,
|
|
93
|
+
title,
|
|
94
|
+
status: "deferred",
|
|
95
|
+
attempts: 0,
|
|
96
|
+
time: {},
|
|
97
|
+
}
|
|
98
|
+
bodyLines = []
|
|
99
|
+
} else {
|
|
100
|
+
// Pending task
|
|
101
|
+
taskIndex++
|
|
102
|
+
currentTask = {
|
|
103
|
+
id: `task-${taskIndex}`,
|
|
104
|
+
title,
|
|
105
|
+
status: "pending",
|
|
106
|
+
attempts: 0,
|
|
107
|
+
time: {},
|
|
108
|
+
}
|
|
109
|
+
bodyLines = []
|
|
110
|
+
}
|
|
111
|
+
continue
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check for header format: ## Task: title or ### title
|
|
115
|
+
const headerMatch = line.match(/^#{1,3}\s*(?:Task\s*[:.]?\s*)?(.+)$/)
|
|
116
|
+
if (headerMatch && !line.startsWith("####")) {
|
|
117
|
+
// Save previous task
|
|
118
|
+
if (currentTask) {
|
|
119
|
+
currentTask.body = bodyLines.join("\n").trim() || undefined
|
|
120
|
+
tasks.push(BloxyState.Task.parse(currentTask))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check if this header looks like a task (not just a section like "Overview")
|
|
124
|
+
const title = headerMatch[1].trim()
|
|
125
|
+
const skipHeaders = ["overview", "summary", "introduction", "tasks", "context", "requirements", "notes"]
|
|
126
|
+
if (skipHeaders.some(h => title.toLowerCase() === h)) {
|
|
127
|
+
currentTask = null
|
|
128
|
+
bodyLines = []
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
taskIndex++
|
|
133
|
+
currentTask = {
|
|
134
|
+
id: `task-${taskIndex}`,
|
|
135
|
+
title,
|
|
136
|
+
status: "pending",
|
|
137
|
+
attempts: 0,
|
|
138
|
+
time: {},
|
|
139
|
+
}
|
|
140
|
+
bodyLines = []
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Accumulate body content for current task
|
|
145
|
+
if (currentTask) {
|
|
146
|
+
bodyLines.push(line)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Save last task
|
|
151
|
+
if (currentTask) {
|
|
152
|
+
currentTask.body = bodyLines.join("\n").trim() || undefined
|
|
153
|
+
tasks.push(BloxyState.Task.parse(currentTask))
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return tasks
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Parse YAML PRD format
|
|
161
|
+
* Expected format:
|
|
162
|
+
* tasks:
|
|
163
|
+
* - title: "task title"
|
|
164
|
+
* body: "optional description"
|
|
165
|
+
*/
|
|
166
|
+
function parseYaml(content: string): BloxyState.Task[] {
|
|
167
|
+
// Simple YAML parser for task lists
|
|
168
|
+
// For full YAML support, could use a library
|
|
169
|
+
const tasks: BloxyState.Task[] = []
|
|
170
|
+
|
|
171
|
+
// Match tasks array entries
|
|
172
|
+
const taskRegex = /^\s*-\s*title:\s*["']?(.+?)["']?\s*$/gm
|
|
173
|
+
let match
|
|
174
|
+
let index = 0
|
|
175
|
+
|
|
176
|
+
while ((match = taskRegex.exec(content)) !== null) {
|
|
177
|
+
index++
|
|
178
|
+
tasks.push(BloxyState.Task.parse({
|
|
179
|
+
id: `task-${index}`,
|
|
180
|
+
title: match[1].trim(),
|
|
181
|
+
status: "pending",
|
|
182
|
+
attempts: 0,
|
|
183
|
+
time: {},
|
|
184
|
+
}))
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return tasks
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Parse JSON PRD format
|
|
192
|
+
* Expected format:
|
|
193
|
+
* {
|
|
194
|
+
* "tasks": [
|
|
195
|
+
* { "title": "task title", "body": "optional" }
|
|
196
|
+
* ]
|
|
197
|
+
* }
|
|
198
|
+
*/
|
|
199
|
+
function parseJson(content: string): BloxyState.Task[] {
|
|
200
|
+
const data = JSON.parse(content)
|
|
201
|
+
const tasks: BloxyState.Task[] = []
|
|
202
|
+
|
|
203
|
+
if (!data.tasks || !Array.isArray(data.tasks)) {
|
|
204
|
+
throw new Error("JSON PRD must have a 'tasks' array")
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
data.tasks.forEach((item: { title?: string; body?: string; completed?: boolean }, index: number) => {
|
|
208
|
+
if (!item.title) return
|
|
209
|
+
if (item.completed) return // Skip completed tasks
|
|
210
|
+
|
|
211
|
+
tasks.push(BloxyState.Task.parse({
|
|
212
|
+
id: `task-${index + 1}`,
|
|
213
|
+
title: item.title,
|
|
214
|
+
body: item.body,
|
|
215
|
+
status: "pending",
|
|
216
|
+
attempts: 0,
|
|
217
|
+
time: {},
|
|
218
|
+
}))
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
return tasks
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Create a BloxyState.Session from parsed results
|
|
226
|
+
*/
|
|
227
|
+
export function createSession(result: ParseResult): BloxyState.Session {
|
|
228
|
+
return BloxyState.Session.parse({
|
|
229
|
+
tasks: result.tasks,
|
|
230
|
+
currentTaskIndex: 0,
|
|
231
|
+
prdPath: result.prdPath,
|
|
232
|
+
config: result.config,
|
|
233
|
+
status: "idle",
|
|
234
|
+
time: {},
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Update the original PRD file to mark a task as complete
|
|
240
|
+
*/
|
|
241
|
+
export async function markTaskInFile(filepath: string, taskTitle: string): Promise<void> {
|
|
242
|
+
try {
|
|
243
|
+
const content = await fs.readFile(filepath, "utf-8")
|
|
244
|
+
const ext = path.extname(filepath).toLowerCase()
|
|
245
|
+
|
|
246
|
+
if (ext === ".md") {
|
|
247
|
+
// Replace - [ ] with - [x] for the matching task
|
|
248
|
+
const escaped = taskTitle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
249
|
+
const updated = content.replace(
|
|
250
|
+
new RegExp(`^([-*]\\s*)\\[[ ]\\](\\s*${escaped})`, "m"),
|
|
251
|
+
"$1[x]$2"
|
|
252
|
+
)
|
|
253
|
+
if (updated !== content) {
|
|
254
|
+
await fs.writeFile(filepath, updated)
|
|
255
|
+
log.info("Marked task complete in PRD", { task: taskTitle })
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// YAML and JSON don't have built-in completion markers in the same way
|
|
259
|
+
} catch (e) {
|
|
260
|
+
log.error("Failed to update PRD file", { error: e })
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { BloxyState } from "./state"
|
|
2
|
+
|
|
3
|
+
export namespace BloxyPrompt {
|
|
4
|
+
/**
|
|
5
|
+
* Build the task context to inject into the session
|
|
6
|
+
*/
|
|
7
|
+
export function buildTaskContext(session: BloxyState.Session, task: BloxyState.Task): string {
|
|
8
|
+
const completed = BloxyState.countCompleted(session)
|
|
9
|
+
const total = session.tasks.length
|
|
10
|
+
const remaining = BloxyState.countRemaining(session)
|
|
11
|
+
|
|
12
|
+
const parts: string[] = []
|
|
13
|
+
|
|
14
|
+
parts.push("## Bloxy Autonomous Mode Active")
|
|
15
|
+
parts.push("")
|
|
16
|
+
parts.push(`**Progress**: Task ${completed + 1} of ${total} (${remaining} remaining)`)
|
|
17
|
+
parts.push("")
|
|
18
|
+
parts.push("---")
|
|
19
|
+
parts.push("")
|
|
20
|
+
parts.push(`## Current Task: ${task.title}`)
|
|
21
|
+
|
|
22
|
+
if (task.body) {
|
|
23
|
+
parts.push("")
|
|
24
|
+
parts.push(task.body)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
parts.push("")
|
|
28
|
+
parts.push("---")
|
|
29
|
+
parts.push("")
|
|
30
|
+
parts.push("## Instructions")
|
|
31
|
+
parts.push("")
|
|
32
|
+
parts.push("1. **Implement** the task described above completely")
|
|
33
|
+
|
|
34
|
+
let step = 2
|
|
35
|
+
if (session.config.runTests && session.config.testCommand) {
|
|
36
|
+
parts.push(`${step}. **Test** by running: \`${session.config.testCommand}\``)
|
|
37
|
+
step++
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (session.config.lintCommand) {
|
|
41
|
+
parts.push(`${step}. **Lint** by running: \`${session.config.lintCommand}\``)
|
|
42
|
+
step++
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (session.config.autoCommit) {
|
|
46
|
+
parts.push(`${step}. **Commit** your changes with a descriptive message`)
|
|
47
|
+
step++
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
parts.push(`${step}. **Signal completion** using the \`bloxy_control\` tool with action "task_complete"`)
|
|
51
|
+
|
|
52
|
+
parts.push("")
|
|
53
|
+
parts.push("## Important")
|
|
54
|
+
parts.push("")
|
|
55
|
+
parts.push("- Focus ONLY on this task - do not work ahead")
|
|
56
|
+
parts.push("- Keep changes focused and minimal")
|
|
57
|
+
parts.push("- If you encounter an error you cannot resolve, use `bloxy_control` with action \"task_failed\"")
|
|
58
|
+
parts.push("- Do NOT modify the PRD file directly")
|
|
59
|
+
|
|
60
|
+
return parts.join("\n")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build completion summary for the session
|
|
65
|
+
*/
|
|
66
|
+
export function buildCompletionSummary(session: BloxyState.Session): string {
|
|
67
|
+
const completed = BloxyState.countCompleted(session)
|
|
68
|
+
const failed = BloxyState.countFailed(session)
|
|
69
|
+
const total = session.tasks.length
|
|
70
|
+
|
|
71
|
+
const parts: string[] = []
|
|
72
|
+
|
|
73
|
+
parts.push("## Bloxy Session Complete")
|
|
74
|
+
parts.push("")
|
|
75
|
+
parts.push(`**Results**: ${completed}/${total} tasks completed${failed > 0 ? `, ${failed} failed` : ""}`)
|
|
76
|
+
parts.push("")
|
|
77
|
+
|
|
78
|
+
if (completed > 0) {
|
|
79
|
+
parts.push("### Completed Tasks")
|
|
80
|
+
session.tasks.filter(t => t.status === "completed").forEach(t => {
|
|
81
|
+
parts.push(`- [x] ${t.title}${t.summary ? `: ${t.summary}` : ""}`)
|
|
82
|
+
})
|
|
83
|
+
parts.push("")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (failed > 0) {
|
|
87
|
+
parts.push("### Failed Tasks")
|
|
88
|
+
session.tasks.filter(t => t.status === "failed").forEach(t => {
|
|
89
|
+
parts.push(`- [ ] ${t.title}${t.error ? `: ${t.error}` : ""}`)
|
|
90
|
+
})
|
|
91
|
+
parts.push("")
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const duration = session.time.completed && session.time.started
|
|
95
|
+
? Math.round((session.time.completed - session.time.started) / 1000)
|
|
96
|
+
: 0
|
|
97
|
+
|
|
98
|
+
if (duration > 0) {
|
|
99
|
+
const minutes = Math.floor(duration / 60)
|
|
100
|
+
const seconds = duration % 60
|
|
101
|
+
parts.push(`**Duration**: ${minutes > 0 ? `${minutes}m ` : ""}${seconds}s`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return parts.join("\n")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Build the status display for the TUI
|
|
109
|
+
*/
|
|
110
|
+
export function buildStatusLine(session: BloxyState.Session): string {
|
|
111
|
+
const task = BloxyState.getCurrentTask(session)
|
|
112
|
+
if (!task) {
|
|
113
|
+
return BloxyState.formatProgress(session)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const completed = BloxyState.countCompleted(session)
|
|
117
|
+
const total = session.tasks.length
|
|
118
|
+
|
|
119
|
+
return `[${completed + 1}/${total}] ${task.title}`
|
|
120
|
+
}
|
|
121
|
+
}
|