tulingcode 0.1.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 +134 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/tuling +179 -0
- package/bunfig.toml +7 -0
- package/drizzle.config.ts +10 -0
- package/git +0 -0
- package/migration/20260127222353_familiar_lady_ursula/migration.sql +90 -0
- package/migration/20260127222353_familiar_lady_ursula/snapshot.json +796 -0
- package/migration/20260211171708_add_project_commands/migration.sql +1 -0
- package/migration/20260211171708_add_project_commands/snapshot.json +806 -0
- package/migration/20260213144116_wakeful_the_professor/migration.sql +11 -0
- package/migration/20260213144116_wakeful_the_professor/snapshot.json +897 -0
- package/migration/20260225215848_workspace/migration.sql +7 -0
- package/migration/20260225215848_workspace/snapshot.json +959 -0
- package/migration/20260227213759_add_session_workspace_id/migration.sql +2 -0
- package/migration/20260227213759_add_session_workspace_id/snapshot.json +983 -0
- package/migration/20260228203230_blue_harpoon/migration.sql +17 -0
- package/migration/20260228203230_blue_harpoon/snapshot.json +1102 -0
- package/migration/20260303231226_add_workspace_fields/migration.sql +5 -0
- package/migration/20260303231226_add_workspace_fields/snapshot.json +1013 -0
- package/migration/20260309230000_move_org_to_state/migration.sql +3 -0
- package/migration/20260309230000_move_org_to_state/snapshot.json +1156 -0
- package/migration/20260312043431_session_message_cursor/migration.sql +4 -0
- package/migration/20260312043431_session_message_cursor/snapshot.json +1168 -0
- package/migration/20260323234822_events/migration.sql +13 -0
- package/migration/20260323234822_events/snapshot.json +1271 -0
- package/migration/20260410174513_workspace-name/migration.sql +16 -0
- package/migration/20260410174513_workspace-name/snapshot.json +1271 -0
- package/migration/20260413175956_chief_energizer/migration.sql +13 -0
- package/migration/20260413175956_chief_energizer/snapshot.json +1399 -0
- package/migration/20260422160000_context_inheritance/migration.sql +3 -0
- package/migration/20260422170000_task_registry/migration.sql +18 -0
- package/migration/20260423145421_remove_session_entry/migration.sql +4 -0
- package/migration/20260515000000_actor_rename/migration.sql +7 -0
- package/migration/20260515010000_memory_fts/migration.sql +33 -0
- package/migration/20260515020000_user_task/migration.sql +29 -0
- package/migration/20260519000000_last_checkpoint_message_id/migration.sql +1 -0
- package/migration/20260521000000_message_agent_id/migration.sql +2 -0
- package/migration/20260521000100_actor_registry_v6/migration.sql +25 -0
- package/migration/20260521010000_memory_fts_v6/migration.sql +33 -0
- package/migration/20260521020000_memory_fts_triggers/migration.sql +17 -0
- package/migration/20260526000000_agent_id_main/migration.sql +14 -0
- package/migration/20260527000000_actor_lifecycle/migration.sql +8 -0
- package/migration/20260527000100_inbox/migration.sql +12 -0
- package/migration/20260529000000_task_todo_redesign/migration.sql +16 -0
- package/migration/20260603000000_task_in_progress_owner/migration.sql +1 -0
- package/migration/20260603000000_workflow_run/migration.sql +17 -0
- package/migration/20260604000000_workflow_script_sha/migration.sql +1 -0
- package/migration/20260608000000_claude_import/migration.sql +7 -0
- package/migration/20260608010000_claude_import_message_ids/migration.sql +1 -0
- package/migration/20260609000000_history_fts/migration.sql +29 -0
- package/migration/20260609230000_workflow_agent_timeout/migration.sql +1 -0
- package/package.json +196 -0
- package/parsers-config.ts +290 -0
- package/script/build.ts +267 -0
- package/script/check-migrations.ts +16 -0
- package/script/fix-node-pty.ts +28 -0
- package/script/generate.ts +23 -0
- package/script/postinstall.mjs +102 -0
- package/script/publish.ts +60 -0
- package/script/run-workspace-server +106 -0
- package/script/schema.ts +63 -0
- package/script/time.ts +6 -0
- package/script/trace-imports.ts +153 -0
- package/script/upgrade-opentui.ts +64 -0
- package/src/account/account.sql.ts +39 -0
- package/src/account/account.ts +456 -0
- package/src/account/repo.ts +166 -0
- package/src/account/schema.ts +99 -0
- package/src/account/url.ts +8 -0
- package/src/acp/README.md +174 -0
- package/src/acp/agent.ts +1783 -0
- package/src/acp/session.ts +116 -0
- package/src/acp/types.ts +24 -0
- package/src/actor/actor.sql.ts +38 -0
- package/src/actor/events.ts +67 -0
- package/src/actor/index.ts +2 -0
- package/src/actor/registry.ts +412 -0
- package/src/actor/return-header.ts +24 -0
- package/src/actor/schema.ts +47 -0
- package/src/actor/spawn-ref.ts +16 -0
- package/src/actor/spawn.ts +741 -0
- package/src/actor/turn.ts +49 -0
- package/src/actor/waiter.ts +166 -0
- package/src/agent/agent.ts +554 -0
- package/src/agent/config.ts +5 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/checkpoint-writer.txt +167 -0
- package/src/agent/prompt/compaction.txt +9 -0
- package/src/agent/prompt/distill.txt +199 -0
- package/src/agent/prompt/dream.txt +155 -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/audio.d.ts +9 -0
- package/src/auth/index.ts +97 -0
- package/src/bus/bus-event.ts +33 -0
- package/src/bus/global.ts +12 -0
- package/src/bus/index.ts +193 -0
- package/src/cli/bootstrap.ts +33 -0
- package/src/cli/cmd/account.ts +258 -0
- package/src/cli/cmd/acp.ts +70 -0
- package/src/cli/cmd/agent.ts +248 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/db.ts +120 -0
- package/src/cli/cmd/debug/agent.ts +192 -0
- package/src/cli/cmd/debug/config.ts +17 -0
- package/src/cli/cmd/debug/file.ts +100 -0
- package/src/cli/cmd/debug/index.ts +48 -0
- package/src/cli/cmd/debug/lsp.ts +61 -0
- package/src/cli/cmd/debug/ripgrep.ts +105 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +23 -0
- package/src/cli/cmd/debug/snapshot.ts +53 -0
- package/src/cli/cmd/export.ts +306 -0
- package/src/cli/cmd/generate.ts +50 -0
- package/src/cli/cmd/github.ts +1647 -0
- package/src/cli/cmd/import.ts +208 -0
- package/src/cli/cmd/mcp.ts +812 -0
- package/src/cli/cmd/models.ts +88 -0
- package/src/cli/cmd/plug.ts +233 -0
- package/src/cli/cmd/pr.ts +138 -0
- package/src/cli/cmd/providers.ts +705 -0
- package/src/cli/cmd/run-completion.ts +77 -0
- package/src/cli/cmd/run.ts +694 -0
- package/src/cli/cmd/serve.ts +21 -0
- package/src/cli/cmd/session.ts +181 -0
- package/src/cli/cmd/stats.ts +413 -0
- package/src/cli/cmd/tui/app.tsx +1130 -0
- package/src/cli/cmd/tui/asset/TEN_VAD_LICENSE +12 -0
- package/src/cli/cmd/tui/asset/charge.wav +0 -0
- package/src/cli/cmd/tui/asset/pulse-a.wav +0 -0
- package/src/cli/cmd/tui/asset/pulse-b.wav +0 -0
- package/src/cli/cmd/tui/asset/pulse-c.wav +0 -0
- package/src/cli/cmd/tui/asset/ten_vad.wasm +0 -0
- package/src/cli/cmd/tui/asset/ten_vad_loader.js +30 -0
- package/src/cli/cmd/tui/attach.ts +83 -0
- package/src/cli/cmd/tui/component/background-image.tsx +150 -0
- package/src/cli/cmd/tui/component/bg-pulse.tsx +130 -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 +208 -0
- package/src/cli/cmd/tui/component/dialog-console-org.tsx +103 -0
- package/src/cli/cmd/tui/component/dialog-go-upsell.tsx +157 -0
- package/src/cli/cmd/tui/component/dialog-image-list.tsx +111 -0
- package/src/cli/cmd/tui/component/dialog-logo-design.tsx +37 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-mimo-login.tsx +224 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +253 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +490 -0
- package/src/cli/cmd/tui/component/dialog-session-delete-failed.tsx +101 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +269 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-skill.tsx +42 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +170 -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/dialog-variant.tsx +39 -0
- package/src/cli/cmd/tui/component/dialog-workflows.tsx +62 -0
- package/src/cli/cmd/tui/component/dialog-workspace-create.tsx +289 -0
- package/src/cli/cmd/tui/component/dialog-workspace-unavailable.tsx +81 -0
- package/src/cli/cmd/tui/component/dialog-worktree.tsx +90 -0
- package/src/cli/cmd/tui/component/error-component.tsx +92 -0
- package/src/cli/cmd/tui/component/logo.tsx +961 -0
- package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +684 -0
- package/src/cli/cmd/tui/component/prompt/cwd.ts +0 -0
- package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1812 -0
- package/src/cli/cmd/tui/component/prompt/part.ts +16 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/spinner.tsx +24 -0
- package/src/cli/cmd/tui/component/starry-background.tsx +305 -0
- package/src/cli/cmd/tui/component/startup-loading.tsx +67 -0
- package/src/cli/cmd/tui/component/task-item.tsx +63 -0
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/config/cwd.ts +5 -0
- package/src/cli/cmd/tui/config/tui-migrate.ts +151 -0
- package/src/cli/cmd/tui/config/tui-schema.ts +38 -0
- package/src/cli/cmd/tui/config/tui.ts +219 -0
- package/src/cli/cmd/tui/context/args.tsx +16 -0
- package/src/cli/cmd/tui/context/directory.ts +15 -0
- package/src/cli/cmd/tui/context/event.ts +45 -0
- package/src/cli/cmd/tui/context/exit.tsx +65 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +105 -0
- package/src/cli/cmd/tui/context/kv.tsx +76 -0
- package/src/cli/cmd/tui/context/language.tsx +91 -0
- package/src/cli/cmd/tui/context/local.tsx +455 -0
- package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
- package/src/cli/cmd/tui/context/project.tsx +109 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +61 -0
- package/src/cli/cmd/tui/context/sdk.tsx +150 -0
- package/src/cli/cmd/tui/context/sync.tsx +828 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +230 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +230 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +225 -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 +234 -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/tulingcode.json +245 -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 +1298 -0
- package/src/cli/cmd/tui/context/thinking.ts +48 -0
- package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
- package/src/cli/cmd/tui/event.ts +56 -0
- package/src/cli/cmd/tui/feature-plugins/home/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +193 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +54 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +114 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/cwd.tsx +45 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/goal.tsx +84 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/instructions.tsx +54 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +98 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/task.tsx +95 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +51 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/tps.ts +31 -0
- package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +274 -0
- package/src/cli/cmd/tui/i18n/en.ts +397 -0
- package/src/cli/cmd/tui/i18n/es.ts +433 -0
- package/src/cli/cmd/tui/i18n/fr.ts +440 -0
- package/src/cli/cmd/tui/i18n/ja.ts +392 -0
- package/src/cli/cmd/tui/i18n/locales.ts +82 -0
- package/src/cli/cmd/tui/i18n/ru.ts +452 -0
- package/src/cli/cmd/tui/i18n/zh.ts +390 -0
- package/src/cli/cmd/tui/i18n/zht.ts +360 -0
- package/src/cli/cmd/tui/layer.ts +6 -0
- package/src/cli/cmd/tui/plugin/api.tsx +402 -0
- package/src/cli/cmd/tui/plugin/index.ts +3 -0
- package/src/cli/cmd/tui/plugin/internal.ts +35 -0
- package/src/cli/cmd/tui/plugin/runtime.ts +1030 -0
- package/src/cli/cmd/tui/plugin/slots.tsx +60 -0
- package/src/cli/cmd/tui/routes/home.tsx +165 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +76 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +116 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +47 -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/index.tsx +2532 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +691 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +488 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +97 -0
- package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +142 -0
- package/src/cli/cmd/tui/thread.ts +246 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +61 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +95 -0
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +223 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +42 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +123 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +452 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +207 -0
- package/src/cli/cmd/tui/ui/link.tsx +28 -0
- package/src/cli/cmd/tui/ui/spinner.ts +378 -0
- package/src/cli/cmd/tui/ui/toast.tsx +102 -0
- package/src/cli/cmd/tui/util/clipboard.ts +203 -0
- package/src/cli/cmd/tui/util/editor.ts +35 -0
- package/src/cli/cmd/tui/util/image-protocol.ts +35 -0
- package/src/cli/cmd/tui/util/index.ts +6 -0
- package/src/cli/cmd/tui/util/model.ts +23 -0
- package/src/cli/cmd/tui/util/provider-origin.ts +7 -0
- package/src/cli/cmd/tui/util/revert-diff.ts +18 -0
- package/src/cli/cmd/tui/util/scroll.ts +23 -0
- package/src/cli/cmd/tui/util/selection.ts +23 -0
- package/src/cli/cmd/tui/util/signal.ts +41 -0
- package/src/cli/cmd/tui/util/sound.ts +154 -0
- package/src/cli/cmd/tui/util/system-locale.ts +209 -0
- package/src/cli/cmd/tui/util/terminal.ts +110 -0
- package/src/cli/cmd/tui/util/transcript.ts +112 -0
- package/src/cli/cmd/tui/util/vad.ts +229 -0
- package/src/cli/cmd/tui/util/voice.ts +360 -0
- package/src/cli/cmd/tui/win32.ts +130 -0
- package/src/cli/cmd/tui/worker.ts +104 -0
- package/src/cli/cmd/uninstall.ts +351 -0
- package/src/cli/cmd/upgrade.ts +79 -0
- package/src/cli/cmd/web.ts +81 -0
- package/src/cli/effect/prompt.ts +25 -0
- package/src/cli/error.ts +82 -0
- package/src/cli/heap.ts +59 -0
- package/src/cli/i18n.ts +15 -0
- package/src/cli/logo.ts +53 -0
- package/src/cli/network.ts +62 -0
- package/src/cli/ui.ts +133 -0
- package/src/cli/upgrade.ts +41 -0
- package/src/command/index.ts +276 -0
- package/src/command/template/initialize.txt +66 -0
- package/src/command/template/review.txt +101 -0
- package/src/config/agent.ts +197 -0
- package/src/config/command.ts +69 -0
- package/src/config/config.ts +1024 -0
- package/src/config/console-state.ts +16 -0
- package/src/config/entry-name.ts +16 -0
- package/src/config/error.ts +21 -0
- package/src/config/formatter.ts +17 -0
- package/src/config/history.ts +21 -0
- package/src/config/index.ts +16 -0
- package/src/config/keybinds.ts +127 -0
- package/src/config/layout.ts +10 -0
- package/src/config/lsp.ts +45 -0
- package/src/config/managed.ts +70 -0
- package/src/config/markdown.ts +97 -0
- package/src/config/mcp.ts +172 -0
- package/src/config/model-id.ts +14 -0
- package/src/config/parse.ts +44 -0
- package/src/config/paths.ts +73 -0
- package/src/config/permission.ts +76 -0
- package/src/config/plugin.ts +88 -0
- package/src/config/provider.ts +118 -0
- package/src/config/server.ts +20 -0
- package/src/config/skills.ts +16 -0
- package/src/config/variable.ts +90 -0
- package/src/control-plane/adaptors/index.ts +52 -0
- package/src/control-plane/adaptors/worktree.ts +47 -0
- package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
- package/src/control-plane/schema.ts +19 -0
- package/src/control-plane/sse.ts +66 -0
- package/src/control-plane/types.ts +34 -0
- package/src/control-plane/util.ts +37 -0
- package/src/control-plane/workspace-context.ts +26 -0
- package/src/control-plane/workspace.sql.ts +17 -0
- package/src/control-plane/workspace.ts +615 -0
- package/src/effect/app-runtime.ts +146 -0
- package/src/effect/bootstrap-runtime.ts +33 -0
- package/src/effect/bridge.ts +48 -0
- package/src/effect/cross-spawn-spawner.ts +514 -0
- package/src/effect/index.ts +5 -0
- package/src/effect/instance-ref.ts +11 -0
- package/src/effect/instance-registry.ts +12 -0
- package/src/effect/instance-state.ts +81 -0
- package/src/effect/logger.ts +73 -0
- package/src/effect/memo-map.ts +3 -0
- package/src/effect/observability.ts +107 -0
- package/src/effect/run-service.ts +52 -0
- package/src/effect/runner.ts +210 -0
- package/src/effect/runtime.ts +19 -0
- package/src/env/index.ts +37 -0
- package/src/file/ignore.ts +81 -0
- package/src/file/index.ts +664 -0
- package/src/file/protected.ts +59 -0
- package/src/file/ripgrep.ts +485 -0
- package/src/file/watcher.ts +163 -0
- package/src/flag/flag.ts +164 -0
- package/src/format/formatter.ts +403 -0
- package/src/format/index.ts +203 -0
- package/src/git/index.ts +260 -0
- package/src/global/index.ts +54 -0
- package/src/history/backfill.ts +162 -0
- package/src/history/extract.ts +67 -0
- package/src/history/fts-query.ts +15 -0
- package/src/history/fts.sql.ts +20 -0
- package/src/history/index.ts +10 -0
- package/src/history/resolve.ts +65 -0
- package/src/history/service.ts +258 -0
- package/src/history/writer.ts +112 -0
- package/src/id/id.ts +87 -0
- package/src/ide/index.ts +73 -0
- package/src/inbox/inbox-ref.ts +38 -0
- package/src/inbox/inbox.sql.ts +26 -0
- package/src/inbox/inbox.ts +223 -0
- package/src/inbox/index.ts +3 -0
- package/src/inbox/render.ts +40 -0
- package/src/index.ts +260 -0
- package/src/installation/index.ts +351 -0
- package/src/installation/version.ts +8 -0
- package/src/lsp/client.ts +249 -0
- package/src/lsp/diagnostic.ts +29 -0
- package/src/lsp/index.ts +3 -0
- package/src/lsp/language.ts +120 -0
- package/src/lsp/launch.ts +21 -0
- package/src/lsp/lsp.ts +519 -0
- package/src/lsp/server.ts +1956 -0
- package/src/mcp/auth.ts +144 -0
- package/src/mcp/index.ts +944 -0
- package/src/mcp/oauth-callback.ts +232 -0
- package/src/mcp/oauth-provider.ts +214 -0
- package/src/memory/fts-query.ts +37 -0
- package/src/memory/fts.sql.ts +19 -0
- package/src/memory/index.ts +1 -0
- package/src/memory/paths.ts +116 -0
- package/src/memory/reconcile.ts +144 -0
- package/src/memory/service.ts +144 -0
- package/src/metrics/client.ts +40 -0
- package/src/metrics/event.ts +43 -0
- package/src/metrics/index.ts +5 -0
- package/src/metrics/installation.ts +18 -0
- package/src/metrics/subscriber.ts +58 -0
- package/src/metrics/util.ts +9 -0
- package/src/node.ts +6 -0
- package/src/npm/config.ts +0 -0
- package/src/npm/index.ts +293 -0
- package/src/npmcli-config.d.ts +43 -0
- package/src/patch/index.ts +680 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/evaluate.ts +15 -0
- package/src/permission/index.ts +379 -0
- package/src/permission/schema.ts +17 -0
- package/src/plugin/checkpoint-splitover.ts +60 -0
- package/src/plugin/cloud-ai.ts +329 -0
- package/src/plugin/cloudflare.ts +76 -0
- package/src/plugin/codex.ts +607 -0
- package/src/plugin/github-copilot/copilot.ts +368 -0
- package/src/plugin/github-copilot/models.ts +153 -0
- package/src/plugin/index.ts +493 -0
- package/src/plugin/install.ts +439 -0
- package/src/plugin/loader.ts +216 -0
- package/src/plugin/matcher.ts +33 -0
- package/src/plugin/meta.ts +188 -0
- package/src/plugin/mimo-free.ts +153 -0
- package/src/plugin/mimo.ts +124 -0
- package/src/plugin/shared.ts +323 -0
- package/src/plugin/subagent-progress-checker.ts +147 -0
- package/src/project/bootstrap.ts +59 -0
- package/src/project/index.ts +2 -0
- package/src/project/instance.ts +190 -0
- package/src/project/project-id.ts +48 -0
- package/src/project/project.sql.ts +16 -0
- package/src/project/project.ts +501 -0
- package/src/project/schema.ts +15 -0
- package/src/project/vcs.ts +227 -0
- package/src/provider/auth.ts +234 -0
- package/src/provider/error.ts +216 -0
- package/src/provider/index.ts +5 -0
- package/src/provider/models.ts +180 -0
- package/src/provider/provider.ts +1782 -0
- package/src/provider/schema.ts +36 -0
- package/src/provider/sdk/copilot/README.md +5 -0
- package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
- package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
- package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +815 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +83 -0
- package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
- package/src/provider/sdk/copilot/index.ts +2 -0
- package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
- package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +335 -0
- package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
- package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +214 -0
- package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1770 -0
- package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +173 -0
- package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +87 -0
- package/src/provider/sdk/copilot/responses/tool/file-search.ts +127 -0
- package/src/provider/sdk/copilot/responses/tool/image-generation.ts +114 -0
- package/src/provider/sdk/copilot/responses/tool/local-shell.ts +64 -0
- package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +103 -0
- package/src/provider/sdk/copilot/responses/tool/web-search.ts +102 -0
- package/src/provider/transform.ts +1322 -0
- package/src/pty/index.ts +364 -0
- package/src/pty/pty.bun.ts +26 -0
- package/src/pty/pty.node.ts +27 -0
- package/src/pty/pty.ts +25 -0
- package/src/pty/schema.ts +17 -0
- package/src/question/index.ts +252 -0
- package/src/question/schema.ts +17 -0
- package/src/server/adapter.bun.ts +40 -0
- package/src/server/adapter.node.ts +66 -0
- package/src/server/adapter.ts +21 -0
- package/src/server/error.ts +53 -0
- package/src/server/event.ts +7 -0
- package/src/server/fence.ts +81 -0
- package/src/server/mdns.ts +60 -0
- package/src/server/middleware.ts +92 -0
- package/src/server/projectors.ts +28 -0
- package/src/server/proxy.ts +171 -0
- package/src/server/routes/control/index.ts +160 -0
- package/src/server/routes/control/workspace.ts +203 -0
- package/src/server/routes/global.ts +287 -0
- package/src/server/routes/instance/bash-interactive.ts +82 -0
- package/src/server/routes/instance/config.ts +89 -0
- package/src/server/routes/instance/event.ts +88 -0
- package/src/server/routes/instance/experimental.ts +408 -0
- package/src/server/routes/instance/file.ts +190 -0
- package/src/server/routes/instance/httpapi/config.ts +51 -0
- package/src/server/routes/instance/httpapi/permission.ts +72 -0
- package/src/server/routes/instance/httpapi/project.ts +62 -0
- package/src/server/routes/instance/httpapi/provider.ts +142 -0
- package/src/server/routes/instance/httpapi/question.ts +121 -0
- package/src/server/routes/instance/httpapi/server.ts +136 -0
- package/src/server/routes/instance/index.ts +301 -0
- package/src/server/routes/instance/mcp.ts +260 -0
- package/src/server/routes/instance/middleware.ts +35 -0
- package/src/server/routes/instance/permission.ts +73 -0
- package/src/server/routes/instance/project.ts +122 -0
- package/src/server/routes/instance/provider.ts +158 -0
- package/src/server/routes/instance/pty.ts +247 -0
- package/src/server/routes/instance/question.ts +162 -0
- package/src/server/routes/instance/session.ts +1296 -0
- package/src/server/routes/instance/sync.ts +143 -0
- package/src/server/routes/instance/trace.ts +59 -0
- package/src/server/routes/instance/tui.ts +384 -0
- package/src/server/routes/instance/workflows.ts +72 -0
- package/src/server/routes/ui.ts +55 -0
- package/src/server/server.ts +136 -0
- package/src/server/workspace.ts +122 -0
- package/src/session/auto-dream.ts +123 -0
- package/src/session/boundary.ts +77 -0
- package/src/session/budgeted-read.ts +118 -0
- package/src/session/checkpoint-align.ts +29 -0
- package/src/session/checkpoint-context.ts +36 -0
- package/src/session/checkpoint-paths.ts +86 -0
- package/src/session/checkpoint-progress-reconcile.ts +111 -0
- package/src/session/checkpoint-retry.ts +192 -0
- package/src/session/checkpoint-templates.ts +114 -0
- package/src/session/checkpoint-validator.ts +259 -0
- package/src/session/checkpoint.ts +1478 -0
- package/src/session/classify.ts +92 -0
- package/src/session/claude-import.sql.ts +13 -0
- package/src/session/claude-import.ts +379 -0
- package/src/session/compaction.ts +543 -0
- package/src/session/goal.ts +232 -0
- package/src/session/index.ts +1 -0
- package/src/session/instruction.ts +276 -0
- package/src/session/last-message-info.ts +32 -0
- package/src/session/llm-request-prefix.ts +82 -0
- package/src/session/llm.ts +735 -0
- package/src/session/max-mode.ts +397 -0
- package/src/session/message-v2.ts +1136 -0
- package/src/session/message.ts +191 -0
- package/src/session/overflow.ts +53 -0
- package/src/session/prefix-capture-ref.ts +48 -0
- package/src/session/processor.ts +962 -0
- package/src/session/projectors.ts +137 -0
- package/src/session/prompt/anthropic.txt +154 -0
- package/src/session/prompt/beast.txt +155 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex.txt +79 -0
- package/src/session/prompt/compose.txt +115 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/default.txt +151 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/gpt.txt +107 -0
- package/src/session/prompt/kimi.txt +95 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/trinity.txt +97 -0
- package/src/session/prompt.ts +3355 -0
- package/src/session/prune.ts +481 -0
- package/src/session/retry.ts +166 -0
- package/src/session/revert.ts +161 -0
- package/src/session/run-state.ts +135 -0
- package/src/session/schema.ts +36 -0
- package/src/session/session.sql.ts +110 -0
- package/src/session/session.ts +908 -0
- package/src/session/status.ts +89 -0
- package/src/session/summary.ts +163 -0
- package/src/session/system.ts +86 -0
- package/src/session/todo.ts +77 -0
- package/src/share/index.ts +2 -0
- package/src/share/session.ts +57 -0
- package/src/share/share-next.ts +381 -0
- package/src/share/share.sql.ts +13 -0
- package/src/shell/shell.ts +110 -0
- package/src/skill/compose/.bundle/ask/SKILL.md +58 -0
- package/src/skill/compose/.bundle/brainstorm/SKILL.md +220 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/frame-template.html +214 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/helper.js +88 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/server.cjs +354 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/start-server.sh +148 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/stop-server.sh +56 -0
- package/src/skill/compose/.bundle/brainstorm/spec-document-reviewer-prompt.md +50 -0
- package/src/skill/compose/.bundle/brainstorm/visual-companion.md +287 -0
- package/src/skill/compose/.bundle/debug/CREATION-LOG.md +119 -0
- package/src/skill/compose/.bundle/debug/SKILL.md +297 -0
- package/src/skill/compose/.bundle/debug/condition-based-waiting-example.ts +158 -0
- package/src/skill/compose/.bundle/debug/condition-based-waiting.md +115 -0
- package/src/skill/compose/.bundle/debug/defense-in-depth.md +122 -0
- package/src/skill/compose/.bundle/debug/find-polluter.sh +63 -0
- package/src/skill/compose/.bundle/debug/root-cause-tracing.md +169 -0
- package/src/skill/compose/.bundle/debug/test-academic.md +14 -0
- package/src/skill/compose/.bundle/debug/test-pressure-1.md +58 -0
- package/src/skill/compose/.bundle/debug/test-pressure-2.md +68 -0
- package/src/skill/compose/.bundle/debug/test-pressure-3.md +69 -0
- package/src/skill/compose/.bundle/execute/SKILL.md +71 -0
- package/src/skill/compose/.bundle/feedback/SKILL.md +214 -0
- package/src/skill/compose/.bundle/merge/SKILL.md +252 -0
- package/src/skill/compose/.bundle/new-skill/SKILL.md +656 -0
- package/src/skill/compose/.bundle/new-skill/anthropic-best-practices.md +1150 -0
- package/src/skill/compose/.bundle/new-skill/examples/CLAUDE_MD_TESTING.md +189 -0
- package/src/skill/compose/.bundle/new-skill/graphviz-conventions.dot +172 -0
- package/src/skill/compose/.bundle/new-skill/persuasion-principles.md +187 -0
- package/src/skill/compose/.bundle/new-skill/render-graphs.js +168 -0
- package/src/skill/compose/.bundle/new-skill/testing-skills-with-subagents.md +384 -0
- package/src/skill/compose/.bundle/parallel/SKILL.md +182 -0
- package/src/skill/compose/.bundle/plan/SKILL.md +161 -0
- package/src/skill/compose/.bundle/plan/plan-document-reviewer-prompt.md +50 -0
- package/src/skill/compose/.bundle/report/SKILL.md +180 -0
- package/src/skill/compose/.bundle/review/SKILL.md +104 -0
- package/src/skill/compose/.bundle/review/code-reviewer.md +171 -0
- package/src/skill/compose/.bundle/subagent/SKILL.md +344 -0
- package/src/skill/compose/.bundle/subagent/code-quality-reviewer-prompt.md +24 -0
- package/src/skill/compose/.bundle/subagent/implementer-prompt.md +126 -0
- package/src/skill/compose/.bundle/subagent/spec-reviewer-prompt.md +112 -0
- package/src/skill/compose/.bundle/tdd/SKILL.md +372 -0
- package/src/skill/compose/.bundle/tdd/testing-anti-patterns.md +299 -0
- package/src/skill/compose/.bundle/verify/SKILL.md +140 -0
- package/src/skill/compose/.bundle/worktree/SKILL.md +234 -0
- package/src/skill/compose/LICENSE-karpathy +28 -0
- package/src/skill/compose/LICENSE-superpowers +26 -0
- package/src/skill/compose/bundle.macro.ts +30 -0
- package/src/skill/compose/extract.ts +85 -0
- package/src/skill/discovery.ts +116 -0
- package/src/skill/index.ts +311 -0
- package/src/snapshot/index.ts +777 -0
- package/src/sql.d.ts +4 -0
- package/src/storage/db.bun.ts +8 -0
- package/src/storage/db.node.ts +8 -0
- package/src/storage/db.ts +172 -0
- package/src/storage/index.ts +26 -0
- package/src/storage/json-migration.ts +426 -0
- package/src/storage/schema.sql.ts +10 -0
- package/src/storage/schema.ts +7 -0
- package/src/storage/storage.ts +331 -0
- package/src/sync/README.md +179 -0
- package/src/sync/event.sql.ts +16 -0
- package/src/sync/index.ts +278 -0
- package/src/sync/schema.ts +14 -0
- package/src/task/events.ts +28 -0
- package/src/task/gate-state.ts +54 -0
- package/src/task/gate.ts +116 -0
- package/src/task/index.ts +1 -0
- package/src/task/registry.ts +387 -0
- package/src/task/schema.ts +43 -0
- package/src/task/task.sql.ts +50 -0
- package/src/team/events.ts +22 -0
- package/src/team/index.ts +113 -0
- package/src/team/schema.ts +31 -0
- package/src/temporary.ts +33 -0
- package/src/tool/actor.shell.txt +72 -0
- package/src/tool/actor.ts +803 -0
- package/src/tool/actor.txt +103 -0
- package/src/tool/apply_patch.ts +308 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/bash-interactive.ts +183 -0
- package/src/tool/bash.ts +696 -0
- package/src/tool/bash.txt +123 -0
- package/src/tool/change-directory.ts +91 -0
- package/src/tool/codesearch.ts +63 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +685 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +132 -0
- package/src/tool/glob.ts +100 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +145 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/history.ts +146 -0
- package/src/tool/history.txt +17 -0
- package/src/tool/index.ts +4 -0
- package/src/tool/invalid.ts +20 -0
- package/src/tool/invocation-style.ts +17 -0
- package/src/tool/lsp.ts +91 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/mcp-exa.ts +78 -0
- package/src/tool/memory-path-guard.ts +162 -0
- package/src/tool/memory.ts +81 -0
- package/src/tool/memory.txt +69 -0
- package/src/tool/multiedit.ts +61 -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 +90 -0
- package/src/tool/question.ts +67 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/read.ts +327 -0
- package/src/tool/read.txt +14 -0
- package/src/tool/registry.ts +413 -0
- package/src/tool/schema.ts +17 -0
- package/src/tool/session-cwd.ts +35 -0
- package/src/tool/shell-tokenize.ts +346 -0
- package/src/tool/shell-wrap.ts +190 -0
- package/src/tool/skill.ts +76 -0
- package/src/tool/skill.txt +5 -0
- package/src/tool/task.shell.txt +57 -0
- package/src/tool/task.ts +456 -0
- package/src/tool/task.txt +56 -0
- package/src/tool/tool.ts +153 -0
- package/src/tool/truncate.ts +201 -0
- package/src/tool/truncation-dir.ts +4 -0
- package/src/tool/webfetch.ts +199 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch/index.ts +104 -0
- package/src/tool/websearch/mimo.ts +118 -0
- package/src/tool/websearch/websearch.txt +14 -0
- package/src/tool/workflow.ts +164 -0
- package/src/tool/workflow.txt +25 -0
- package/src/tool/write.ts +88 -0
- package/src/tool/write.txt +9 -0
- package/src/util/abort.ts +35 -0
- package/src/util/archive.ts +15 -0
- package/src/util/color.ts +17 -0
- package/src/util/data-url.ts +9 -0
- package/src/util/defer.ts +10 -0
- package/src/util/effect-http-client.ts +11 -0
- package/src/util/effect-zod.ts +367 -0
- package/src/util/error.ts +78 -0
- package/src/util/filesystem.ts +243 -0
- package/src/util/fn.ts +21 -0
- package/src/util/format.ts +20 -0
- package/src/util/iife.ts +3 -0
- package/src/util/index.ts +12 -0
- package/src/util/keybind.ts +101 -0
- package/src/util/lazy.ts +18 -0
- package/src/util/local-context.ts +23 -0
- package/src/util/locale.ts +79 -0
- package/src/util/lock.ts +96 -0
- package/src/util/log.ts +197 -0
- package/src/util/media.ts +26 -0
- package/src/util/mimo-process.ts +24 -0
- package/src/util/network.ts +9 -0
- package/src/util/process.ts +174 -0
- package/src/util/queue.ts +32 -0
- package/src/util/record.ts +3 -0
- package/src/util/rpc.ts +64 -0
- package/src/util/schema.ts +53 -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 +5 -0
- package/src/util/update-schema.ts +13 -0
- package/src/util/which.ts +14 -0
- package/src/util/wildcard.ts +57 -0
- package/src/workflow/builtin/deep-research.js +391 -0
- package/src/workflow/builtin.ts +54 -0
- package/src/workflow/events.ts +72 -0
- package/src/workflow/meta.ts +335 -0
- package/src/workflow/persistence.ts +312 -0
- package/src/workflow/resolve.ts +45 -0
- package/src/workflow/runtime-ref.ts +18 -0
- package/src/workflow/runtime.ts +1234 -0
- package/src/workflow/sandbox.ts +280 -0
- package/src/workflow/workflow.sql.ts +31 -0
- package/src/workflow/workspace.ts +69 -0
- package/src/worktree/index.ts +614 -0
- package/sst-env.d.ts +10 -0
- package/test/AGENTS.md +133 -0
- package/test/account/repo.test.ts +352 -0
- package/test/account/service.test.ts +456 -0
- package/test/acp/agent-interface.test.ts +51 -0
- package/test/acp/event-subscription.test.ts +725 -0
- package/test/actor/cancel-cascade.test.ts +432 -0
- package/test/actor/no-completion-listener.test.ts +41 -0
- package/test/actor/poststop-progress-write-permission.repro.test.ts +414 -0
- package/test/actor/registry-render.test.ts +113 -0
- package/test/actor/registry-status.test.ts +111 -0
- package/test/actor/registry.test.ts +619 -0
- package/test/actor/return-header.test.ts +40 -0
- package/test/actor/spawn-lifecycle.test.ts +346 -0
- package/test/actor/spawn-no-deadlock.test.ts +340 -0
- package/test/actor/spawn-notification.test.ts +393 -0
- package/test/actor/spawn-task-autostart.test.ts +530 -0
- package/test/actor/spawn.test.ts +1072 -0
- package/test/actor/status-event-payload.test.ts +132 -0
- package/test/actor/terminology.test.ts +39 -0
- package/test/actor/turn.test.ts +125 -0
- package/test/actor/waiter.test.ts +246 -0
- package/test/agent/agent.test.ts +874 -0
- package/test/agent/allowlist.test.ts +45 -0
- package/test/auth/auth.test.ts +86 -0
- package/test/bus/bus-effect.test.ts +162 -0
- package/test/bus/bus-integration.test.ts +87 -0
- package/test/bus/bus.test.ts +219 -0
- package/test/cli/account.test.ts +26 -0
- package/test/cli/cmd/tui/prompt-part.test.ts +47 -0
- package/test/cli/error.test.ts +18 -0
- package/test/cli/github-action.test.ts +198 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/cli/import.test.ts +54 -0
- package/test/cli/plugin-auth-picker.test.ts +120 -0
- package/test/cli/run-completion.test.ts +131 -0
- package/test/cli/tui/keybind-plugin.test.ts +90 -0
- package/test/cli/tui/plugin-add.test.ts +111 -0
- package/test/cli/tui/plugin-install.test.ts +87 -0
- package/test/cli/tui/plugin-lifecycle.test.ts +224 -0
- package/test/cli/tui/plugin-loader-entrypoint.test.ts +484 -0
- package/test/cli/tui/plugin-loader-pure.test.ts +71 -0
- package/test/cli/tui/plugin-loader.test.ts +816 -0
- package/test/cli/tui/plugin-toggle.test.ts +157 -0
- package/test/cli/tui/revert-diff.test.ts +35 -0
- package/test/cli/tui/route-agent-id.test.ts +26 -0
- package/test/cli/tui/sidebar-tps.test.ts +63 -0
- package/test/cli/tui/slot-replace.test.tsx +47 -0
- package/test/cli/tui/sync-bucket.test.ts +29 -0
- package/test/cli/tui/theme-store.test.ts +51 -0
- package/test/cli/tui/thread.test.ts +121 -0
- package/test/cli/tui/transcript.test.ts +426 -0
- package/test/cli/tui/use-event.test.tsx +175 -0
- package/test/cli/tui/voice.test.ts +269 -0
- package/test/command/deep-research-command.test.ts +16 -0
- package/test/config/agent-color.test.ts +77 -0
- package/test/config/checkpoint-fork.test.ts +21 -0
- package/test/config/config.test.ts +2577 -0
- package/test/config/fixtures/empty-frontmatter.md +4 -0
- package/test/config/fixtures/frontmatter.md +28 -0
- package/test/config/fixtures/markdown-header.md +11 -0
- package/test/config/fixtures/no-frontmatter.md +1 -0
- package/test/config/fixtures/weird-model-id.md +13 -0
- package/test/config/lsp.test.ts +87 -0
- package/test/config/markdown.test.ts +228 -0
- package/test/config/plugin.test.ts +0 -0
- package/test/config/tui.test.ts +627 -0
- package/test/control-plane/adaptors.test.ts +71 -0
- package/test/control-plane/sse.test.ts +56 -0
- package/test/effect/app-runtime-logger.test.ts +92 -0
- package/test/effect/cross-spawn-spawner.test.ts +411 -0
- package/test/effect/instance-state.test.ts +482 -0
- package/test/effect/observability.test.ts +46 -0
- package/test/effect/run-service.test.ts +46 -0
- package/test/effect/runner-warn-log.test.ts +111 -0
- package/test/effect/runner.test.ts +494 -0
- package/test/fake/provider.ts +90 -0
- package/test/file/fsmonitor.test.ts +68 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/file/index.test.ts +956 -0
- package/test/file/path-traversal.test.ts +204 -0
- package/test/file/ripgrep.test.ts +214 -0
- package/test/file/watcher.test.ts +249 -0
- package/test/filesystem/filesystem.test.ts +319 -0
- package/test/fixture/db.ts +11 -0
- package/test/fixture/fixture.test.ts +58 -0
- package/test/fixture/fixture.ts +190 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/lsp/fake-lsp-server.js +75 -0
- package/test/fixture/plug-worker.ts +93 -0
- package/test/fixture/plugin-meta-worker.ts +19 -0
- package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
- package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
- package/test/fixture/skills/cloudflare/SKILL.md +211 -0
- package/test/fixture/skills/index.json +6 -0
- package/test/fixture/tui-plugin.ts +328 -0
- package/test/fixture/tui-runtime.ts +31 -0
- package/test/format/format.test.ts +244 -0
- package/test/git/git.test.ts +128 -0
- package/test/global/fixture/global-paths-worker.ts +17 -0
- package/test/global/mimocode-home.test.ts +143 -0
- package/test/history/backfill.test.ts +149 -0
- package/test/history/extract.test.ts +106 -0
- package/test/history/fts-query.test.ts +30 -0
- package/test/history/resolve.test.ts +130 -0
- package/test/history/service.test.ts +210 -0
- package/test/history/writer.test.ts +163 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/inbox/drain-in-loop.test.ts +230 -0
- package/test/inbox/fork-agent-compat.test.ts +387 -0
- package/test/inbox/gc-on-init.test.ts +167 -0
- package/test/inbox/send-no-block.test.ts +120 -0
- package/test/inbox/sender-cancel-independence.test.ts +160 -0
- package/test/inbox/wake-matrix.test.ts +141 -0
- package/test/installation/installation.test.ts +226 -0
- package/test/keybind.test.ts +421 -0
- package/test/lib/effect.ts +53 -0
- package/test/lib/filesystem.ts +10 -0
- package/test/lib/llm-server.ts +770 -0
- package/test/lib/scripted-llm-server.ts +245 -0
- package/test/lsp/client.test.ts +98 -0
- package/test/lsp/index.test.ts +109 -0
- package/test/lsp/launch.test.ts +22 -0
- package/test/lsp/lifecycle.test.ts +184 -0
- package/test/mcp/headers.test.ts +178 -0
- package/test/mcp/lifecycle.test.ts +824 -0
- package/test/mcp/oauth-auto-connect.test.ts +281 -0
- package/test/mcp/oauth-browser.test.ts +268 -0
- package/test/mcp/oauth-callback.test.ts +34 -0
- package/test/memory/abort-leak-webfetch.ts +49 -0
- package/test/memory/abort-leak.test.ts +127 -0
- package/test/memory/cc-frontmatter.test.ts +85 -0
- package/test/memory/cc-paths.test.ts +60 -0
- package/test/memory/cc-reconcile.test.ts +239 -0
- package/test/memory/cc-search.test.ts +151 -0
- package/test/memory/fts-query.test.ts +48 -0
- package/test/memory/fts-rowid-stability.test.ts +271 -0
- package/test/memory/paths.test.ts +210 -0
- package/test/memory/reconcile.test.ts +115 -0
- package/test/memory/service.test.ts +169 -0
- package/test/npm.test.ts +18 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/permission/abort.test.ts +116 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/disabled.test.ts +51 -0
- package/test/permission/next.test.ts +1080 -0
- package/test/permission/non-interactive.test.ts +55 -0
- package/test/permission-task.test.ts +326 -0
- package/test/plugin/actor-hooks.test.ts +1471 -0
- package/test/plugin/auth-override.test.ts +79 -0
- package/test/plugin/checkpoint-splitover.test.ts +434 -0
- package/test/plugin/cloudflare.test.ts +68 -0
- package/test/plugin/codex.test.ts +123 -0
- package/test/plugin/github-copilot-models.test.ts +163 -0
- package/test/plugin/install-concurrency.test.ts +140 -0
- package/test/plugin/install.test.ts +570 -0
- package/test/plugin/loader-shared.test.ts +1169 -0
- package/test/plugin/matcher.test.ts +97 -0
- package/test/plugin/meta.test.ts +137 -0
- package/test/plugin/mimo.test.ts +257 -0
- package/test/plugin/shared.test.ts +88 -0
- package/test/plugin/subagent-progress-checker.test.ts +227 -0
- package/test/plugin/trigger.test.ts +116 -0
- package/test/plugin/workspace-adaptor.test.ts +109 -0
- package/test/preload.ts +102 -0
- package/test/project/migrate-global.test.ts +150 -0
- package/test/project/project-id.test.ts +64 -0
- package/test/project/project.test.ts +481 -0
- package/test/project/vcs.test.ts +286 -0
- package/test/project/worktree-remove.test.ts +126 -0
- package/test/project/worktree.test.ts +214 -0
- package/test/provider/amazon-bedrock.test.ts +462 -0
- package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
- package/test/provider/error.test.ts +160 -0
- package/test/provider/gitlab-duo.test.ts +413 -0
- package/test/provider/model-groups.test.ts +389 -0
- package/test/provider/provider-chunk-timeout.test.ts +23 -0
- package/test/provider/provider.test.ts +2648 -0
- package/test/provider/transform.test.ts +3379 -0
- package/test/pty/pty-output-isolation.test.ts +146 -0
- package/test/pty/pty-session.test.ts +102 -0
- package/test/pty/pty-shell.test.ts +69 -0
- package/test/question/question.test.ts +464 -0
- package/test/server/global-session-list.test.ts +105 -0
- package/test/server/project-init-git.test.ts +122 -0
- package/test/server/session-actions.test.ts +49 -0
- package/test/server/session-list.test.ts +110 -0
- package/test/server/session-messages.test.ts +220 -0
- package/test/server/session-prompt-busy.test.ts +146 -0
- package/test/server/session-select.test.ts +100 -0
- package/test/server/session-task-route.test.ts +165 -0
- package/test/server/summarize-route-main-slice.test.ts +99 -0
- package/test/server/trace-attributes.test.ts +76 -0
- package/test/server/workflows-route.test.ts +279 -0
- package/test/session/bootstrap-skip-system.test.ts +121 -0
- package/test/session/boundary.test.ts +33 -0
- package/test/session/budgeted-read.test.ts +74 -0
- package/test/session/checkpoint-align.test.ts +58 -0
- package/test/session/checkpoint-boundary.test.ts +186 -0
- package/test/session/checkpoint-child-session.test.ts +508 -0
- package/test/session/checkpoint-context.test.ts +141 -0
- package/test/session/checkpoint-drain.test.ts +188 -0
- package/test/session/checkpoint-extract-titles.test.ts +58 -0
- package/test/session/checkpoint-fork-mode.test.ts +576 -0
- package/test/session/checkpoint-main-slice.test.ts +259 -0
- package/test/session/checkpoint-paths.test.ts +78 -0
- package/test/session/checkpoint-permission.test.ts +136 -0
- package/test/session/checkpoint-progress-reconcile.test.ts +219 -0
- package/test/session/checkpoint-rebuild-unify.test.ts +143 -0
- package/test/session/checkpoint-rebuild-v3.test.ts +248 -0
- package/test/session/checkpoint-render-verify.test.ts +512 -0
- package/test/session/checkpoint-retry.test.ts +150 -0
- package/test/session/checkpoint-splitover-integration.test.ts +533 -0
- package/test/session/checkpoint-templates.test.ts +51 -0
- package/test/session/checkpoint-thresholds.test.ts +120 -0
- package/test/session/checkpoint-validator.test.ts +189 -0
- package/test/session/classify-integration.test.ts +476 -0
- package/test/session/classify.test.ts +335 -0
- package/test/session/compaction-agent-scope.test.ts +164 -0
- package/test/session/context-inheritance.test.ts +46 -0
- package/test/session/fork-prefix-invariant.test.ts +116 -0
- package/test/session/goal.test.ts +106 -0
- package/test/session/instruction.test.ts +387 -0
- package/test/session/invalid-output-continuation.test.ts +150 -0
- package/test/session/last-message-info.test.ts +47 -0
- package/test/session/length-tool-safety.test.ts +121 -0
- package/test/session/llm-request-prefix.test.ts +197 -0
- package/test/session/llm-retry.test.ts +59 -0
- package/test/session/llm-system-prompt.test.ts +479 -0
- package/test/session/llm.test.ts +1272 -0
- package/test/session/main-lifecycle.test.ts +51 -0
- package/test/session/main-runloop-history-invariant.test.ts +182 -0
- package/test/session/max-mode-econnreset.test.ts +229 -0
- package/test/session/max-mode.test.ts +54 -0
- package/test/session/message-v2-filter.test.ts +197 -0
- package/test/session/message-v2.test.ts +1119 -0
- package/test/session/messages-default-main.test.ts +105 -0
- package/test/session/messages-pagination.test.ts +888 -0
- package/test/session/overflow.test.ts +576 -0
- package/test/session/processor-effect.test.ts +853 -0
- package/test/session/prompt-effect.test.ts +1574 -0
- package/test/session/prompt-rebuild-loop.test.ts +108 -0
- package/test/session/prompt-rebuild-reset.test.ts +67 -0
- package/test/session/prompt-sweep.test.ts +145 -0
- package/test/session/prompt-task-gate.test.ts +127 -0
- package/test/session/prompt.test.ts +703 -0
- package/test/session/prune-main-slice.test.ts +272 -0
- package/test/session/prune-skip-system.test.ts +346 -0
- package/test/session/prune.test.ts +419 -0
- package/test/session/rebuild-microcompact.test.ts +318 -0
- package/test/session/recall-reminder.test.ts +37 -0
- package/test/session/retry.test.ts +410 -0
- package/test/session/revert-compact.test.ts +639 -0
- package/test/session/run-state-tuple-key.test.ts +152 -0
- package/test/session/session-create-registers-main.test.ts +70 -0
- package/test/session/session.test.ts +181 -0
- package/test/session/snapshot-tool-race.test.ts +301 -0
- package/test/session/structured-output-integration.test.ts +264 -0
- package/test/session/structured-output-retry.test.ts +127 -0
- package/test/session/structured-output.test.ts +397 -0
- package/test/session/summary-main-slice.test.ts +170 -0
- package/test/session/system.test.ts +72 -0
- package/test/share/share-next.test.ts +332 -0
- package/test/shell/shell.test.ts +73 -0
- package/test/skill/compose-review.test.ts +141 -0
- package/test/skill/discovery.test.ts +116 -0
- package/test/skill/skill.test.ts +465 -0
- package/test/snapshot/snapshot.test.ts +1531 -0
- package/test/storage/db.test.ts +16 -0
- package/test/storage/json-migration.test.ts +831 -0
- package/test/storage/storage.test.ts +293 -0
- package/test/sync/index.test.ts +237 -0
- package/test/task/gate-state.test.ts +66 -0
- package/test/task/gate.test.ts +167 -0
- package/test/task/registry.test.ts +152 -0
- package/test/task/state-machine.test.ts +292 -0
- package/test/team/migrate-to-inbox.test.ts +124 -0
- package/test/team/team.test.ts +75 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/actor-cancel.test.ts +206 -0
- package/test/tool/actor-recover.test.ts +50 -0
- package/test/tool/actor-send.test.ts +200 -0
- package/test/tool/actor-status.test.ts +296 -0
- package/test/tool/actor-wait.test.ts +193 -0
- package/test/tool/actor.shell.test.ts +250 -0
- package/test/tool/actor.test.ts +748 -0
- package/test/tool/apply_patch.test.ts +626 -0
- package/test/tool/bash.test.ts +1195 -0
- package/test/tool/describe-workflow.test.ts +12 -0
- package/test/tool/edit.test.ts +691 -0
- package/test/tool/external-directory.test.ts +207 -0
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +65179 -0
- package/test/tool/glob.test.ts +81 -0
- package/test/tool/grep.test.ts +114 -0
- package/test/tool/history.test.ts +144 -0
- package/test/tool/invocation-style.test.ts +30 -0
- package/test/tool/memory-edit-ask-skip.test.ts +62 -0
- package/test/tool/memory-path-guard.test.ts +594 -0
- package/test/tool/memory.test.ts +71 -0
- package/test/tool/question.test.ts +167 -0
- package/test/tool/read.test.ts +483 -0
- package/test/tool/registry-invocation-style.test.ts +121 -0
- package/test/tool/registry.test.ts +164 -0
- package/test/tool/shell-tokenize.test.ts +273 -0
- package/test/tool/shell-wrap-missing-script.test.ts +128 -0
- package/test/tool/shell-wrap.test.ts +257 -0
- package/test/tool/skill.test.ts +99 -0
- package/test/tool/task-recover.test.ts +36 -0
- package/test/tool/task.shell.test.ts +234 -0
- package/test/tool/task.test.ts +296 -0
- package/test/tool/tool-def-shell-shape.test.ts +23 -0
- package/test/tool/tool-define.test.ts +59 -0
- package/test/tool/truncation.test.ts +253 -0
- package/test/tool/webfetch.test.ts +103 -0
- package/test/tool/whitelist.test.ts +373 -0
- package/test/tool/write.test.ts +244 -0
- package/test/util/data-url.test.ts +14 -0
- package/test/util/effect-zod.test.ts +869 -0
- package/test/util/error.test.ts +38 -0
- package/test/util/filesystem.test.ts +656 -0
- package/test/util/format.test.ts +59 -0
- package/test/util/glob.test.ts +164 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/lock.test.ts +72 -0
- package/test/util/log.test.ts +44 -0
- package/test/util/module.test.ts +59 -0
- package/test/util/process.test.ts +128 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/which.test.ts +100 -0
- package/test/util/wildcard.test.ts +90 -0
- package/test/workflow/builtin.test.ts +22 -0
- package/test/workflow/deep-research-cluster.test.ts +47 -0
- package/test/workflow/lib.ts +243 -0
- package/test/workflow/meta.test.ts +142 -0
- package/test/workflow/model-routing.test.ts +68 -0
- package/test/workflow/persistence.test.ts +229 -0
- package/test/workflow/resolve.test.ts +37 -0
- package/test/workflow/runtime-nested.test.ts +419 -0
- package/test/workflow/runtime-worktree.test.ts +261 -0
- package/test/workflow/runtime.test.ts +1078 -0
- package/test/workflow/sandbox.test.ts +259 -0
- package/test/workflow/tool.test.ts +473 -0
- package/test/workflow/verify-wow.test.ts +144 -0
- package/test/workflow/workspace.test.ts +88 -0
- package/test/workspace/workspace-restore.test.ts +281 -0
- package/test/worktree/index.test.ts +30 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
// Parses the mandatory `export const meta = { ... }` literal from a workflow
|
|
2
|
+
// script WITHOUT executing the script body — and, critically, WITHOUT executing
|
|
3
|
+
// the literal either. The literal is parsed as DATA by a small recursive-descent
|
|
4
|
+
// reader (objects/arrays/strings/numbers/booleans/null only), so listing/preview
|
|
5
|
+
// is side-effect-free and cannot reach the host realm. Anything that isn't a
|
|
6
|
+
// pure data literal (calls, property access, operators, functions, spreads,
|
|
7
|
+
// templates) fails to parse and is rejected.
|
|
8
|
+
//
|
|
9
|
+
// Why not `new Function`/`eval`: that runs the literal in the HOST realm,
|
|
10
|
+
// outside the QuickJS sandbox — a meta like
|
|
11
|
+
// { name: (globalThis.process.mainModule.require('child_process').execSync('id'),'x') }
|
|
12
|
+
// would execute arbitrary host code. Why not jsonc-parser: the real meta uses
|
|
13
|
+
// JS object syntax with UNQUOTED keys (`{ name: "x", phases: [{ title: "a" }] }`)
|
|
14
|
+
// and single quotes, which strict/lenient JSONC rejects (verified empirically).
|
|
15
|
+
// A purpose-built data reader handles that syntax while remaining pure data.
|
|
16
|
+
//
|
|
17
|
+
// The meta statement is replaced with an equal-length blank so the body's line
|
|
18
|
+
// numbers are preserved for stack traces.
|
|
19
|
+
|
|
20
|
+
export type WorkflowMeta = {
|
|
21
|
+
name: string
|
|
22
|
+
description: string
|
|
23
|
+
whenToUse?: string
|
|
24
|
+
phases?: { title: string; detail?: string }[]
|
|
25
|
+
model?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type ParseResult =
|
|
29
|
+
| { ok: true; meta: WorkflowMeta; body: string }
|
|
30
|
+
| { ok: false; error: string }
|
|
31
|
+
|
|
32
|
+
const META_START_RE = /export\s+const\s+meta\s*=\s*/
|
|
33
|
+
|
|
34
|
+
export function parseMeta(script: string): ParseResult {
|
|
35
|
+
const start = META_START_RE.exec(script)
|
|
36
|
+
if (!start) {
|
|
37
|
+
return { ok: false, error: "workflow script must start with `export const meta = { ... }`" }
|
|
38
|
+
}
|
|
39
|
+
const open = script.indexOf("{", start.index + start[0].length)
|
|
40
|
+
if (open === -1) {
|
|
41
|
+
return { ok: false, error: "workflow script must start with `export const meta = { ... }`" }
|
|
42
|
+
}
|
|
43
|
+
const close = findBalancedClose(script, open)
|
|
44
|
+
if (close === -1) {
|
|
45
|
+
return { ok: false, error: "could not locate a balanced meta object literal" }
|
|
46
|
+
}
|
|
47
|
+
const literal = script.slice(open, close + 1)
|
|
48
|
+
const parsed = parseDataLiteral(literal)
|
|
49
|
+
if (!parsed.ok) return { ok: false, error: `meta is not a valid object literal: ${parsed.error}` }
|
|
50
|
+
const meta = parsed.value
|
|
51
|
+
if (typeof meta !== "object" || meta === null || Array.isArray(meta)) return { ok: false, error: "meta must be an object" }
|
|
52
|
+
const m = meta as Record<string, unknown>
|
|
53
|
+
if (typeof m.name !== "string" || !m.name) return { ok: false, error: "meta.name (non-empty string) is required" }
|
|
54
|
+
if (typeof m.description !== "string" || !m.description)
|
|
55
|
+
return { ok: false, error: "meta.description (non-empty string) is required" }
|
|
56
|
+
const endIndex = close + 1 + (script[close + 1] === ";" ? 1 : 0)
|
|
57
|
+
const matched = script.slice(start.index, endIndex)
|
|
58
|
+
const body = script.slice(0, start.index) + matched.replace(/[^\n]/g, " ") + script.slice(endIndex)
|
|
59
|
+
return { ok: true, meta: m as WorkflowMeta, body }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Scans from the `{` at `open`, counting brace depth while ignoring braces that
|
|
63
|
+
// appear inside string literals (single/double/backtick, respecting backslash
|
|
64
|
+
// escapes) or comments (`//` line, `/* */` block). Comment handling mirrors
|
|
65
|
+
// `skipTrivia` so a brace inside a meta comment (`{ name: "n" // }` ) is not
|
|
66
|
+
// miscounted. Returns the index of the matching `}` that closes depth to 0, or -1.
|
|
67
|
+
function findBalancedClose(script: string, open: number): number {
|
|
68
|
+
let depth = 0
|
|
69
|
+
let quote = ""
|
|
70
|
+
for (let i = open; i < script.length; i++) {
|
|
71
|
+
const ch = script[i]
|
|
72
|
+
if (quote) {
|
|
73
|
+
if (ch === "\\") {
|
|
74
|
+
i++
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
if (ch === quote) quote = ""
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
if (ch === "/" && script[i + 1] === "/") {
|
|
81
|
+
i += 2
|
|
82
|
+
while (i < script.length && script[i] !== "\n") i++
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
if (ch === "/" && script[i + 1] === "*") {
|
|
86
|
+
i += 2
|
|
87
|
+
while (i < script.length && !(script[i] === "*" && script[i + 1] === "/")) i++
|
|
88
|
+
i++ // land on the `/` of `*/`; loop's i++ steps past it
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
92
|
+
quote = ch
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
if (ch === "{") depth++
|
|
96
|
+
else if (ch === "}") {
|
|
97
|
+
depth--
|
|
98
|
+
if (depth === 0) return i
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return -1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// A tiny recursive-descent reader for the JS object-literal DATA subset. It
|
|
106
|
+
// PARSES, never evaluates: there is no `new Function`/`eval`/`vm` and no host
|
|
107
|
+
// code runs. Accepts objects, arrays, double/single-quoted strings (with
|
|
108
|
+
// standard escapes), numbers, `true`/`false`/`null`, identifier or quoted keys,
|
|
109
|
+
// and trailing commas. Anything else (a call `()`, member access `.`/`[]` as an
|
|
110
|
+
// expression, operators, `function`/`=>`, `...`, backtick templates) is a parse
|
|
111
|
+
// error -> rejected. This is strictly a superset-free of code execution.
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
type DataResult = { ok: true; value: unknown } | { ok: false; error: string }
|
|
115
|
+
|
|
116
|
+
// Real metas are ~2 levels deep (object -> phases[] -> phase object). A cap of
|
|
117
|
+
// 100 is generous for any legitimate meta while preventing pathologically deep
|
|
118
|
+
// input (e.g. `[[[...]]]` 50k deep) from overflowing the native call stack with
|
|
119
|
+
// a `RangeError`. The cap throws `ParseFail`, so `parseDataLiteral`'s catch
|
|
120
|
+
// converts it to `{ ok: false }` — keeping the documented return contract
|
|
121
|
+
// (callers branch on `parsed.ok` and do not try/catch a thrown exception).
|
|
122
|
+
const MAX_DEPTH = 100
|
|
123
|
+
|
|
124
|
+
function parseDataLiteral(text: string): DataResult {
|
|
125
|
+
const reader = { text, pos: 0, depth: 0 }
|
|
126
|
+
// `try` is justified here: the recursive reader signals malformed input by
|
|
127
|
+
// throwing a tagged error which we convert to a result. (No host execution.)
|
|
128
|
+
try {
|
|
129
|
+
skipTrivia(reader)
|
|
130
|
+
const value = readValue(reader)
|
|
131
|
+
skipTrivia(reader)
|
|
132
|
+
if (reader.pos !== reader.text.length) throw new ParseFail(`unexpected token at offset ${reader.pos}`)
|
|
133
|
+
return { ok: true, value }
|
|
134
|
+
} catch (e) {
|
|
135
|
+
if (e instanceof ParseFail) return { ok: false, error: e.message }
|
|
136
|
+
throw e
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
class ParseFail extends Error {}
|
|
141
|
+
|
|
142
|
+
type Reader = { text: string; pos: number; depth: number }
|
|
143
|
+
|
|
144
|
+
// Skip whitespace plus `//` line and `/* */` block comments.
|
|
145
|
+
function skipTrivia(r: Reader): void {
|
|
146
|
+
for (;;) {
|
|
147
|
+
const ch = r.text[r.pos]
|
|
148
|
+
if (ch === " " || ch === "\t" || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v") {
|
|
149
|
+
r.pos++
|
|
150
|
+
continue
|
|
151
|
+
}
|
|
152
|
+
if (ch === "/" && r.text[r.pos + 1] === "/") {
|
|
153
|
+
r.pos += 2
|
|
154
|
+
while (r.pos < r.text.length && r.text[r.pos] !== "\n") r.pos++
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
if (ch === "/" && r.text[r.pos + 1] === "*") {
|
|
158
|
+
r.pos += 2
|
|
159
|
+
while (r.pos < r.text.length && !(r.text[r.pos] === "*" && r.text[r.pos + 1] === "/")) r.pos++
|
|
160
|
+
if (r.pos >= r.text.length) throw new ParseFail("unterminated comment")
|
|
161
|
+
r.pos += 2
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function readValue(r: Reader): unknown {
|
|
169
|
+
const ch = r.text[r.pos]
|
|
170
|
+
if (ch === undefined) throw new ParseFail("unexpected end of input")
|
|
171
|
+
if (ch === "{") return readObject(r)
|
|
172
|
+
if (ch === "[") return readArray(r)
|
|
173
|
+
if (ch === '"' || ch === "'") return readString(r)
|
|
174
|
+
if (ch === "-" || (ch >= "0" && ch <= "9")) return readNumber(r)
|
|
175
|
+
if (matchKeyword(r, "true")) return true
|
|
176
|
+
if (matchKeyword(r, "false")) return false
|
|
177
|
+
if (matchKeyword(r, "null")) return null
|
|
178
|
+
throw new ParseFail(`unexpected token at offset ${r.pos} (only data literals are allowed)`)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function readObject(r: Reader): Record<string, unknown> {
|
|
182
|
+
if (++r.depth > MAX_DEPTH) throw new ParseFail("meta nesting too deep")
|
|
183
|
+
r.pos++ // consume `{`
|
|
184
|
+
const obj: Record<string, unknown> = {}
|
|
185
|
+
skipTrivia(r)
|
|
186
|
+
if (r.text[r.pos] === "}") {
|
|
187
|
+
r.pos++
|
|
188
|
+
r.depth--
|
|
189
|
+
return obj
|
|
190
|
+
}
|
|
191
|
+
for (;;) {
|
|
192
|
+
skipTrivia(r)
|
|
193
|
+
const key = readKey(r)
|
|
194
|
+
skipTrivia(r)
|
|
195
|
+
if (r.text[r.pos] !== ":") throw new ParseFail(`expected ':' after key '${key}' at offset ${r.pos}`)
|
|
196
|
+
r.pos++ // consume `:`
|
|
197
|
+
skipTrivia(r)
|
|
198
|
+
obj[key] = readValue(r)
|
|
199
|
+
skipTrivia(r)
|
|
200
|
+
const sep = r.text[r.pos]
|
|
201
|
+
if (sep === ",") {
|
|
202
|
+
r.pos++
|
|
203
|
+
skipTrivia(r)
|
|
204
|
+
if (r.text[r.pos] === "}") {
|
|
205
|
+
// trailing comma
|
|
206
|
+
r.pos++
|
|
207
|
+
r.depth--
|
|
208
|
+
return obj
|
|
209
|
+
}
|
|
210
|
+
continue
|
|
211
|
+
}
|
|
212
|
+
if (sep === "}") {
|
|
213
|
+
r.pos++
|
|
214
|
+
r.depth--
|
|
215
|
+
return obj
|
|
216
|
+
}
|
|
217
|
+
throw new ParseFail(`expected ',' or '}' at offset ${r.pos}`)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function readArray(r: Reader): unknown[] {
|
|
222
|
+
if (++r.depth > MAX_DEPTH) throw new ParseFail("meta nesting too deep")
|
|
223
|
+
r.pos++ // consume `[`
|
|
224
|
+
const arr: unknown[] = []
|
|
225
|
+
skipTrivia(r)
|
|
226
|
+
if (r.text[r.pos] === "]") {
|
|
227
|
+
r.pos++
|
|
228
|
+
r.depth--
|
|
229
|
+
return arr
|
|
230
|
+
}
|
|
231
|
+
for (;;) {
|
|
232
|
+
skipTrivia(r)
|
|
233
|
+
arr.push(readValue(r))
|
|
234
|
+
skipTrivia(r)
|
|
235
|
+
const sep = r.text[r.pos]
|
|
236
|
+
if (sep === ",") {
|
|
237
|
+
r.pos++
|
|
238
|
+
skipTrivia(r)
|
|
239
|
+
if (r.text[r.pos] === "]") {
|
|
240
|
+
// trailing comma
|
|
241
|
+
r.pos++
|
|
242
|
+
r.depth--
|
|
243
|
+
return arr
|
|
244
|
+
}
|
|
245
|
+
continue
|
|
246
|
+
}
|
|
247
|
+
if (sep === "]") {
|
|
248
|
+
r.pos++
|
|
249
|
+
r.depth--
|
|
250
|
+
return arr
|
|
251
|
+
}
|
|
252
|
+
throw new ParseFail(`expected ',' or ']' at offset ${r.pos}`)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Object key: an identifier (`name`, `$a`, `_b`, `a1`) or a quoted string.
|
|
257
|
+
// No computed keys (`[expr]`), no numeric keys — those aren't legitimate meta.
|
|
258
|
+
function readKey(r: Reader): string {
|
|
259
|
+
const ch = r.text[r.pos]
|
|
260
|
+
if (ch === '"' || ch === "'") return readString(r)
|
|
261
|
+
if (ch !== undefined && (/[A-Za-z_$]/.test(ch))) {
|
|
262
|
+
const startPos = r.pos
|
|
263
|
+
r.pos++
|
|
264
|
+
while (r.pos < r.text.length && /[A-Za-z0-9_$]/.test(r.text[r.pos])) r.pos++
|
|
265
|
+
return r.text.slice(startPos, r.pos)
|
|
266
|
+
}
|
|
267
|
+
throw new ParseFail(`expected a property name at offset ${r.pos}`)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function readString(r: Reader): string {
|
|
271
|
+
const quote = r.text[r.pos]
|
|
272
|
+
r.pos++ // consume opening quote
|
|
273
|
+
let out = ""
|
|
274
|
+
for (;;) {
|
|
275
|
+
const ch = r.text[r.pos]
|
|
276
|
+
if (ch === undefined || ch === "\n") throw new ParseFail("unterminated string")
|
|
277
|
+
if (ch === "\\") {
|
|
278
|
+
const esc = r.text[r.pos + 1]
|
|
279
|
+
r.pos += 2
|
|
280
|
+
if (esc === "n") out += "\n"
|
|
281
|
+
else if (esc === "t") out += "\t"
|
|
282
|
+
else if (esc === "r") out += "\r"
|
|
283
|
+
else if (esc === "b") out += "\b"
|
|
284
|
+
else if (esc === "f") out += "\f"
|
|
285
|
+
else if (esc === "v") out += "\v"
|
|
286
|
+
else if (esc === "0") out += "\0"
|
|
287
|
+
else if (esc === "u") {
|
|
288
|
+
const hex = r.text.slice(r.pos, r.pos + 4)
|
|
289
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) throw new ParseFail("invalid \\u escape")
|
|
290
|
+
out += String.fromCharCode(parseInt(hex, 16))
|
|
291
|
+
r.pos += 4
|
|
292
|
+
} else if (esc === undefined) throw new ParseFail("unterminated string")
|
|
293
|
+
else out += esc // \\ \" \' \/ and any other escaped char -> literal
|
|
294
|
+
continue
|
|
295
|
+
}
|
|
296
|
+
if (ch === quote) {
|
|
297
|
+
r.pos++
|
|
298
|
+
return out
|
|
299
|
+
}
|
|
300
|
+
out += ch
|
|
301
|
+
r.pos++
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function readNumber(r: Reader): number {
|
|
306
|
+
const startPos = r.pos
|
|
307
|
+
if (r.text[r.pos] === "-") r.pos++
|
|
308
|
+
while (r.pos < r.text.length && /[0-9]/.test(r.text[r.pos])) r.pos++
|
|
309
|
+
if (r.text[r.pos] === ".") {
|
|
310
|
+
r.pos++
|
|
311
|
+
while (r.pos < r.text.length && /[0-9]/.test(r.text[r.pos])) r.pos++
|
|
312
|
+
}
|
|
313
|
+
if (r.text[r.pos] === "e" || r.text[r.pos] === "E") {
|
|
314
|
+
r.pos++
|
|
315
|
+
if (r.text[r.pos] === "+" || r.text[r.pos] === "-") r.pos++
|
|
316
|
+
while (r.pos < r.text.length && /[0-9]/.test(r.text[r.pos])) r.pos++
|
|
317
|
+
}
|
|
318
|
+
const raw = r.text.slice(startPos, r.pos)
|
|
319
|
+
const n = Number(raw)
|
|
320
|
+
if (!Number.isFinite(n)) throw new ParseFail(`invalid number '${raw}'`)
|
|
321
|
+
return n
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Matches a bare keyword only when it is not followed by an identifier char
|
|
325
|
+
// (so `truefoo` is not read as `true`).
|
|
326
|
+
function matchKeyword(r: Reader, word: string): boolean {
|
|
327
|
+
if (r.text.startsWith(word, r.pos)) {
|
|
328
|
+
const after = r.text[r.pos + word.length]
|
|
329
|
+
if (after === undefined || !/[A-Za-z0-9_$]/.test(after)) {
|
|
330
|
+
r.pos += word.length
|
|
331
|
+
return true
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return false
|
|
335
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { Effect } from "effect"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { createHash } from "node:crypto"
|
|
4
|
+
import { appendFileSync, mkdirSync } from "node:fs"
|
|
5
|
+
import { Database, eq, desc } from "../storage"
|
|
6
|
+
import { WorkflowRunTable } from "./workflow.sql"
|
|
7
|
+
import { Global } from "../global"
|
|
8
|
+
import type { SessionID } from "../session/schema"
|
|
9
|
+
|
|
10
|
+
// Recursively sort object keys so JSON.stringify is canonical (key order in the
|
|
11
|
+
// guest's opts object must not change the content key).
|
|
12
|
+
function canonical(value: unknown): unknown {
|
|
13
|
+
if (value === null || typeof value !== "object") return value
|
|
14
|
+
if (Array.isArray(value)) return value.map(canonical)
|
|
15
|
+
return Object.fromEntries(
|
|
16
|
+
Object.keys(value as Record<string, unknown>)
|
|
17
|
+
.sort()
|
|
18
|
+
.map((k) => [k, canonical((value as Record<string, unknown>)[k])]),
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Content hash for one agent() call: sha256 over the SEMANTIC fields only
|
|
23
|
+
// (prompt + agentType/model/schema/phase). label/tools/isolation are
|
|
24
|
+
// display/dispatch only and are excluded so they never bust the cache.
|
|
25
|
+
export function journalKeyBase(prompt: string, opts: {
|
|
26
|
+
agentType?: string
|
|
27
|
+
model?: unknown
|
|
28
|
+
schema?: unknown
|
|
29
|
+
phase?: string
|
|
30
|
+
[k: string]: unknown
|
|
31
|
+
}): string {
|
|
32
|
+
const material = canonical({
|
|
33
|
+
prompt,
|
|
34
|
+
agentType: opts.agentType ?? null,
|
|
35
|
+
model: opts.model ?? null,
|
|
36
|
+
schema: opts.schema ?? null,
|
|
37
|
+
phase: opts.phase ?? null,
|
|
38
|
+
})
|
|
39
|
+
return createHash("sha256").update(JSON.stringify(material)).digest("hex")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Full journal key = content hash + ":" + occurrence index, to disambiguate
|
|
43
|
+
// byte-identical calls (e.g. N identical refuters) into distinct journal slots.
|
|
44
|
+
export function journalKey(
|
|
45
|
+
prompt: string,
|
|
46
|
+
opts: { agentType?: string; model?: unknown; schema?: unknown; phase?: string; [k: string]: unknown },
|
|
47
|
+
occ: number,
|
|
48
|
+
): string {
|
|
49
|
+
return journalKeyBase(prompt, opts) + ":" + occ
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type JournalEvent =
|
|
53
|
+
| { t: "agent"; key: string; result: unknown; pass: number }
|
|
54
|
+
| { t: "log"; msg: string; pass: number }
|
|
55
|
+
| { t: "phase"; title: string; pass: number }
|
|
56
|
+
|
|
57
|
+
export type JournalLoad = { results: Map<string, unknown>; pass: number }
|
|
58
|
+
|
|
59
|
+
export type RunSummary = {
|
|
60
|
+
runID: string
|
|
61
|
+
sessionID: SessionID
|
|
62
|
+
name: string
|
|
63
|
+
status: "running" | "completed" | "failed" | "cancelled"
|
|
64
|
+
running: number
|
|
65
|
+
succeeded: number
|
|
66
|
+
failed: number
|
|
67
|
+
currentPhase?: string
|
|
68
|
+
parentActorID?: string
|
|
69
|
+
args?: unknown
|
|
70
|
+
scriptSha?: string
|
|
71
|
+
/** The per-agent timeout this run was originally launched with (ms). Persisted
|
|
72
|
+
* so a resume that doesn't supply its own override picks the same value, instead
|
|
73
|
+
* of silently defaulting to unbounded. Undefined means the launch had no timeout. */
|
|
74
|
+
agentTimeoutMs?: number
|
|
75
|
+
error?: string
|
|
76
|
+
createdAt: number
|
|
77
|
+
updatedAt: number
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const scriptDir = () => path.join(Global.Path.data, "workflow")
|
|
81
|
+
|
|
82
|
+
// Defense in depth: persistence path functions must not trust their caller. runID
|
|
83
|
+
// is interpolated directly into a filename, so a value containing a path separator
|
|
84
|
+
// or dot-dot (`../../../etc/passwd`, `wf_../x`, an absolute path) would escape
|
|
85
|
+
// scriptDir. The HTTP route already rejects these, but resume()/journal IO are also
|
|
86
|
+
// reachable from the workflow tool and the TUI, so we re-enforce the minted shape
|
|
87
|
+
// here (`wf_` + base62 — a charset with no `.` or `/`). A throw here surfaces as an
|
|
88
|
+
// Effect defect: on the async IO paths (readScript/loadJournal) resume() captures it
|
|
89
|
+
// via Effect.exit and treats it as not-resumable; on the synchronous journal appends
|
|
90
|
+
// it fails as a defect BEFORE any appendFileSync (the caller Effect.ignore's it), so
|
|
91
|
+
// a malformed runID can never touch the filesystem.
|
|
92
|
+
// The `+` form (not the route's fixed `{26}`) is deliberate: this in-depth guard only
|
|
93
|
+
// needs the traversal-proof property (no `.`/`/`), so it stays correct even if the
|
|
94
|
+
// minted ID length changes; the strict length check lives at the route trust boundary.
|
|
95
|
+
const RUN_ID = /^wf_[0-9A-Za-z]+$/
|
|
96
|
+
const safeRunID = (runID: string) => {
|
|
97
|
+
if (!RUN_ID.test(runID)) throw new Error(`invalid workflow runID: ${JSON.stringify(runID)}`)
|
|
98
|
+
return runID
|
|
99
|
+
}
|
|
100
|
+
const scriptPath = (runID: string) => path.join(scriptDir(), `${safeRunID(runID)}.js`)
|
|
101
|
+
const journalPath = (runID: string) => path.join(scriptDir(), `${safeRunID(runID)}.jsonl`)
|
|
102
|
+
|
|
103
|
+
function toSummary(row: typeof WorkflowRunTable.$inferSelect): RunSummary {
|
|
104
|
+
return {
|
|
105
|
+
runID: row.id,
|
|
106
|
+
sessionID: row.session_id,
|
|
107
|
+
name: row.name,
|
|
108
|
+
status: row.status,
|
|
109
|
+
running: row.running,
|
|
110
|
+
succeeded: row.succeeded,
|
|
111
|
+
failed: row.failed,
|
|
112
|
+
...(row.current_phase ? { currentPhase: row.current_phase } : {}),
|
|
113
|
+
...(row.parent_actor_id ? { parentActorID: row.parent_actor_id } : {}),
|
|
114
|
+
...(row.args !== null && row.args !== undefined ? { args: row.args } : {}),
|
|
115
|
+
...(row.script_sha ? { scriptSha: row.script_sha } : {}),
|
|
116
|
+
...(row.agent_timeout_ms !== null && row.agent_timeout_ms !== undefined ? { agentTimeoutMs: row.agent_timeout_ms } : {}),
|
|
117
|
+
...(row.error ? { error: row.error } : {}),
|
|
118
|
+
createdAt: row.time_created,
|
|
119
|
+
updatedAt: row.time_updated,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const recordStart = (input: {
|
|
124
|
+
runID: string
|
|
125
|
+
sessionID: SessionID
|
|
126
|
+
name: string
|
|
127
|
+
parentActorID?: string
|
|
128
|
+
args?: unknown
|
|
129
|
+
scriptSha?: string
|
|
130
|
+
/** The per-agent timeout for this run, persisted so a subsequent resume
|
|
131
|
+
* (especially via TUI / API where the caller doesn't know the original
|
|
132
|
+
* launch parameters) can read it back instead of silently defaulting to
|
|
133
|
+
* unbounded — which would let a wedged mimo TTFT stall the run forever. */
|
|
134
|
+
agentTimeoutMs?: number
|
|
135
|
+
}) =>
|
|
136
|
+
Effect.sync(() =>
|
|
137
|
+
Database.use((db) =>
|
|
138
|
+
db
|
|
139
|
+
.insert(WorkflowRunTable)
|
|
140
|
+
.values({
|
|
141
|
+
id: input.runID,
|
|
142
|
+
session_id: input.sessionID,
|
|
143
|
+
name: input.name,
|
|
144
|
+
status: "running",
|
|
145
|
+
running: 0,
|
|
146
|
+
succeeded: 0,
|
|
147
|
+
failed: 0,
|
|
148
|
+
parent_actor_id: input.parentActorID ?? null,
|
|
149
|
+
args: input.args ?? null,
|
|
150
|
+
script_sha: input.scriptSha ?? null,
|
|
151
|
+
agent_timeout_ms: input.agentTimeoutMs ?? null,
|
|
152
|
+
})
|
|
153
|
+
// On resume the row already exists. We reset the counters AND re-stamp the
|
|
154
|
+
// script_sha: launch passes the CURRENT script's sha, so a same-script
|
|
155
|
+
// resume re-writes the identical sha (no-op) while a changed-script relaunch
|
|
156
|
+
// (the P1-2 mismatch path) overwrites the stale sha with the new one — so a
|
|
157
|
+
// SUBSEQUENT resume of the now-current script replays correctly. The sha
|
|
158
|
+
// COMPARISON happens in resume() against load()'s pre-launch value, before
|
|
159
|
+
// this overwrite runs, so re-stamping here never hides the mismatch.
|
|
160
|
+
// agent_timeout_ms is overwritten ONLY when the caller passes one (i.e. an
|
|
161
|
+
// explicit override on resume); undefined input preserves the persisted
|
|
162
|
+
// value via the COALESCE-style guard below.
|
|
163
|
+
.onConflictDoUpdate({
|
|
164
|
+
target: WorkflowRunTable.id,
|
|
165
|
+
set: {
|
|
166
|
+
status: "running",
|
|
167
|
+
running: 0,
|
|
168
|
+
succeeded: 0,
|
|
169
|
+
failed: 0,
|
|
170
|
+
script_sha: input.scriptSha ?? null,
|
|
171
|
+
...(input.agentTimeoutMs !== undefined ? { agent_timeout_ms: input.agentTimeoutMs } : {}),
|
|
172
|
+
},
|
|
173
|
+
})
|
|
174
|
+
.run(),
|
|
175
|
+
),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
const recordPhase = (input: { runID: string; phase: string }) =>
|
|
179
|
+
Effect.sync(() =>
|
|
180
|
+
Database.use((db) =>
|
|
181
|
+
db.update(WorkflowRunTable).set({ current_phase: input.phase }).where(eq(WorkflowRunTable.id, input.runID)).run(),
|
|
182
|
+
),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
const flushCounters = (input: { runID: string; running: number; succeeded: number; failed: number }) =>
|
|
186
|
+
Effect.sync(() =>
|
|
187
|
+
Database.use((db) =>
|
|
188
|
+
db
|
|
189
|
+
.update(WorkflowRunTable)
|
|
190
|
+
.set({ running: input.running, succeeded: input.succeeded, failed: input.failed })
|
|
191
|
+
.where(eq(WorkflowRunTable.id, input.runID))
|
|
192
|
+
.run(),
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
const recordTerminal = (input: { runID: string; status: "completed" | "failed" | "cancelled"; error?: string }) =>
|
|
197
|
+
Effect.sync(() =>
|
|
198
|
+
Database.use((db) =>
|
|
199
|
+
db
|
|
200
|
+
.update(WorkflowRunTable)
|
|
201
|
+
.set({ status: input.status, ...(input.error ? { error: input.error } : {}) })
|
|
202
|
+
.where(eq(WorkflowRunTable.id, input.runID))
|
|
203
|
+
.run(),
|
|
204
|
+
),
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
const list = (input?: { sessionID?: SessionID }) =>
|
|
208
|
+
Effect.sync(() =>
|
|
209
|
+
Database.use((db) => {
|
|
210
|
+
const rows = input?.sessionID
|
|
211
|
+
? db
|
|
212
|
+
.select()
|
|
213
|
+
.from(WorkflowRunTable)
|
|
214
|
+
.where(eq(WorkflowRunTable.session_id, input.sessionID))
|
|
215
|
+
.orderBy(desc(WorkflowRunTable.time_created))
|
|
216
|
+
.all()
|
|
217
|
+
: db.select().from(WorkflowRunTable).orderBy(desc(WorkflowRunTable.time_created)).all()
|
|
218
|
+
return rows.map(toSummary)
|
|
219
|
+
}),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
const load = (runID: string) =>
|
|
223
|
+
Effect.sync(() =>
|
|
224
|
+
Database.use((db) => {
|
|
225
|
+
const row = db.select().from(WorkflowRunTable).where(eq(WorkflowRunTable.id, runID)).get()
|
|
226
|
+
return row ? toSummary(row) : undefined
|
|
227
|
+
}),
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
const writeScript = (runID: string, body: string) =>
|
|
231
|
+
Effect.promise(async () => {
|
|
232
|
+
const fs = await import("fs/promises")
|
|
233
|
+
await fs.mkdir(scriptDir(), { recursive: true })
|
|
234
|
+
await Bun.write(scriptPath(runID), body)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
const readScript = (runID: string) => Effect.promise(() => Bun.file(scriptPath(runID)).text())
|
|
238
|
+
|
|
239
|
+
const appendJournal = (runID: string, event: JournalEvent) =>
|
|
240
|
+
Effect.promise(async () => {
|
|
241
|
+
const fs = await import("fs/promises")
|
|
242
|
+
await fs.mkdir(scriptDir(), { recursive: true })
|
|
243
|
+
await fs.appendFile(journalPath(runID), JSON.stringify(event) + "\n")
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
// Synchronous append (one or a batch of events). Called PER-AGENT from the
|
|
247
|
+
// agent() hook the instant a spawn succeeds, so each result is durable on disk
|
|
248
|
+
// immediately — a mid-run process exit / SIGKILL / deadline leaves a journal
|
|
249
|
+
// containing every completed agent, which is what makes resume replay them
|
|
250
|
+
// (durability does NOT wait for run completion). It is SYNCHRONOUS on purpose:
|
|
251
|
+
// an Effect.promise(async fs) append suspends the calling fiber on a macrotask,
|
|
252
|
+
// which empirically starves the quickjs sandbox pump (the guest's own promise
|
|
253
|
+
// stops being driven); a sync write completes in one scheduler slice and never
|
|
254
|
+
// yields the pump. Empty batch is a no-op (no mkdir/open). Errors propagate as a
|
|
255
|
+
// defect for Effect.ignore.
|
|
256
|
+
const appendJournalSync = (runID: string, events: JournalEvent[]) =>
|
|
257
|
+
Effect.sync(() => {
|
|
258
|
+
if (events.length === 0) return
|
|
259
|
+
mkdirSync(scriptDir(), { recursive: true })
|
|
260
|
+
appendFileSync(journalPath(runID), events.map((e) => JSON.stringify(e) + "\n").join(""))
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
const loadJournal = (runID: string): Effect.Effect<JournalLoad> =>
|
|
264
|
+
Effect.promise(async () => {
|
|
265
|
+
const file = Bun.file(journalPath(runID))
|
|
266
|
+
if (!(await file.exists())) return { results: new Map(), pass: 1 }
|
|
267
|
+
const text = await file.text()
|
|
268
|
+
const results = new Map<string, unknown>()
|
|
269
|
+
let maxPass = 0
|
|
270
|
+
for (const line of text.split("\n")) {
|
|
271
|
+
if (!line) continue
|
|
272
|
+
let ev: JournalEvent
|
|
273
|
+
try {
|
|
274
|
+
ev = JSON.parse(line) as JournalEvent
|
|
275
|
+
} catch {
|
|
276
|
+
continue // torn/partial line (crash mid-append) — skip
|
|
277
|
+
}
|
|
278
|
+
if (typeof ev.pass === "number" && ev.pass > maxPass) maxPass = ev.pass
|
|
279
|
+
if (ev.t === "agent") results.set(ev.key, ev.result)
|
|
280
|
+
}
|
|
281
|
+
return { results, pass: maxPass + 1 }
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
// Truncate the journal to empty (MR104 P1-2). Called on the resume sha-mismatch
|
|
285
|
+
// path BEFORE the fresh relaunch appends: replaying the OLD journal onto an EDITED
|
|
286
|
+
// script is silent divergence, so the stale lines must not survive — and a fresh
|
|
287
|
+
// run must not interleave its appends with them (a LATER resume's loadJournal would
|
|
288
|
+
// otherwise read both old + new → wrong replay). We truncate (write "") rather than
|
|
289
|
+
// delete so the file always exists for a concurrent reader; loadJournal treats an
|
|
290
|
+
// empty file as "no results, pass 1" exactly like a missing one. mkdir first so the
|
|
291
|
+
// truncate cannot fail on a never-written run (no journal yet → still ends empty).
|
|
292
|
+
const clearJournal = (runID: string) =>
|
|
293
|
+
Effect.promise(async () => {
|
|
294
|
+
const fs = await import("fs/promises")
|
|
295
|
+
await fs.mkdir(scriptDir(), { recursive: true })
|
|
296
|
+
await Bun.write(journalPath(runID), "")
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
export const WorkflowPersistence = {
|
|
300
|
+
recordStart,
|
|
301
|
+
recordPhase,
|
|
302
|
+
flushCounters,
|
|
303
|
+
recordTerminal,
|
|
304
|
+
list,
|
|
305
|
+
load,
|
|
306
|
+
writeScript,
|
|
307
|
+
readScript,
|
|
308
|
+
appendJournal,
|
|
309
|
+
appendJournalSync,
|
|
310
|
+
loadJournal,
|
|
311
|
+
clearJournal,
|
|
312
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
import { Filesystem } from "@/util"
|
|
3
|
+
|
|
4
|
+
// A first arg to workflow() is an inline script when it contains the mandatory
|
|
5
|
+
// meta export anywhere (real scripts may have a leading comment/whitespace);
|
|
6
|
+
// otherwise it is a bare saved-workflow name to resolve from the workflows dir.
|
|
7
|
+
const META_RE = /export\s+const\s+meta\s*=/
|
|
8
|
+
|
|
9
|
+
export function isInlineScript(nameOrScript: string): boolean {
|
|
10
|
+
return META_RE.test(nameOrScript)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Walk from `start` up to `stop` (the worktree root), checking
|
|
14
|
+
// .tulingcode/workflows/<name>.js then .claude/workflows/<name>.js at each level.
|
|
15
|
+
// First hit wins, nearest-first (project dir overrides a higher-level one) —
|
|
16
|
+
// mirrors how skills/commands resolve named user files. Returns the script body
|
|
17
|
+
// or null if no file matches (the caller turns null into a thrown, fail-loud
|
|
18
|
+
// "unknown workflow"). A bare name is constrained to a single path segment so it
|
|
19
|
+
// can never inject a separator and escape the workflows dir.
|
|
20
|
+
const SAFE_NAME = /^[A-Za-z0-9._-]+$/
|
|
21
|
+
|
|
22
|
+
export async function resolveWorkflowScript(name: string, start: string, stop: string): Promise<string | null> {
|
|
23
|
+
if (!SAFE_NAME.test(name)) throw new Error(`invalid workflow name: ${JSON.stringify(name)}`)
|
|
24
|
+
const subdirs = [".tulingcode/workflows", ".claude/workflows"]
|
|
25
|
+
for (const found of await collectUp(name, subdirs, start, stop)) {
|
|
26
|
+
return Filesystem.readText(found)
|
|
27
|
+
}
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function collectUp(name: string, subdirs: string[], start: string, stop: string): Promise<string[]> {
|
|
32
|
+
const out: string[] = []
|
|
33
|
+
let current = start
|
|
34
|
+
for (;;) {
|
|
35
|
+
for (const sub of subdirs) {
|
|
36
|
+
const candidate = path.join(current, sub, `${name}.js`)
|
|
37
|
+
if (await Filesystem.exists(candidate)) out.push(candidate)
|
|
38
|
+
}
|
|
39
|
+
if (current === stop) break
|
|
40
|
+
const parent = path.dirname(current)
|
|
41
|
+
if (parent === current) break
|
|
42
|
+
current = parent
|
|
43
|
+
}
|
|
44
|
+
return out
|
|
45
|
+
}
|