saeeol 1.3.0 → 1.3.1
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/.turbo/turbo-typecheck.log +1 -0
- package/AGENTS.md +72 -0
- package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
- package/Dockerfile +18 -0
- package/assets/saeeol.ico +0 -0
- package/bin/saeeol.cjs +0 -0
- package/database.db +0 -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/20260423070820_add_icon_url_override/migration.sql +2 -0
- package/migration/20260423070820_add_icon_url_override/snapshot.json +1409 -0
- package/migration/20260428004200_add_session_path/migration.sql +1 -0
- package/migration/20260428004200_add_session_path/snapshot.json +1419 -0
- package/npm/bin/saeeol +42 -0
- package/npm/package.json +39 -0
- package/npm/postinstall.js +162 -0
- package/package.json +201 -207
- package/parsers-config.ts +289 -0
- package/script/build.ts +393 -0
- package/script/check-migrations.ts +16 -0
- package/script/fix-node-pty.ts +34 -0
- package/script/generate.ts +23 -0
- package/script/postinstall.mjs +189 -0
- package/script/publish.ts +200 -0
- package/script/run-workspace-server +106 -0
- package/script/schema.ts +63 -0
- package/script/test-runner.ts +420 -0
- package/script/time.ts +6 -0
- package/script/trace-imports.ts +153 -0
- package/script/upgrade-opentui.ts +64 -0
- package/scripts/diff-sdk-types.sh +52 -0
- package/specs/effect/facades.md +221 -0
- package/specs/effect/http-api.md +401 -0
- package/specs/effect/instance-context.md +309 -0
- package/specs/effect/loose-ends.md +34 -0
- package/specs/effect/migration.md +299 -0
- package/specs/effect/routes.md +64 -0
- package/specs/effect/schema.md +399 -0
- package/specs/effect/server-package.md +668 -0
- package/specs/effect/tools.md +90 -0
- package/specs/tui-plugins.md +433 -0
- package/specs/v2/api.ts +67 -0
- package/specs/v2/keymappings.md +10 -0
- package/specs/v2/message-shape.md +136 -0
- package/src/acp/agent-message.ts +1 -1
- package/src/acp/agent-utils.ts +1 -1
- package/src/boxes/ansi.ts +17 -0
- package/src/boxes/atomic-write.ts +35 -0
- package/src/boxes/b64.ts +58 -0
- package/src/boxes/bash-security.ts +129 -0
- package/src/boxes/bom.ts +18 -0
- package/src/boxes/cancel.ts +16 -0
- package/src/boxes/chop.ts +12 -0
- package/src/boxes/clamp.ts +3 -0
- package/src/boxes/compact.ts +9 -0
- package/src/boxes/cost-tracker.ts +116 -0
- package/src/boxes/dataurl.ts +29 -0
- package/src/boxes/delay.ts +27 -0
- package/src/boxes/diff-apply.ts +53 -0
- package/src/boxes/disposable.ts +13 -0
- package/src/boxes/err.ts +34 -0
- package/src/boxes/human.ts +47 -0
- package/src/boxes/iife.ts +9 -0
- package/src/boxes/latch.ts +8 -0
- package/src/boxes/memory.ts +198 -0
- package/src/boxes/net.ts +16 -0
- package/src/boxes/plural.ts +4 -0
- package/src/boxes/puny.ts +21 -0
- package/src/boxes/retry.ts +49 -0
- package/src/boxes/rwlock.ts +41 -0
- package/src/boxes/schedule.ts +71 -0
- package/src/boxes/scope.ts +21 -0
- package/src/boxes/tokens.ts +9 -0
- package/src/boxes/ttl-cache.ts +63 -0
- package/src/boxes/typed-event.ts +51 -0
- package/src/boxes/uid.ts +50 -0
- package/src/boxes/wave6.test.ts +296 -0
- package/src/boxes/wildcard.ts +58 -0
- package/src/bus/global.ts +1 -1
- package/src/cli/cmd/github-run-api.ts +2 -2
- package/src/cli/cmd/run-events.ts +2 -2
- package/src/cli/cmd/tui/component/logo.tsx +1 -1
- package/src/cli/cmd/tui/component/prompt/use-prompt-memos.ts +2 -2
- package/src/cli/cmd/tui/context/app/editor-zed.ts +1 -1
- package/src/cli/cmd/tui/context/app/editor.ts +1 -1
- package/src/cli/cmd/tui/context/app/theme.tsx +1 -1
- package/src/cli/cmd/tui/util/revert-diff.ts +1 -1
- package/src/overlay/cli/cmd/roll-call-call.ts +1 -1
- package/src/overlay/cost-tracker/format.ts +1 -1
- package/src/overlay/cost-tracker/index.ts +4 -4
- package/src/overlay/cost-tracker/state.ts +2 -2
- package/src/overlay/cost-tracker/types.ts +2 -2
- package/src/overlay/memory/age.ts +1 -1
- package/src/overlay/memory/index.ts +4 -4
- package/src/overlay/memory/paths.ts +2 -2
- package/src/overlay/memory/scan.ts +1 -1
- package/src/overlay/memory/types.ts +2 -2
- package/src/overlay/tool/bash-security.ts +3 -3
- package/src/overlay/util/url.ts +1 -1
- package/src/plugin/codex-auth.ts +1 -1
- package/src/provider/model-cache.ts +2 -2
- package/src/provider/provider-resolve.ts +3 -3
- package/src/provider/transform-message.ts +1 -1
- package/src/server/routes/game.ts +284 -0
- package/src/server/server.ts +2 -0
- package/src/session/core/compaction/compaction-helpers.ts +1 -1
- package/src/session/core/compaction/compaction.ts +1 -1
- package/src/session/core/session.ts +2 -0
- package/src/sessions/ingest-queue.ts +2 -2
- package/src/sessions/remote-ws.ts +1 -1
- package/src/tool/workflow/question.ts +1 -1
- package/src/util/abort.ts +1 -1
- package/src/util/bom.ts +2 -2
- package/src/util/color.ts +1 -1
- package/src/util/data-url.ts +1 -1
- package/src/util/defer.ts +1 -1
- package/src/util/error.ts +2 -2
- package/src/util/filesystem.ts +2 -2
- package/src/util/format.ts +1 -1
- package/src/util/iife.ts +1 -1
- package/src/util/local-context.ts +1 -1
- package/src/util/locale.ts +2 -2
- package/src/util/lock.ts +1 -1
- package/src/util/network.ts +1 -1
- package/src/util/signal.ts +1 -1
- package/src/util/token.ts +1 -1
- package/src/util/wildcard.ts +1 -1
- 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/agent/agent.test.ts +890 -0
- package/test/auth/auth.test.ts +86 -0
- package/test/bun/registry.test.ts +75 -0
- package/test/bus/bus-effect.test.ts +161 -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/auto-mode.test.ts +75 -0
- package/test/cli/bin-saeeol.test.ts +8 -0
- package/test/cli/cmd/tui/prompt-part.test.ts +47 -0
- package/test/cli/cmd/tui/prompt-traits.test.ts +38 -0
- package/test/cli/cmd/tui/sync.test.tsx +159 -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 +85 -0
- package/test/cli/import.test.ts +97 -0
- package/test/cli/install-artifact.test.ts +72 -0
- package/test/cli/plugin-auth-picker.test.ts +120 -0
- package/test/cli/pr.test.ts +59 -0
- package/test/cli/tui/editor-context-zed.test.ts +356 -0
- package/test/cli/tui/editor-context.test.tsx +228 -0
- package/test/cli/tui/keybind-plugin.test.ts +90 -0
- package/test/cli/tui/markdown.test.ts +161 -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/slot-replace.test.tsx +47 -0
- package/test/cli/tui/theme-store.test.ts +54 -0
- package/test/cli/tui/thread.test.ts +28 -0
- package/test/cli/tui/transcript.test.ts +426 -0
- package/test/cli/tui/usage.test.ts +60 -0
- package/test/cli/tui/use-event.test.tsx +175 -0
- package/test/config/agent-color.test.ts +67 -0
- package/test/config/config.test.ts +2544 -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 +624 -0
- package/test/control-plane/adapters.test.ts +71 -0
- package/test/control-plane/workspace.test.ts +1526 -0
- package/test/effect/app-runtime-logger.test.ts +98 -0
- package/test/effect/config-service.test.ts +65 -0
- package/test/effect/instance-state.test.ts +394 -0
- package/test/effect/run-service.test.ts +89 -0
- package/test/effect/runner.test.ts +523 -0
- package/test/fake/provider.ts +82 -0
- package/test/file/fsmonitor.test.ts +68 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/file/index.test.ts +954 -0
- package/test/file/path-traversal.test.ts +205 -0
- package/test/file/ripgrep.test.ts +226 -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 +26 -0
- package/test/fixture/fixture.ts +175 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/log-init-worker.ts +62 -0
- package/test/fixture/lsp/fake-lsp-server.js +249 -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/cloudflare/SKILL.md +211 -0
- package/test/fixture/skills/index.json +6 -0
- package/test/fixture/tui-plugin.ts +323 -0
- package/test/fixture/tui-runtime.ts +31 -0
- package/test/format/format.test.ts +272 -0
- package/test/git/git.test.ts +128 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/installation/installation.test.ts +168 -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 +778 -0
- package/test/lib/websocket.ts +46 -0
- package/test/lsp/client.test.ts +482 -0
- package/test/lsp/index.test.ts +160 -0
- package/test/lsp/launch.test.ts +22 -0
- package/test/lsp/lifecycle.test.ts +184 -0
- package/test/ltm/ltm.test.ts +230 -0
- package/test/mcp/headers.test.ts +178 -0
- package/test/mcp/lifecycle.test.ts +787 -0
- package/test/mcp/oauth-auto-connect.test.ts +311 -0
- package/test/mcp/oauth-browser.test.ts +276 -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 +128 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/next.test.ts +1227 -0
- package/test/permission/next.toConfig.test.ts +110 -0
- package/test/permission-task.test.ts +326 -0
- package/test/plugin/auth-override.test.ts +79 -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 +261 -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/meta.test.ts +137 -0
- package/test/plugin/plugin-contract.test.ts +291 -0
- package/test/plugin/shared.test.ts +88 -0
- package/test/plugin/trigger.test.ts +102 -0
- package/test/plugin/workspace-adapter.test.ts +109 -0
- package/test/preload.ts +77 -0
- package/test/project/instance.test.ts +276 -0
- package/test/project/migrate-global.test.ts +152 -0
- package/test/project/project.test.ts +600 -0
- package/test/project/vcs.test.ts +286 -0
- package/test/project/worktree-remove.test.ts +126 -0
- package/test/project/worktree.test.ts +223 -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/gitlab-duo.test.ts +413 -0
- package/test/provider/local.test.ts +208 -0
- package/test/provider/models.test.ts +261 -0
- package/test/provider/provider-category.test.ts +190 -0
- package/test/provider/provider.test.ts +2758 -0
- package/test/provider/transform.test.ts +3681 -0
- package/test/pty/pty-output-isolation.test.ts +147 -0
- package/test/pty/pty-session.test.ts +102 -0
- package/test/pty/pty-shell.test.ts +104 -0
- package/test/question/question.test.ts +490 -0
- package/test/saeeol/agent-global-config-dirs.test.ts +24 -0
- package/test/saeeol/agent-manager-tool.test.ts +71 -0
- package/test/saeeol/agent-permission-overrides.test.ts +75 -0
- package/test/saeeol/agent-skill-permissions.test.ts +37 -0
- package/test/saeeol/ask-agent-permissions.test.ts +303 -0
- package/test/saeeol/bash-hierarchy.test.ts +64 -0
- package/test/saeeol/bash-permission-metadata.test.ts +66 -0
- package/test/saeeol/bash-security-extended.test.ts +243 -0
- package/test/saeeol/bedrock-claude-empty-content.test.ts +138 -0
- package/test/saeeol/boxes-integration.test.ts +415 -0
- package/test/saeeol/builtin-skills.test.ts +75 -0
- package/test/saeeol/cleanup.ts +28 -0
- package/test/saeeol/cli/dev-setup.test.ts +74 -0
- package/test/saeeol/cli/roll-call.test.ts +161 -0
- package/test/saeeol/cli-run-auto-helper.test.ts +58 -0
- package/test/saeeol/codex-auth-refresh.test.ts +124 -0
- package/test/saeeol/commit-message/generate.test.ts +188 -0
- package/test/saeeol/commit-message/git-context.test.ts +303 -0
- package/test/saeeol/commit-message-windows.test.ts +38 -0
- package/test/saeeol/compaction-payload-recovery.test.ts +406 -0
- package/test/saeeol/compaction-preservation-audit.test.ts +122 -0
- package/test/saeeol/compaction-skip-guard.test.ts +224 -0
- package/test/saeeol/compaction-smart-select.test.ts +100 -0
- package/test/saeeol/config/config.test.ts +166 -0
- package/test/saeeol/config/indexing-default-plugin.test.ts +82 -0
- package/test/saeeol/config/opentelemetry-default.test.ts +29 -0
- package/test/saeeol/config-gitignore.test.ts +70 -0
- package/test/saeeol/config-injector.test.ts +305 -0
- package/test/saeeol/config-resilience.test.ts +234 -0
- package/test/saeeol/config-validation.test.ts +183 -0
- package/test/saeeol/cost-propagation.test.ts +94 -0
- package/test/saeeol/cost-tracker-extended.test.ts +141 -0
- package/test/saeeol/cost-tracker.test.ts +64 -0
- package/test/saeeol/custom-provider-delete.test.ts +149 -0
- package/test/saeeol/diff-full.test.ts +226 -0
- package/test/saeeol/edit-permission-filediff.test.ts +223 -0
- package/test/saeeol/encoding.test.ts +364 -0
- package/test/saeeol/enhance-prompt.test.ts +61 -0
- package/test/saeeol/ensure-plan-dir.test.ts +32 -0
- package/test/saeeol/errors.test.ts +144 -0
- package/test/saeeol/external-directory-boundary.test.ts +96 -0
- package/test/saeeol/gateway-headers.test.ts +88 -0
- package/test/saeeol/help.test.ts +191 -0
- package/test/saeeol/ignore-migrator.test.ts +308 -0
- package/test/saeeol/indexing-auth.test.ts +45 -0
- package/test/saeeol/indexing-feature.test.ts +44 -0
- package/test/saeeol/indexing-label.test.ts +70 -0
- package/test/saeeol/indexing-startup.test.ts +381 -0
- package/test/saeeol/indexing-worktree.test.ts +73 -0
- package/test/saeeol/instruction.test.ts +136 -0
- package/test/saeeol/lancedb-runtime.test.ts +116 -0
- package/test/saeeol/loader-auth.test.ts +168 -0
- package/test/saeeol/local-model.test.ts +621 -0
- package/test/saeeol/logo.test.ts +31 -0
- package/test/saeeol/lsp-typescript-lightweight.test.ts +89 -0
- package/test/saeeol/mcp-branding.test.ts +33 -0
- package/test/saeeol/mcp-docker-rm.test.ts +32 -0
- package/test/saeeol/mcp-migrator.test.ts +736 -0
- package/test/saeeol/mcp-oauth-callback.test.ts +33 -0
- package/test/saeeol/memory-io.test.ts +198 -0
- package/test/saeeol/memory-paths.test.ts +87 -0
- package/test/saeeol/memory-security.test.ts +166 -0
- package/test/saeeol/model-cache-org.test.ts +164 -0
- package/test/saeeol/model-info-panel-utils.test.ts +52 -0
- package/test/saeeol/model-info-panel.types.test.ts +7 -0
- package/test/saeeol/models-401-fallback.test.ts +52 -0
- package/test/saeeol/modes-migrator.test.ts +320 -0
- package/test/saeeol/nvidia-headers.test.ts +74 -0
- package/test/saeeol/patch-jsonc.test.ts +73 -0
- package/test/saeeol/patch.test.ts +172 -0
- package/test/saeeol/paths.test.ts +265 -0
- package/test/saeeol/permission/config-paths.test.ts +174 -0
- package/test/saeeol/permission/env-read.test.ts +149 -0
- package/test/saeeol/permission/external-directory-allow.test.ts +327 -0
- package/test/saeeol/permission/next.always-rules.test.ts +882 -0
- package/test/saeeol/permission/next.reply-http.test.ts +205 -0
- package/test/saeeol/permission/next.reply-routing.test.ts +184 -0
- package/test/saeeol/plan-exit-detection.test.ts +494 -0
- package/test/saeeol/plan-followup.test.ts +1376 -0
- package/test/saeeol/project-config-update.test.ts +120 -0
- package/test/saeeol/project-id.test.ts +455 -0
- package/test/saeeol/provider-cost.test.ts +171 -0
- package/test/saeeol/provider-list-failed-state.test.ts +100 -0
- package/test/saeeol/question-dismiss-all.test.ts +174 -0
- package/test/saeeol/read-directory.test.ts +116 -0
- package/test/saeeol/rules-migrator.test.ts +257 -0
- package/test/saeeol/run-auto.test.ts +176 -0
- package/test/saeeol/run-network.test.ts +224 -0
- package/test/saeeol/semantic-search.test.ts +186 -0
- package/test/saeeol/server/permission-allow-everything.test.ts +125 -0
- package/test/saeeol/session/instruction-substitution.test.ts +72 -0
- package/test/saeeol/session/platform-attribution.test.ts +118 -0
- package/test/saeeol/session/session.test.ts +105 -0
- package/test/saeeol/session-compaction-cap.test.ts +399 -0
- package/test/saeeol/session-compaction-chunks.test.ts +501 -0
- package/test/saeeol/session-compaction-safety.test.ts +481 -0
- package/test/saeeol/session-fork-remap.test.ts +251 -0
- package/test/saeeol/session-import-service.test.ts +114 -0
- package/test/saeeol/session-list.test.ts +47 -0
- package/test/saeeol/session-message-metadata.test.ts +128 -0
- package/test/saeeol/session-overflow.test.ts +78 -0
- package/test/saeeol/session-processor-empty-tool-calls.test.ts +571 -0
- package/test/saeeol/session-processor-network-offline.test.ts +204 -0
- package/test/saeeol/session-processor-retry-limit.test.ts +238 -0
- package/test/saeeol/session-processor-review-telemetry.test.ts +82 -0
- package/test/saeeol/session-prompt-compaction-safety.test.ts +517 -0
- package/test/saeeol/session-prompt-queue.test.ts +815 -0
- package/test/saeeol/sessions/inflight-cache.test.ts +157 -0
- package/test/saeeol/sessions/ingest-queue.test.ts +402 -0
- package/test/saeeol/sessions/remote-protocol.test.ts +258 -0
- package/test/saeeol/sessions/remote-sender.test.ts +1036 -0
- package/test/saeeol/sessions/remote-ws.test.ts +367 -0
- package/test/saeeol/sessions/sessions-enable-remote.test.disable +181 -0
- package/test/saeeol/slot-prop-reactivity.test.ts +142 -0
- package/test/saeeol/snapshot-cache.test.ts +84 -0
- package/test/saeeol/snapshot-freeze-repro.test.ts +100 -0
- package/test/saeeol/snapshot-track-timeout.test.ts +519 -0
- package/test/saeeol/stats-subagent-cost.test.ts +123 -0
- package/test/saeeol/suggestion/auto-dismiss.test.ts +65 -0
- package/test/saeeol/suggestion/suggestion.test.ts +145 -0
- package/test/saeeol/suggestion/tool.test.ts +298 -0
- package/test/saeeol/summary-file-diff.test.ts +28 -0
- package/test/saeeol/system-prompt.test.ts +142 -0
- package/test/saeeol/task-nesting.test.ts +193 -0
- package/test/saeeol/telemetry/feedback.test.ts +8 -0
- package/test/saeeol/todo-view.test.ts +57 -0
- package/test/saeeol/tool-encoding.test.ts +455 -0
- package/test/saeeol/tool-registry-indexing-import-failure.test.ts +49 -0
- package/test/saeeol/tool-registry-indexing.test.ts +236 -0
- package/test/saeeol/tool-registry-semantic-import-failure.test.ts +55 -0
- package/test/saeeol/tool-task-model.test.ts +352 -0
- package/test/saeeol/transform-opus-4.7.test.ts +89 -0
- package/test/saeeol/tui-diff.test.ts +91 -0
- package/test/saeeol/tui-sync.test.ts +80 -0
- package/test/saeeol/util/url.test.ts +141 -0
- package/test/saeeol/workflows-migrator.test.ts +261 -0
- package/test/saeeol/worktree-diff-summary.test.ts +64 -0
- package/test/saeeol/worktree-diff.test.ts +223 -0
- package/test/saeeol/worktree-remove-lock.test.ts +82 -0
- package/test/server/AGENTS.md +15 -0
- package/test/server/contract.test.ts +357 -0
- package/test/server/experimental-session-list.test.ts +157 -0
- package/test/server/global-session-list.test.ts +155 -0
- package/test/server/httpapi-authorization.test.ts +103 -0
- package/test/server/httpapi-bridge.test.ts +440 -0
- package/test/server/httpapi-config.test.ts +67 -0
- package/test/server/httpapi-cors.test.ts +89 -0
- package/test/server/httpapi-event.test.ts +57 -0
- package/test/server/httpapi-experimental.test.ts +219 -0
- package/test/server/httpapi-file.test.ts +79 -0
- package/test/server/httpapi-instance-context.test.ts +237 -0
- package/test/server/httpapi-instance.legacy.test.ts +140 -0
- package/test/server/httpapi-instance.test.ts +83 -0
- package/test/server/httpapi-json-parity.test.ts +263 -0
- package/test/server/httpapi-mcp-oauth.test.ts +76 -0
- package/test/server/httpapi-mcp.test.ts +189 -0
- package/test/server/httpapi-provider.test.ts +153 -0
- package/test/server/httpapi-pty-websocket.test.ts +16 -0
- package/test/server/httpapi-pty.test.ts +175 -0
- package/test/server/httpapi-raw-route-auth.test.ts +89 -0
- package/test/server/httpapi-sdk.test.ts +681 -0
- package/test/server/httpapi-session.test.ts +464 -0
- package/test/server/httpapi-sync.test.ts +130 -0
- package/test/server/httpapi-tui.test.ts +121 -0
- package/test/server/httpapi-workspace-routing.test.ts +471 -0
- package/test/server/httpapi-workspace.test.ts +427 -0
- package/test/server/lib/conformance.ts +88 -0
- package/test/server/lib/stateful.ts +112 -0
- package/test/server/project-init-git.test.ts +113 -0
- package/test/server/proxy-util.test.ts +113 -0
- package/test/server/session-actions.test.ts +49 -0
- package/test/server/session-list.test.ts +238 -0
- package/test/server/session-messages.test.ts +167 -0
- package/test/server/session-select.test.ts +100 -0
- package/test/server/trace-attributes.test.ts +76 -0
- package/test/server/workspace-proxy.test.ts +165 -0
- package/test/server/workspace-routing.test.ts +85 -0
- package/test/session/compaction.test.ts +2420 -0
- package/test/session/instruction.test.ts +247 -0
- package/test/session/llm.test.ts +1273 -0
- package/test/session/message-v2.test.ts +1291 -0
- package/test/session/messages-pagination.test.ts +1173 -0
- package/test/session/network.test.ts +249 -0
- package/test/session/processor-effect.test.ts +847 -0
- package/test/session/prompt.test.ts +2131 -0
- package/test/session/retry.test.ts +340 -0
- package/test/session/revert-compact.test.ts +639 -0
- package/test/session/schema-decoding.test.ts +311 -0
- package/test/session/session-entry-stepper.test.ts +917 -0
- package/test/session/session-schema.test.ts +76 -0
- package/test/session/snapshot-tool-race.test.ts +257 -0
- package/test/session/structured-output-integration.test.ts +265 -0
- package/test/session/structured-output.test.ts +381 -0
- package/test/session/system.test.ts +73 -0
- package/test/share/share-next.test.ts +333 -0
- package/test/shell/shell.test.ts +99 -0
- package/test/skill/discovery.test.ts +116 -0
- package/test/skill/skill.test.ts +393 -0
- package/test/snapshot/snapshot.test.ts +1531 -0
- package/test/storage/db.test.ts +23 -0
- package/test/storage/json-migration.test.ts +832 -0
- package/test/storage/storage.test.ts +293 -0
- package/test/suggestion/suggestion.test.ts +1 -0
- package/test/sync/index.test.ts +256 -0
- package/test/tool/__snapshots__/parameters.test.ts.snap +500 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/apply_patch.test.ts +614 -0
- package/test/tool/bash.test.ts +1225 -0
- package/test/tool/diagnostics-filter.test.ts +55 -0
- package/test/tool/edit.test.ts +754 -0
- package/test/tool/external-directory.test.ts +169 -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 +107 -0
- package/test/tool/grep.test.ts +114 -0
- package/test/tool/lsp.test.ts +187 -0
- package/test/tool/parameters.test.ts +243 -0
- package/test/tool/question.test.ts +129 -0
- package/test/tool/read.test.ts +500 -0
- package/test/tool/recall.test.ts +151 -0
- package/test/tool/registry.test.ts +203 -0
- package/test/tool/skill.test.ts +135 -0
- package/test/tool/suggest.test.ts +1 -0
- package/test/tool/task.test.ts +612 -0
- package/test/tool/tool-define.test.ts +99 -0
- package/test/tool/truncation.test.ts +260 -0
- package/test/tool/webfetch.test.ts +103 -0
- package/test/tool/write.test.ts +291 -0
- package/test/util/data-url.test.ts +14 -0
- package/test/util/effect-zod.test.ts +754 -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 +86 -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/workspace/workspace-restore.test.ts +296 -0
- package/src/provider/models-snapshot.d.ts +0 -2
- package/src/provider/models-snapshot.js +0 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { fetchSaeeolModels, type SaeeolModelsResult } from "@saeeol/gateway"
|
|
2
|
-
import { TTLCache } from "
|
|
1
|
+
import { fetchSaeeolModels, type SaeeolModelsResult } from "@saeeol/gateway"
|
|
2
|
+
import { TTLCache } from "@/boxes/ttl-cache"
|
|
3
3
|
import { Config } from "../config/config"
|
|
4
4
|
import { Auth } from "../auth"
|
|
5
5
|
import * as Log from "@saeeol/core/util/log"
|
|
@@ -188,7 +188,7 @@ export async function resolveSDK(model: Model, s: State, envs: Record<string, st
|
|
|
188
188
|
void Bus.publish(ProviderInstallEvent.Started, {
|
|
189
189
|
providerID: model.providerID,
|
|
190
190
|
pkg: model.api.npm,
|
|
191
|
-
})
|
|
191
|
+
}).catch(() => {})
|
|
192
192
|
try {
|
|
193
193
|
const item = await Npm.add(model.api.npm)
|
|
194
194
|
if (!item.entrypoint) throw new Error(`Package ${model.api.npm} has no import entrypoint`)
|
|
@@ -196,13 +196,13 @@ export async function resolveSDK(model: Model, s: State, envs: Record<string, st
|
|
|
196
196
|
void Bus.publish(ProviderInstallEvent.Completed, {
|
|
197
197
|
providerID: model.providerID,
|
|
198
198
|
pkg: model.api.npm,
|
|
199
|
-
})
|
|
199
|
+
}).catch(() => {})
|
|
200
200
|
} catch (installErr) {
|
|
201
201
|
void Bus.publish(ProviderInstallEvent.Failed, {
|
|
202
202
|
providerID: model.providerID,
|
|
203
203
|
pkg: model.api.npm,
|
|
204
204
|
error: installErr instanceof Error ? installErr.message : String(installErr),
|
|
205
|
-
})
|
|
205
|
+
}).catch(() => {})
|
|
206
206
|
throw installErr
|
|
207
207
|
}
|
|
208
208
|
} else {
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { Hono } from "hono"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import { generateText } from "ai"
|
|
4
|
+
import { createOpenAI } from "@ai-sdk/openai"
|
|
5
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
|
|
6
|
+
import * as Log from "@saeeol/core/util/log"
|
|
7
|
+
import { lazy } from "@/util/lazy"
|
|
8
|
+
|
|
9
|
+
const log = Log.create({ service: "game-event" })
|
|
10
|
+
|
|
11
|
+
// ── Request schemas ──────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const GameContextSchema = z.object({
|
|
14
|
+
character: z.object({ id: z.string(), name: z.string() }).optional(),
|
|
15
|
+
stats: z.record(z.number()).optional(),
|
|
16
|
+
flags: z.record(z.any()).optional(),
|
|
17
|
+
items: z.record(z.number()).optional(),
|
|
18
|
+
route: z.string().optional(),
|
|
19
|
+
act: z.string().optional(),
|
|
20
|
+
choice_history: z.array(z.string()).optional(),
|
|
21
|
+
bosses_defeated: z.array(z.string()).optional(),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const EventSchema = z.object({
|
|
25
|
+
id: z.string().optional(),
|
|
26
|
+
lines: z.array(z.object({ speaker: z.string(), text: z.string() }).passthrough()).optional(),
|
|
27
|
+
choices: z.array(z.any()).optional(),
|
|
28
|
+
nextSceneId: z.string().optional(),
|
|
29
|
+
}).passthrough()
|
|
30
|
+
|
|
31
|
+
const BaseRequestSchema = z.object({
|
|
32
|
+
action: z.enum(["augment", "generate", "reaction"]),
|
|
33
|
+
context: GameContextSchema.optional(),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const AugmentRequestSchema = BaseRequestSchema.extend({
|
|
37
|
+
action: z.literal("augment"),
|
|
38
|
+
event: EventSchema,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const GenerateRequestSchema = BaseRequestSchema.extend({
|
|
42
|
+
action: z.literal("generate"),
|
|
43
|
+
event_id: z.string(),
|
|
44
|
+
prompt_hint: z.record(z.any()).optional(),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const ReactionRequestSchema = BaseRequestSchema.extend({
|
|
48
|
+
action: z.literal("reaction"),
|
|
49
|
+
choice_text: z.string(),
|
|
50
|
+
event: EventSchema,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const RequestSchema = z.discriminatedUnion("action", [
|
|
54
|
+
AugmentRequestSchema,
|
|
55
|
+
GenerateRequestSchema,
|
|
56
|
+
ReactionRequestSchema,
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
// ── Prompt builders ──────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
function buildSystemPrompt(hint: Record<string, any> = {}): string {
|
|
62
|
+
const tone = hint.tone ?? "몰입감 있고 생생한 묘사"
|
|
63
|
+
const themes = (hint.themes ?? []).join(", ")
|
|
64
|
+
const escalation = hint.escalation ?? ""
|
|
65
|
+
|
|
66
|
+
return `너는 에로틱 판타지 던전 크롤러 게임의 AI 내레이터다.
|
|
67
|
+
|
|
68
|
+
## 역할
|
|
69
|
+
- 플레이어의 행동과 상황에 맞는 생생한 묘사를 생성한다
|
|
70
|
+
- 캐릭터의 성격과 현재 상태(HP, 음란도, 개발도, 소지 아이템, 플래그)를 반영한다
|
|
71
|
+
- 항상 한국어로 응답한다
|
|
72
|
+
|
|
73
|
+
## 분위기
|
|
74
|
+
- 톤: ${tone}
|
|
75
|
+
- 테마: ${themes}
|
|
76
|
+
${escalation ? `- 에스컬레이션: ${escalation}` : ""}
|
|
77
|
+
|
|
78
|
+
## 응답 형식
|
|
79
|
+
항상 다음 JSON 스키마로 응답한다. 다른 텍스트는 절대 포함하지 않는다:
|
|
80
|
+
{
|
|
81
|
+
"lines": [
|
|
82
|
+
{ "speaker": "나레이션", "text": "묘사 텍스트", "ai": true }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
## 규칙
|
|
87
|
+
- lines는 1~3개
|
|
88
|
+
- 각 line의 text는 1~3문장
|
|
89
|
+
- 캐릭터 이름은 context에서 가져와서 자연스럽게 사용
|
|
90
|
+
- 현재 루트와 act의 분위기를 반영
|
|
91
|
+
- 플래그가 있으면 이전 경험을 참조
|
|
92
|
+
- 절대 JSON 이외의 텍스트를 출력하지 않는다`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildAugmentPrompt(event: any, context: any): string {
|
|
96
|
+
const charName = context?.character?.name ?? "모험자"
|
|
97
|
+
const charId = context?.character?.id ?? ""
|
|
98
|
+
const route = context?.route ?? ""
|
|
99
|
+
const flags = context?.flags ?? {}
|
|
100
|
+
const stats = context?.stats ?? {}
|
|
101
|
+
const originalLines = (event?.lines ?? []).map((l: any) => `${l.speaker}: ${l.text}`).join("\n")
|
|
102
|
+
|
|
103
|
+
return `이 이벤트에 분위기를 더하는 AI 묘사를 생성하라.
|
|
104
|
+
|
|
105
|
+
## 현재 상태
|
|
106
|
+
- 캐릭터: ${charName} (${charId})
|
|
107
|
+
- 루트: ${route}
|
|
108
|
+
- HP: ${stats.hp ?? "?"}, 음란도: ${stats.lewdness ?? "?"}, 개발도: ${stats.corruption ?? "?"}
|
|
109
|
+
- 플래그: ${JSON.stringify(flags)}
|
|
110
|
+
|
|
111
|
+
## 원본 이벤트 대사
|
|
112
|
+
${originalLines}
|
|
113
|
+
|
|
114
|
+
## 요청
|
|
115
|
+
원본 대사 앞에 들어갈 1~2줄의 분위기 묘사를 생성하라. 캐릭터의 현재 상태와 플래그를 반영하라.`
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function buildGeneratePrompt(eventId: string, context: any, hint: Record<string, any> = {}): string {
|
|
119
|
+
const charName = context?.character?.name ?? "모험자"
|
|
120
|
+
const route = context?.route ?? ""
|
|
121
|
+
const act = context?.act ?? ""
|
|
122
|
+
const stats = context?.stats ?? {}
|
|
123
|
+
const flags = context?.flags ?? {}
|
|
124
|
+
const items = context?.items ?? {}
|
|
125
|
+
const charHints = hint.character_hints ?? {}
|
|
126
|
+
const charId = context?.character?.id ?? ""
|
|
127
|
+
const charHint = charHints[charId] ?? ""
|
|
128
|
+
|
|
129
|
+
return `완전히 새로운 게임 이벤트를 생성하라.
|
|
130
|
+
|
|
131
|
+
## 이벤트 ID: ${eventId}
|
|
132
|
+
## Act: ${act}, Route: ${route}
|
|
133
|
+
|
|
134
|
+
## 캐릭터
|
|
135
|
+
- 이름: ${charName} (${charId})
|
|
136
|
+
- 성향: ${charHint}
|
|
137
|
+
- HP: ${stats.hp ?? "?"}, 음란도: ${stats.lewdness ?? "?"}, 개발도: ${stats.corruption ?? "?"}
|
|
138
|
+
|
|
139
|
+
## 소지품
|
|
140
|
+
${JSON.stringify(items)}
|
|
141
|
+
|
|
142
|
+
## 경험한 일들 (플래그)
|
|
143
|
+
${JSON.stringify(flags)}
|
|
144
|
+
|
|
145
|
+
## 요청
|
|
146
|
+
다음 JSON 스키마로 완전한 이벤트를 생성하라:
|
|
147
|
+
{
|
|
148
|
+
"id": "${eventId}",
|
|
149
|
+
"act": "${act}",
|
|
150
|
+
"lines": [
|
|
151
|
+
{ "speaker": "나레이션", "text": "...", "ai": true }
|
|
152
|
+
],
|
|
153
|
+
"choices": [
|
|
154
|
+
{ "text": "선택지 텍스트", "nextSceneId": "다음_이벤트_ID", "conditions": [], "effects": [] }
|
|
155
|
+
],
|
|
156
|
+
"nextSceneId": "기본_다음_이벤트_ID"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
2~4줄의 대사와 2~3개의 선택지를 만들어라.`
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function buildReactionPrompt(choiceText: string, event: any, context: any): string {
|
|
163
|
+
const charName = context?.character?.name ?? "모험자"
|
|
164
|
+
const stats = context?.stats ?? {}
|
|
165
|
+
|
|
166
|
+
return `플레이어가 선택을 한 직후의 반응 묘사를 생성하라.
|
|
167
|
+
|
|
168
|
+
## 선택한 것: "${choiceText}"
|
|
169
|
+
## 캐릭터: ${charName}
|
|
170
|
+
- HP: ${stats.hp ?? "?"}, 음란도: ${stats.lewdness ?? "?"}
|
|
171
|
+
|
|
172
|
+
## 요청
|
|
173
|
+
선택 직후의 짧은 반응 묘사 1~2줄을 생성하라. 캐릭터의 감정과 상황 변화를 반영하라.
|
|
174
|
+
|
|
175
|
+
JSON 형식:
|
|
176
|
+
{
|
|
177
|
+
"lines": [
|
|
178
|
+
{ "speaker": "나레이션", "text": "...", "ai": true }
|
|
179
|
+
]
|
|
180
|
+
}`
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ── LLM call ─────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
function createProvider() {
|
|
186
|
+
// Use OPENAI_API_KEY or OPENAI_BASE_URL from env
|
|
187
|
+
const apiKey = process.env.OPENAI_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? ""
|
|
188
|
+
const baseURL = process.env.OPENAI_BASE_URL
|
|
189
|
+
|
|
190
|
+
if (baseURL) {
|
|
191
|
+
return createOpenAICompatible({ name: "custom", baseURL, apiKey })
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return createOpenAI({ apiKey })
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function callLLM(systemPrompt: string, userPrompt: string): Promise<any> {
|
|
198
|
+
const provider = createProvider()
|
|
199
|
+
const modelId = process.env.GAME_LLM_MODEL ?? "gpt-4o-mini"
|
|
200
|
+
const model = provider(modelId)
|
|
201
|
+
|
|
202
|
+
const result = await generateText({
|
|
203
|
+
model,
|
|
204
|
+
system: systemPrompt,
|
|
205
|
+
prompt: userPrompt,
|
|
206
|
+
maxTokens: 1024,
|
|
207
|
+
temperature: 0.8,
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
// Extract JSON from response (handle markdown code blocks)
|
|
211
|
+
let text = result.text.trim()
|
|
212
|
+
const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/)
|
|
213
|
+
if (jsonMatch) {
|
|
214
|
+
text = jsonMatch[1].trim()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return JSON.parse(text)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ── Routes ───────────────────────────────────────────────────────
|
|
221
|
+
|
|
222
|
+
export const GameEventRoutes = lazy(() =>
|
|
223
|
+
new Hono()
|
|
224
|
+
.post(
|
|
225
|
+
"/event",
|
|
226
|
+
async (c) => {
|
|
227
|
+
const body = await c.req.json()
|
|
228
|
+
const parsed = RequestSchema.safeParse(body)
|
|
229
|
+
|
|
230
|
+
if (!parsed.success) {
|
|
231
|
+
return c.json({ error: "Invalid request", details: parsed.error.flatten() }, 400)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const req = parsed.data
|
|
235
|
+
const context = req.context ?? {}
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
switch (req.action) {
|
|
239
|
+
case "augment": {
|
|
240
|
+
const hint: Record<string, any> = {}
|
|
241
|
+
const systemPrompt = buildSystemPrompt(hint)
|
|
242
|
+
const userPrompt = buildAugmentPrompt(req.event, context)
|
|
243
|
+
|
|
244
|
+
const result = await callLLM(systemPrompt, userPrompt)
|
|
245
|
+
|
|
246
|
+
// Merge AI lines into original event
|
|
247
|
+
const aiLines: any[] = result.lines ?? []
|
|
248
|
+
const originalLines: any[] = req.event?.lines ?? []
|
|
249
|
+
const merged = {
|
|
250
|
+
...req.event,
|
|
251
|
+
lines: [...aiLines, ...originalLines],
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
log.info("augment event", { id: req.event?.id, aiLines: aiLines.length })
|
|
255
|
+
return c.json(merged)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
case "generate": {
|
|
259
|
+
const hint = req.prompt_hint ?? {}
|
|
260
|
+
const systemPrompt = buildSystemPrompt(hint)
|
|
261
|
+
const userPrompt = buildGeneratePrompt(req.event_id, context, hint)
|
|
262
|
+
|
|
263
|
+
const result = await callLLM(systemPrompt, userPrompt)
|
|
264
|
+
log.info("generate event", { id: req.event_id })
|
|
265
|
+
return c.json(result)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
case "reaction": {
|
|
269
|
+
const hint: Record<string, any> = {}
|
|
270
|
+
const systemPrompt = buildSystemPrompt(hint)
|
|
271
|
+
const userPrompt = buildReactionPrompt(req.choice_text, req.event, context)
|
|
272
|
+
|
|
273
|
+
const result = await callLLM(systemPrompt, userPrompt)
|
|
274
|
+
log.info("reaction", { choice: req.choice_text })
|
|
275
|
+
return c.json(result)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} catch (err: any) {
|
|
279
|
+
log.error("game event failed", { error: err.message })
|
|
280
|
+
return c.json({ error: err.message }, 500)
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
),
|
|
284
|
+
)
|
package/src/server/server.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { InstanceRoutes } from "./routes/instance"
|
|
|
13
13
|
import { ControlPlaneRoutes } from "./routes/control"
|
|
14
14
|
import { UIRoutes } from "./routes/ui"
|
|
15
15
|
import { GlobalRoutes } from "./routes/global"
|
|
16
|
+
import { GameEventRoutes } from "./routes/game"
|
|
16
17
|
import { WorkspaceRouterMiddleware } from "./workspace"
|
|
17
18
|
import { InstanceMiddleware } from "./routes/instance/middleware"
|
|
18
19
|
import { WorkspaceRoutes } from "./routes/control/workspace"
|
|
@@ -106,6 +107,7 @@ function createHono(opts: CorsOptions, selection: ServerBackend.Selection = Serv
|
|
|
106
107
|
.use(CompressionMiddleware)
|
|
107
108
|
.use(CorsMiddleware(opts))
|
|
108
109
|
.route("/global", GlobalRoutes())
|
|
110
|
+
.route("/api", GameEventRoutes())
|
|
109
111
|
|
|
110
112
|
const runtime = adapter.create(app)
|
|
111
113
|
|
|
@@ -317,7 +317,9 @@ export const getUsage = (input: {
|
|
|
317
317
|
input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ??
|
|
318
318
|
// google-vertex-anthropic returns metadata under "vertex" key
|
|
319
319
|
input.metadata?.["vertex"]?.["cacheCreationInputTokens"] ??
|
|
320
|
+
// @ts-expect-error
|
|
320
321
|
input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ??
|
|
322
|
+
// @ts-expect-error
|
|
321
323
|
input.metadata?.["venice"]?.["usage"]?.["cacheCreationInputTokens"] ??
|
|
322
324
|
0,
|
|
323
325
|
),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ulid } from "ulid"
|
|
1
|
+
import { ulid } from "ulid"
|
|
2
2
|
import type * as SDK from "@saeeol/sdk/v2"
|
|
3
3
|
import type { SaeeolSession } from "@/saeeol/session"
|
|
4
|
-
import { expDelay } from "
|
|
4
|
+
import { expDelay } from "@/boxes/schedule"
|
|
5
5
|
|
|
6
6
|
export namespace IngestQueue {
|
|
7
7
|
export type Client = {
|
package/src/util/abort.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { cancelAfter as abortAfter, cancelAny as abortAfterAny } from "
|
|
1
|
+
export { cancelAfter as abortAfter, cancelAny as abortAfterAny } from "@/boxes/cancel"
|
package/src/util/bom.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { split, join } from "
|
|
1
|
+
export { split, join } from "@/boxes/bom"
|
|
2
2
|
import { Effect } from "effect"
|
|
3
3
|
import { AppFileSystem } from "@saeeol/core/filesystem"
|
|
4
|
-
import { split, join } from "
|
|
4
|
+
import { split, join } from "@/boxes/bom"
|
|
5
5
|
|
|
6
6
|
export const readFile = Effect.fn("Bom.readFile")(function* (fs: AppFileSystem.Interface, filePath: string) {
|
|
7
7
|
return split(new TextDecoder("utf-8", { ignoreBOM: true }).decode(yield* fs.readFile(filePath)))
|
package/src/util/color.ts
CHANGED
package/src/util/data-url.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { decode as decodeDataUrl } from "
|
|
1
|
+
export { decode as decodeDataUrl } from "@/boxes/dataurl"
|
package/src/util/defer.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { disposable as defer } from "
|
|
1
|
+
export { disposable as defer } from "@/boxes/disposable"
|
package/src/util/error.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { msg as errorMessage, fmt as errorFormat } from "
|
|
2
|
-
import { msg as errorMessage, fmt as errorFormat } from "
|
|
1
|
+
export { msg as errorMessage, fmt as errorFormat } from "@/boxes/err"
|
|
2
|
+
import { msg as errorMessage, fmt as errorFormat } from "@/boxes/err"
|
|
3
3
|
import { isRecord } from "./record"
|
|
4
4
|
|
|
5
5
|
export function errorData(error: unknown) {
|
package/src/util/filesystem.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { chmod, mkdir, readFile, stat as statFile, writeFile } from "fs/promises"
|
|
2
|
-
import { atomicWrite } from "
|
|
1
|
+
import { chmod, mkdir, readFile, stat as statFile, writeFile } from "fs/promises"
|
|
2
|
+
import { atomicWrite } from "@/boxes/atomic-write"
|
|
3
3
|
import { createWriteStream, existsSync, statSync } from "fs"
|
|
4
4
|
import { realpathSync } from "fs"
|
|
5
5
|
import { dirname, isAbsolute, join, relative, resolve as pathResolve, sep, win32 } from "path"
|
package/src/util/format.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { secsDuration as formatDuration } from "
|
|
1
|
+
export { secsDuration as formatDuration } from "@/boxes/human"
|
package/src/util/iife.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { iife } from "
|
|
1
|
+
export { iife } from "@/boxes/iife"
|
package/src/util/locale.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { time, datetime } from "
|
|
2
|
-
export { title as titlecase, time, datetime, compact as number, duration, truncate, truncateMid as truncateMiddle, plural as pluralize } from "
|
|
1
|
+
import { time, datetime } from "@/boxes/human"
|
|
2
|
+
export { title as titlecase, time, datetime, compact as number, duration, truncate, truncateMid as truncateMiddle, plural as pluralize } from "@/boxes/human"
|
|
3
3
|
|
|
4
4
|
export function todayTimeOrDateTime(input: number): string {
|
|
5
5
|
const date = new Date(input)
|
package/src/util/lock.ts
CHANGED
package/src/util/network.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { online, proxied } from "
|
|
1
|
+
export { online, proxied } from "@/boxes/net"
|
package/src/util/signal.ts
CHANGED
package/src/util/token.ts
CHANGED
package/src/util/wildcard.ts
CHANGED
package/sst-env.d.ts
ADDED
package/test/AGENTS.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Test Fixtures Guide
|
|
2
|
+
|
|
3
|
+
## Temporary Directory Fixture
|
|
4
|
+
|
|
5
|
+
The `tmpdir` function in `fixture/fixture.ts` creates temporary directories for tests with automatic cleanup.
|
|
6
|
+
|
|
7
|
+
### Basic Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { tmpdir } from "./fixture/fixture"
|
|
11
|
+
|
|
12
|
+
test("example", async () => {
|
|
13
|
+
await using tmp = await tmpdir()
|
|
14
|
+
// tmp.path is the temp directory path
|
|
15
|
+
// automatically cleaned up when test ends
|
|
16
|
+
})
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Options
|
|
20
|
+
|
|
21
|
+
- `git?: boolean` - Initialize a git repo with a root commit
|
|
22
|
+
- `config?: Partial<Config.Info>` - Write an `saeeol.json` config file
|
|
23
|
+
- `init?: (dir: string) => Promise<T>` - Custom setup function, returns value accessible as `tmp.extra`
|
|
24
|
+
- `dispose?: (dir: string) => Promise<T>` - Custom cleanup function
|
|
25
|
+
|
|
26
|
+
### Examples
|
|
27
|
+
|
|
28
|
+
**Git repository:**
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
await using tmp = await tmpdir({ git: true })
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**With config file:**
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
await using tmp = await tmpdir({
|
|
38
|
+
config: { model: "test/model", username: "testuser" },
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Custom initialization (returns extra data):**
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
await using tmp = await tmpdir<string>({
|
|
46
|
+
init: async (dir) => {
|
|
47
|
+
await Bun.write(path.join(dir, "file.txt"), "content")
|
|
48
|
+
return "extra data"
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
// Access extra data via tmp.extra
|
|
52
|
+
console.log(tmp.extra) // "extra data"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**With cleanup:**
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
await using tmp = await tmpdir({
|
|
59
|
+
init: async (dir) => {
|
|
60
|
+
const specialDir = path.join(dir, "special")
|
|
61
|
+
await fs.mkdir(specialDir)
|
|
62
|
+
return specialDir
|
|
63
|
+
},
|
|
64
|
+
dispose: async (dir) => {
|
|
65
|
+
// Custom cleanup logic
|
|
66
|
+
await fs.rm(path.join(dir, "special"), { recursive: true })
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Returned Object
|
|
72
|
+
|
|
73
|
+
- `path: string` - Absolute path to the temp directory (realpath resolved)
|
|
74
|
+
- `extra: T` - Value returned by the `init` function
|
|
75
|
+
- `[Symbol.asyncDispose]` - Enables automatic cleanup via `await using`
|
|
76
|
+
|
|
77
|
+
### Notes
|
|
78
|
+
|
|
79
|
+
- Directories are created in the system temp folder with prefix `saeeol-test-`
|
|
80
|
+
- Use `await using` for automatic cleanup when the variable goes out of scope
|
|
81
|
+
- Paths are sanitized to strip null bytes (defensive fix for CI environments)
|
|
82
|
+
|
|
83
|
+
## Testing With Effects
|
|
84
|
+
|
|
85
|
+
Use `testEffect(...)` from `test/lib/effect.ts` for tests that exercise Effect services or Effect-based workflows.
|
|
86
|
+
|
|
87
|
+
### Core Pattern
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { describe, expect } from "bun:test"
|
|
91
|
+
import { Effect, Layer } from "effect"
|
|
92
|
+
import { provideTmpdirInstance } from "../fixture/fixture"
|
|
93
|
+
import { testEffect } from "../lib/effect"
|
|
94
|
+
|
|
95
|
+
const it = testEffect(Layer.mergeAll(MyService.defaultLayer))
|
|
96
|
+
|
|
97
|
+
describe("my service", () => {
|
|
98
|
+
it.live("does the thing", () =>
|
|
99
|
+
provideTmpdirInstance(() =>
|
|
100
|
+
Effect.gen(function* () {
|
|
101
|
+
const svc = yield* MyService.Service
|
|
102
|
+
const out = yield* svc.run()
|
|
103
|
+
expect(out).toEqual("ok")
|
|
104
|
+
}),
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### `it.effect` vs `it.live`
|
|
111
|
+
|
|
112
|
+
- Use `it.effect(...)` when the test should run with `TestClock` and `TestConsole`.
|
|
113
|
+
- Use `it.live(...)` when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.
|
|
114
|
+
- Most integration-style tests in this package use `it.live(...)`.
|
|
115
|
+
|
|
116
|
+
### Effect Fixtures
|
|
117
|
+
|
|
118
|
+
Prefer the Effect-aware helpers from `fixture/fixture.ts` instead of building a manual runtime in each test.
|
|
119
|
+
|
|
120
|
+
- `tmpdirScoped(options?)` creates a scoped temp directory and cleans it up when the Effect scope closes.
|
|
121
|
+
- `provideInstance(dir)(effect)` is the low-level helper. It does not create a directory; it just runs an Effect with `Instance.current` bound to `dir`.
|
|
122
|
+
- `provideTmpdirInstance((dir) => effect, options?)` is the convenience helper. It creates a temp directory, binds it as the active instance, and disposes the instance on cleanup.
|
|
123
|
+
- `provideTmpdirServer((input) => effect, options?)` does the same, but also provides the test LLM server.
|
|
124
|
+
|
|
125
|
+
Use `provideTmpdirInstance(...)` by default when a test only needs one temp instance. Use `tmpdirScoped()` plus `provideInstance(...)` when a test needs multiple directories, custom setup before binding, or needs to switch instance context within one test.
|
|
126
|
+
|
|
127
|
+
### Style
|
|
128
|
+
|
|
129
|
+
- Define `const it = testEffect(...)` near the top of the file.
|
|
130
|
+
- Keep the test body inside `Effect.gen(function* () { ... })`.
|
|
131
|
+
- Yield services directly with `yield* MyService.Service` or `yield* MyTool`.
|
|
132
|
+
- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers when `testEffect(...)` already provides the runtime.
|
|
133
|
+
- When a test needs instance-local state, prefer `provideTmpdirInstance(...)` or `provideInstance(...)` over manual `Instance.provide(...)` inside Promise-style tests.
|