saeeol 1.2.5 → 1.2.8
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/package.json +17 -12
- package/src/ltm/config.ts +15 -15
- package/src/ltm/events.ts +1 -1
- package/src/ltm/index.ts +1 -1
- package/src/ltm/pipeline.ts +22 -22
- package/src/ltm/scheduler.ts +20 -20
- package/src/ltm/store.ts +9 -7
- package/src/ltm/types.ts +16 -16
- package/src/provider/local/embedder.ts +21 -21
- package/src/provider/models-snapshot.d.ts +2 -0
- package/src/provider/models-snapshot.js +3 -0
- package/src/session/core/session.ts +1 -39
- package/src/session/message/message-errors.ts +1 -1
- package/src/session/message/message-parts.ts +1 -1
- package/src/session/message/message-transform.ts +1 -1
- package/src/session/message/message-types.ts +1 -1
- package/src/tool/core/tool.ts +1 -1
- package/AGENTS.md +0 -72
- package/BUN_SHELL_MIGRATION_PLAN.md +0 -136
- package/Dockerfile +0 -18
- package/assets/saeeol.ico +0 -0
- package/bunfig.toml +0 -7
- package/database.db +0 -0
- package/drizzle.config.ts +0 -10
- package/git +0 -0
- package/migration/20260127222353_familiar_lady_ursula/migration.sql +0 -90
- package/migration/20260127222353_familiar_lady_ursula/snapshot.json +0 -796
- package/migration/20260211171708_add_project_commands/migration.sql +0 -1
- package/migration/20260211171708_add_project_commands/snapshot.json +0 -806
- package/migration/20260213144116_wakeful_the_professor/migration.sql +0 -11
- package/migration/20260213144116_wakeful_the_professor/snapshot.json +0 -897
- package/migration/20260225215848_workspace/migration.sql +0 -7
- package/migration/20260225215848_workspace/snapshot.json +0 -959
- package/migration/20260227213759_add_session_workspace_id/migration.sql +0 -2
- package/migration/20260227213759_add_session_workspace_id/snapshot.json +0 -983
- package/migration/20260228203230_blue_harpoon/migration.sql +0 -17
- package/migration/20260228203230_blue_harpoon/snapshot.json +0 -1102
- package/migration/20260303231226_add_workspace_fields/migration.sql +0 -5
- package/migration/20260303231226_add_workspace_fields/snapshot.json +0 -1013
- package/migration/20260309230000_move_org_to_state/migration.sql +0 -3
- package/migration/20260309230000_move_org_to_state/snapshot.json +0 -1156
- package/migration/20260312043431_session_message_cursor/migration.sql +0 -4
- package/migration/20260312043431_session_message_cursor/snapshot.json +0 -1168
- package/migration/20260323234822_events/migration.sql +0 -13
- package/migration/20260323234822_events/snapshot.json +0 -1271
- package/migration/20260410174513_workspace-name/migration.sql +0 -16
- package/migration/20260410174513_workspace-name/snapshot.json +0 -1271
- package/migration/20260413175956_chief_energizer/migration.sql +0 -13
- package/migration/20260413175956_chief_energizer/snapshot.json +0 -1399
- package/migration/20260423070820_add_icon_url_override/migration.sql +0 -2
- package/migration/20260423070820_add_icon_url_override/snapshot.json +0 -1409
- package/migration/20260428004200_add_session_path/migration.sql +0 -1
- package/migration/20260428004200_add_session_path/snapshot.json +0 -1419
- package/npm/bin/saeeol +0 -42
- package/npm/package.json +0 -39
- package/npm/postinstall.js +0 -162
- package/parsers-config.ts +0 -289
- package/script/build.ts +0 -393
- package/script/check-migrations.ts +0 -16
- package/script/fix-node-pty.ts +0 -34
- package/script/generate.ts +0 -23
- package/script/postinstall.mjs +0 -189
- package/script/publish.ts +0 -200
- package/script/run-workspace-server +0 -106
- package/script/schema.ts +0 -63
- package/script/test-runner.ts +0 -420
- package/script/time.ts +0 -6
- package/script/trace-imports.ts +0 -153
- package/script/upgrade-opentui.ts +0 -64
- package/scripts/diff-sdk-types.sh +0 -52
- package/specs/effect/facades.md +0 -221
- package/specs/effect/http-api.md +0 -401
- package/specs/effect/instance-context.md +0 -309
- package/specs/effect/loose-ends.md +0 -34
- package/specs/effect/migration.md +0 -299
- package/specs/effect/routes.md +0 -64
- package/specs/effect/schema.md +0 -399
- package/specs/effect/server-package.md +0 -668
- package/specs/effect/tools.md +0 -90
- package/specs/tui-plugins.md +0 -433
- package/specs/v2/api.ts +0 -67
- package/specs/v2/keymappings.md +0 -10
- package/specs/v2/message-shape.md +0 -136
- package/src/tool/apply_patch.txt +0 -33
- package/src/tool/bash.txt +0 -119
- package/src/tool/edit.txt +0 -10
- package/src/tool/glob.txt +0 -6
- package/src/tool/grep.txt +0 -8
- package/src/tool/lsp.txt +0 -24
- package/src/tool/plan-enter.txt +0 -14
- package/src/tool/plan-exit.txt +0 -13
- package/src/tool/question.txt +0 -11
- package/src/tool/read.txt +0 -14
- package/src/tool/recall.txt +0 -12
- package/src/tool/skill.txt +0 -5
- package/src/tool/task.txt +0 -57
- package/src/tool/todowrite.txt +0 -167
- package/src/tool/warpgrep.txt +0 -10
- package/src/tool/webfetch.txt +0 -13
- package/src/tool/websearch.txt +0 -14
- package/src/tool/write.txt +0 -8
- package/sst-env.d.ts +0 -10
- package/test/AGENTS.md +0 -133
- package/test/account/repo.test.ts +0 -352
- package/test/account/service.test.ts +0 -456
- package/test/acp/agent-interface.test.ts +0 -51
- package/test/acp/event-subscription.test.ts +0 -725
- package/test/agent/agent.test.ts +0 -890
- package/test/auth/auth.test.ts +0 -86
- package/test/bun/registry.test.ts +0 -75
- package/test/bus/bus-effect.test.ts +0 -161
- package/test/bus/bus-integration.test.ts +0 -87
- package/test/bus/bus.test.ts +0 -219
- package/test/cli/account.test.ts +0 -26
- package/test/cli/auto-mode.test.ts +0 -75
- package/test/cli/bin-saeeol.test.ts +0 -8
- package/test/cli/cmd/tui/prompt-part.test.ts +0 -47
- package/test/cli/cmd/tui/prompt-traits.test.ts +0 -38
- package/test/cli/cmd/tui/sync.test.tsx +0 -159
- package/test/cli/error.test.ts +0 -18
- package/test/cli/github-action.test.ts +0 -198
- package/test/cli/github-remote.test.ts +0 -85
- package/test/cli/import.test.ts +0 -97
- package/test/cli/install-artifact.test.ts +0 -72
- package/test/cli/plugin-auth-picker.test.ts +0 -120
- package/test/cli/pr.test.ts +0 -59
- package/test/cli/tui/editor-context-zed.test.ts +0 -356
- package/test/cli/tui/editor-context.test.tsx +0 -228
- package/test/cli/tui/keybind-plugin.test.ts +0 -90
- package/test/cli/tui/markdown.test.ts +0 -161
- package/test/cli/tui/plugin-add.test.ts +0 -111
- package/test/cli/tui/plugin-install.test.ts +0 -87
- package/test/cli/tui/plugin-lifecycle.test.ts +0 -224
- package/test/cli/tui/plugin-loader-entrypoint.test.ts +0 -484
- package/test/cli/tui/plugin-loader-pure.test.ts +0 -71
- package/test/cli/tui/plugin-loader.test.ts +0 -816
- package/test/cli/tui/plugin-toggle.test.ts +0 -157
- package/test/cli/tui/revert-diff.test.ts +0 -35
- package/test/cli/tui/slot-replace.test.tsx +0 -47
- package/test/cli/tui/theme-store.test.ts +0 -54
- package/test/cli/tui/thread.test.ts +0 -28
- package/test/cli/tui/transcript.test.ts +0 -426
- package/test/cli/tui/usage.test.ts +0 -60
- package/test/cli/tui/use-event.test.tsx +0 -175
- package/test/config/agent-color.test.ts +0 -67
- package/test/config/config.test.ts +0 -2544
- package/test/config/fixtures/empty-frontmatter.md +0 -4
- package/test/config/fixtures/frontmatter.md +0 -28
- package/test/config/fixtures/markdown-header.md +0 -11
- package/test/config/fixtures/no-frontmatter.md +0 -1
- package/test/config/fixtures/weird-model-id.md +0 -13
- package/test/config/lsp.test.ts +0 -87
- package/test/config/markdown.test.ts +0 -228
- package/test/config/plugin.test.ts +0 -0
- package/test/config/tui.test.ts +0 -624
- package/test/control-plane/adapters.test.ts +0 -71
- package/test/control-plane/workspace.test.ts +0 -1526
- package/test/effect/app-runtime-logger.test.ts +0 -98
- package/test/effect/config-service.test.ts +0 -65
- package/test/effect/instance-state.test.ts +0 -394
- package/test/effect/run-service.test.ts +0 -89
- package/test/effect/runner.test.ts +0 -523
- package/test/fake/provider.ts +0 -82
- package/test/file/fsmonitor.test.ts +0 -68
- package/test/file/ignore.test.ts +0 -10
- package/test/file/index.test.ts +0 -954
- package/test/file/path-traversal.test.ts +0 -205
- package/test/file/ripgrep.test.ts +0 -226
- package/test/file/watcher.test.ts +0 -249
- package/test/filesystem/filesystem.test.ts +0 -319
- package/test/fixture/db.ts +0 -11
- package/test/fixture/fixture.test.ts +0 -26
- package/test/fixture/fixture.ts +0 -175
- package/test/fixture/flock-worker.ts +0 -72
- package/test/fixture/log-init-worker.ts +0 -62
- package/test/fixture/lsp/fake-lsp-server.js +0 -249
- package/test/fixture/plug-worker.ts +0 -93
- package/test/fixture/plugin-meta-worker.ts +0 -19
- package/test/fixture/skills/agents-sdk/SKILL.md +0 -152
- package/test/fixture/skills/cloudflare/SKILL.md +0 -211
- package/test/fixture/skills/index.json +0 -6
- package/test/fixture/tui-plugin.ts +0 -323
- package/test/fixture/tui-runtime.ts +0 -31
- package/test/format/format.test.ts +0 -272
- package/test/git/git.test.ts +0 -128
- package/test/ide/ide.test.ts +0 -82
- package/test/installation/installation.test.ts +0 -168
- package/test/keybind.test.ts +0 -421
- package/test/lib/effect.ts +0 -53
- package/test/lib/filesystem.ts +0 -10
- package/test/lib/llm-server.ts +0 -778
- package/test/lib/websocket.ts +0 -46
- package/test/lsp/client.test.ts +0 -482
- package/test/lsp/index.test.ts +0 -160
- package/test/lsp/launch.test.ts +0 -22
- package/test/lsp/lifecycle.test.ts +0 -184
- package/test/ltm/ltm.test.ts +0 -230
- package/test/mcp/headers.test.ts +0 -178
- package/test/mcp/lifecycle.test.ts +0 -787
- package/test/mcp/oauth-auto-connect.test.ts +0 -311
- package/test/mcp/oauth-browser.test.ts +0 -276
- package/test/mcp/oauth-callback.test.ts +0 -34
- package/test/memory/abort-leak-webfetch.ts +0 -49
- package/test/memory/abort-leak.test.ts +0 -128
- package/test/patch/patch.test.ts +0 -348
- package/test/permission/arity.test.ts +0 -33
- package/test/permission/next.test.ts +0 -1227
- package/test/permission/next.toConfig.test.ts +0 -110
- package/test/permission-task.test.ts +0 -326
- package/test/plugin/auth-override.test.ts +0 -79
- package/test/plugin/cloudflare.test.ts +0 -68
- package/test/plugin/codex.test.ts +0 -123
- package/test/plugin/github-copilot-models.test.ts +0 -261
- package/test/plugin/install-concurrency.test.ts +0 -140
- package/test/plugin/install.test.ts +0 -570
- package/test/plugin/loader-shared.test.ts +0 -1169
- package/test/plugin/meta.test.ts +0 -137
- package/test/plugin/shared.test.ts +0 -88
- package/test/plugin/trigger.test.ts +0 -102
- package/test/plugin/workspace-adapter.test.ts +0 -109
- package/test/preload.ts +0 -77
- package/test/project/instance.test.ts +0 -276
- package/test/project/migrate-global.test.ts +0 -152
- package/test/project/project.test.ts +0 -600
- package/test/project/vcs.test.ts +0 -286
- package/test/project/worktree-remove.test.ts +0 -126
- package/test/project/worktree.test.ts +0 -223
- package/test/provider/amazon-bedrock.test.ts +0 -462
- package/test/provider/copilot/convert-to-copilot-messages.test.ts +0 -523
- package/test/provider/copilot/copilot-chat-model.test.ts +0 -592
- package/test/provider/gitlab-duo.test.ts +0 -413
- package/test/provider/local.test.ts +0 -208
- package/test/provider/models.test.ts +0 -261
- package/test/provider/provider-category.test.ts +0 -190
- package/test/provider/provider.test.ts +0 -2758
- package/test/provider/transform.test.ts +0 -3681
- package/test/pty/pty-output-isolation.test.ts +0 -147
- package/test/pty/pty-session.test.ts +0 -102
- package/test/pty/pty-shell.test.ts +0 -104
- package/test/question/question.test.ts +0 -490
- package/test/saeeol/agent-global-config-dirs.test.ts +0 -24
- package/test/saeeol/agent-manager-tool.test.ts +0 -71
- package/test/saeeol/agent-permission-overrides.test.ts +0 -75
- package/test/saeeol/agent-skill-permissions.test.ts +0 -37
- package/test/saeeol/ask-agent-permissions.test.ts +0 -303
- package/test/saeeol/bash-hierarchy.test.ts +0 -64
- package/test/saeeol/bash-permission-metadata.test.ts +0 -66
- package/test/saeeol/bash-security-extended.test.ts +0 -243
- package/test/saeeol/bedrock-claude-empty-content.test.ts +0 -138
- package/test/saeeol/boxes-integration.test.ts +0 -415
- package/test/saeeol/builtin-skills.test.ts +0 -75
- package/test/saeeol/cleanup.ts +0 -28
- package/test/saeeol/cli/dev-setup.test.ts +0 -74
- package/test/saeeol/cli/roll-call.test.ts +0 -161
- package/test/saeeol/cli-run-auto-helper.test.ts +0 -58
- package/test/saeeol/codex-auth-refresh.test.ts +0 -124
- package/test/saeeol/commit-message/generate.test.ts +0 -188
- package/test/saeeol/commit-message/git-context.test.ts +0 -303
- package/test/saeeol/commit-message-windows.test.ts +0 -38
- package/test/saeeol/compaction-payload-recovery.test.ts +0 -406
- package/test/saeeol/compaction-preservation-audit.test.ts +0 -122
- package/test/saeeol/compaction-skip-guard.test.ts +0 -224
- package/test/saeeol/compaction-smart-select.test.ts +0 -100
- package/test/saeeol/config/config.test.ts +0 -166
- package/test/saeeol/config/indexing-default-plugin.test.ts +0 -82
- package/test/saeeol/config/opentelemetry-default.test.ts +0 -29
- package/test/saeeol/config-gitignore.test.ts +0 -70
- package/test/saeeol/config-injector.test.ts +0 -305
- package/test/saeeol/config-resilience.test.ts +0 -234
- package/test/saeeol/config-validation.test.ts +0 -183
- package/test/saeeol/cost-propagation.test.ts +0 -94
- package/test/saeeol/cost-tracker-extended.test.ts +0 -141
- package/test/saeeol/cost-tracker.test.ts +0 -64
- package/test/saeeol/custom-provider-delete.test.ts +0 -149
- package/test/saeeol/diff-full.test.ts +0 -226
- package/test/saeeol/edit-permission-filediff.test.ts +0 -223
- package/test/saeeol/encoding.test.ts +0 -364
- package/test/saeeol/enhance-prompt.test.ts +0 -61
- package/test/saeeol/ensure-plan-dir.test.ts +0 -32
- package/test/saeeol/errors.test.ts +0 -144
- package/test/saeeol/external-directory-boundary.test.ts +0 -96
- package/test/saeeol/gateway-headers.test.ts +0 -88
- package/test/saeeol/help.test.ts +0 -191
- package/test/saeeol/ignore-migrator.test.ts +0 -308
- package/test/saeeol/indexing-auth.test.ts +0 -45
- package/test/saeeol/indexing-feature.test.ts +0 -44
- package/test/saeeol/indexing-label.test.ts +0 -70
- package/test/saeeol/indexing-startup.test.ts +0 -381
- package/test/saeeol/indexing-worktree.test.ts +0 -73
- package/test/saeeol/instruction.test.ts +0 -136
- package/test/saeeol/lancedb-runtime.test.ts +0 -116
- package/test/saeeol/loader-auth.test.ts +0 -168
- package/test/saeeol/local-model.test.ts +0 -621
- package/test/saeeol/logo.test.ts +0 -31
- package/test/saeeol/lsp-typescript-lightweight.test.ts +0 -89
- package/test/saeeol/mcp-branding.test.ts +0 -33
- package/test/saeeol/mcp-docker-rm.test.ts +0 -32
- package/test/saeeol/mcp-migrator.test.ts +0 -736
- package/test/saeeol/mcp-oauth-callback.test.ts +0 -33
- package/test/saeeol/memory-io.test.ts +0 -198
- package/test/saeeol/memory-paths.test.ts +0 -87
- package/test/saeeol/memory-security.test.ts +0 -166
- package/test/saeeol/model-cache-org.test.ts +0 -164
- package/test/saeeol/model-info-panel-utils.test.ts +0 -52
- package/test/saeeol/model-info-panel.types.test.ts +0 -7
- package/test/saeeol/models-401-fallback.test.ts +0 -52
- package/test/saeeol/modes-migrator.test.ts +0 -320
- package/test/saeeol/nvidia-headers.test.ts +0 -74
- package/test/saeeol/patch-jsonc.test.ts +0 -73
- package/test/saeeol/patch.test.ts +0 -172
- package/test/saeeol/paths.test.ts +0 -265
- package/test/saeeol/permission/config-paths.test.ts +0 -174
- package/test/saeeol/permission/env-read.test.ts +0 -149
- package/test/saeeol/permission/external-directory-allow.test.ts +0 -327
- package/test/saeeol/permission/next.always-rules.test.ts +0 -882
- package/test/saeeol/permission/next.reply-http.test.ts +0 -205
- package/test/saeeol/permission/next.reply-routing.test.ts +0 -184
- package/test/saeeol/plan-exit-detection.test.ts +0 -494
- package/test/saeeol/plan-followup.test.ts +0 -1376
- package/test/saeeol/project-config-update.test.ts +0 -120
- package/test/saeeol/project-id.test.ts +0 -455
- package/test/saeeol/provider-cost.test.ts +0 -171
- package/test/saeeol/provider-list-failed-state.test.ts +0 -100
- package/test/saeeol/question-dismiss-all.test.ts +0 -174
- package/test/saeeol/read-directory.test.ts +0 -116
- package/test/saeeol/rules-migrator.test.ts +0 -257
- package/test/saeeol/run-auto.test.ts +0 -176
- package/test/saeeol/run-network.test.ts +0 -224
- package/test/saeeol/semantic-search.test.ts +0 -186
- package/test/saeeol/server/permission-allow-everything.test.ts +0 -125
- package/test/saeeol/session/instruction-substitution.test.ts +0 -72
- package/test/saeeol/session/platform-attribution.test.ts +0 -118
- package/test/saeeol/session/session.test.ts +0 -105
- package/test/saeeol/session-compaction-cap.test.ts +0 -399
- package/test/saeeol/session-compaction-chunks.test.ts +0 -501
- package/test/saeeol/session-compaction-safety.test.ts +0 -481
- package/test/saeeol/session-fork-remap.test.ts +0 -251
- package/test/saeeol/session-import-service.test.ts +0 -114
- package/test/saeeol/session-list.test.ts +0 -47
- package/test/saeeol/session-message-metadata.test.ts +0 -128
- package/test/saeeol/session-overflow.test.ts +0 -78
- package/test/saeeol/session-processor-empty-tool-calls.test.ts +0 -571
- package/test/saeeol/session-processor-network-offline.test.ts +0 -204
- package/test/saeeol/session-processor-retry-limit.test.ts +0 -238
- package/test/saeeol/session-processor-review-telemetry.test.ts +0 -82
- package/test/saeeol/session-prompt-compaction-safety.test.ts +0 -517
- package/test/saeeol/session-prompt-queue.test.ts +0 -815
- package/test/saeeol/sessions/inflight-cache.test.ts +0 -157
- package/test/saeeol/sessions/ingest-queue.test.ts +0 -402
- package/test/saeeol/sessions/remote-protocol.test.ts +0 -258
- package/test/saeeol/sessions/remote-sender.test.ts +0 -1036
- package/test/saeeol/sessions/remote-ws.test.ts +0 -367
- package/test/saeeol/sessions/sessions-enable-remote.test.disable +0 -181
- package/test/saeeol/slot-prop-reactivity.test.ts +0 -142
- package/test/saeeol/snapshot-cache.test.ts +0 -84
- package/test/saeeol/snapshot-freeze-repro.test.ts +0 -100
- package/test/saeeol/snapshot-track-timeout.test.ts +0 -519
- package/test/saeeol/stats-subagent-cost.test.ts +0 -123
- package/test/saeeol/suggestion/auto-dismiss.test.ts +0 -65
- package/test/saeeol/suggestion/suggestion.test.ts +0 -145
- package/test/saeeol/suggestion/tool.test.ts +0 -298
- package/test/saeeol/summary-file-diff.test.ts +0 -28
- package/test/saeeol/system-prompt.test.ts +0 -142
- package/test/saeeol/task-nesting.test.ts +0 -193
- package/test/saeeol/telemetry/feedback.test.ts +0 -8
- package/test/saeeol/todo-view.test.ts +0 -57
- package/test/saeeol/tool-encoding.test.ts +0 -455
- package/test/saeeol/tool-registry-indexing-import-failure.test.ts +0 -49
- package/test/saeeol/tool-registry-indexing.test.ts +0 -236
- package/test/saeeol/tool-registry-semantic-import-failure.test.ts +0 -55
- package/test/saeeol/tool-task-model.test.ts +0 -352
- package/test/saeeol/transform-opus-4.7.test.ts +0 -89
- package/test/saeeol/tui-diff.test.ts +0 -91
- package/test/saeeol/tui-sync.test.ts +0 -80
- package/test/saeeol/util/url.test.ts +0 -141
- package/test/saeeol/workflows-migrator.test.ts +0 -261
- package/test/saeeol/worktree-diff-summary.test.ts +0 -64
- package/test/saeeol/worktree-diff.test.ts +0 -223
- package/test/saeeol/worktree-remove-lock.test.ts +0 -82
- package/test/server/AGENTS.md +0 -15
- package/test/server/contract.test.ts +0 -231
- package/test/server/experimental-session-list.test.ts +0 -157
- package/test/server/global-session-list.test.ts +0 -155
- package/test/server/httpapi-authorization.test.ts +0 -103
- package/test/server/httpapi-bridge.test.ts +0 -440
- package/test/server/httpapi-config.test.ts +0 -67
- package/test/server/httpapi-cors.test.ts +0 -89
- package/test/server/httpapi-event.test.ts +0 -57
- package/test/server/httpapi-experimental.test.ts +0 -219
- package/test/server/httpapi-file.test.ts +0 -79
- package/test/server/httpapi-instance-context.test.ts +0 -237
- package/test/server/httpapi-instance.legacy.test.ts +0 -140
- package/test/server/httpapi-instance.test.ts +0 -83
- package/test/server/httpapi-json-parity.test.ts +0 -263
- package/test/server/httpapi-mcp-oauth.test.ts +0 -76
- package/test/server/httpapi-mcp.test.ts +0 -189
- package/test/server/httpapi-provider.test.ts +0 -153
- package/test/server/httpapi-pty-websocket.test.ts +0 -16
- package/test/server/httpapi-pty.test.ts +0 -175
- package/test/server/httpapi-raw-route-auth.test.ts +0 -89
- package/test/server/httpapi-sdk.test.ts +0 -679
- package/test/server/httpapi-session.test.ts +0 -464
- package/test/server/httpapi-sync.test.ts +0 -130
- package/test/server/httpapi-tui.test.ts +0 -121
- package/test/server/httpapi-workspace-routing.test.ts +0 -471
- package/test/server/httpapi-workspace.test.ts +0 -427
- package/test/server/project-init-git.test.ts +0 -113
- package/test/server/proxy-util.test.ts +0 -113
- package/test/server/session-actions.test.ts +0 -49
- package/test/server/session-list.test.ts +0 -238
- package/test/server/session-messages.test.ts +0 -167
- package/test/server/session-select.test.ts +0 -100
- package/test/server/trace-attributes.test.ts +0 -76
- package/test/server/workspace-proxy.test.ts +0 -165
- package/test/server/workspace-routing.test.ts +0 -85
- package/test/session/compaction.test.ts +0 -2420
- package/test/session/instruction.test.ts +0 -247
- package/test/session/llm.test.ts +0 -1273
- package/test/session/message-v2.test.ts +0 -1291
- package/test/session/messages-pagination.test.ts +0 -1173
- package/test/session/network.test.ts +0 -249
- package/test/session/processor-effect.test.ts +0 -847
- package/test/session/prompt.test.ts +0 -2131
- package/test/session/retry.test.ts +0 -340
- package/test/session/revert-compact.test.ts +0 -639
- package/test/session/schema-decoding.test.ts +0 -311
- package/test/session/session-entry-stepper.test.ts +0 -917
- package/test/session/session-schema.test.ts +0 -76
- package/test/session/snapshot-tool-race.test.ts +0 -257
- package/test/session/structured-output-integration.test.ts +0 -265
- package/test/session/structured-output.test.ts +0 -381
- package/test/session/system.test.ts +0 -73
- package/test/share/share-next.test.ts +0 -333
- package/test/shell/shell.test.ts +0 -99
- package/test/skill/discovery.test.ts +0 -116
- package/test/skill/skill.test.ts +0 -393
- package/test/snapshot/snapshot.test.ts +0 -1531
- package/test/storage/db.test.ts +0 -23
- package/test/storage/json-migration.test.ts +0 -832
- package/test/storage/storage.test.ts +0 -293
- package/test/suggestion/suggestion.test.ts +0 -1
- package/test/sync/index.test.ts +0 -256
- package/test/tool/__snapshots__/parameters.test.ts.snap +0 -500
- package/test/tool/__snapshots__/tool.test.ts.snap +0 -9
- package/test/tool/apply_patch.test.ts +0 -614
- package/test/tool/bash.test.ts +0 -1225
- package/test/tool/diagnostics-filter.test.ts +0 -55
- package/test/tool/edit.test.ts +0 -754
- package/test/tool/external-directory.test.ts +0 -169
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +0 -65179
- package/test/tool/glob.test.ts +0 -107
- package/test/tool/grep.test.ts +0 -114
- package/test/tool/lsp.test.ts +0 -187
- package/test/tool/parameters.test.ts +0 -243
- package/test/tool/question.test.ts +0 -129
- package/test/tool/read.test.ts +0 -500
- package/test/tool/recall.test.ts +0 -151
- package/test/tool/registry.test.ts +0 -203
- package/test/tool/skill.test.ts +0 -135
- package/test/tool/suggest.test.ts +0 -1
- package/test/tool/task.test.ts +0 -612
- package/test/tool/tool-define.test.ts +0 -99
- package/test/tool/truncation.test.ts +0 -260
- package/test/tool/webfetch.test.ts +0 -103
- package/test/tool/write.test.ts +0 -291
- package/test/util/data-url.test.ts +0 -14
- package/test/util/effect-zod.test.ts +0 -754
- package/test/util/error.test.ts +0 -38
- package/test/util/filesystem.test.ts +0 -656
- package/test/util/format.test.ts +0 -59
- package/test/util/glob.test.ts +0 -164
- package/test/util/iife.test.ts +0 -36
- package/test/util/lazy.test.ts +0 -50
- package/test/util/lock.test.ts +0 -72
- package/test/util/log.test.ts +0 -86
- package/test/util/module.test.ts +0 -59
- package/test/util/process.test.ts +0 -128
- package/test/util/timeout.test.ts +0 -21
- package/test/util/which.test.ts +0 -100
- package/test/util/wildcard.test.ts +0 -90
- package/test/workspace/workspace-restore.test.ts +0 -296
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, test } from "bun:test"
|
|
2
|
-
import { RemoteWS } from "../../../src/sessions/remote-ws"
|
|
3
|
-
import type { ServerWebSocket } from "bun"
|
|
4
|
-
|
|
5
|
-
function nolog() {
|
|
6
|
-
return {
|
|
7
|
-
info: () => {},
|
|
8
|
-
error: () => {},
|
|
9
|
-
warn: () => {},
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function capture() {
|
|
14
|
-
const calls: unknown[][] = []
|
|
15
|
-
return {
|
|
16
|
-
calls,
|
|
17
|
-
log: {
|
|
18
|
-
info: (...args: unknown[]) => calls.push(args),
|
|
19
|
-
error: (...args: unknown[]) => calls.push(args),
|
|
20
|
-
warn: (...args: unknown[]) => calls.push(args),
|
|
21
|
-
},
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function createServer() {
|
|
26
|
-
const messages: string[] = []
|
|
27
|
-
const clients: ServerWebSocket<unknown>[] = []
|
|
28
|
-
const pending: {
|
|
29
|
-
connect: ((ws: ServerWebSocket<unknown>) => void)[]
|
|
30
|
-
message: ((msg: string) => void)[]
|
|
31
|
-
} = { connect: [], message: [] }
|
|
32
|
-
|
|
33
|
-
const server = Bun.serve({
|
|
34
|
-
port: 0,
|
|
35
|
-
fetch(req, server) {
|
|
36
|
-
const upgraded = server.upgrade(req)
|
|
37
|
-
if (!upgraded) return new Response("Not found", { status: 404 })
|
|
38
|
-
return undefined
|
|
39
|
-
},
|
|
40
|
-
websocket: {
|
|
41
|
-
open(ws) {
|
|
42
|
-
clients.push(ws)
|
|
43
|
-
const cb = pending.connect.shift()
|
|
44
|
-
cb?.(ws)
|
|
45
|
-
},
|
|
46
|
-
message(_ws, msg) {
|
|
47
|
-
const str = String(msg)
|
|
48
|
-
messages.push(str)
|
|
49
|
-
const cb = pending.message.shift()
|
|
50
|
-
cb?.(str)
|
|
51
|
-
},
|
|
52
|
-
close(ws) {
|
|
53
|
-
const idx = clients.indexOf(ws)
|
|
54
|
-
if (idx >= 0) clients.splice(idx, 1)
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
url: `ws://localhost:${server.port}`,
|
|
61
|
-
messages,
|
|
62
|
-
clients,
|
|
63
|
-
stop: () => server.stop(true),
|
|
64
|
-
waitForConnect: () =>
|
|
65
|
-
new Promise<ServerWebSocket<unknown>>((resolve) => {
|
|
66
|
-
pending.connect.push(resolve)
|
|
67
|
-
}),
|
|
68
|
-
waitForMessage: () =>
|
|
69
|
-
new Promise<string>((resolve) => {
|
|
70
|
-
pending.message.push(resolve)
|
|
71
|
-
}),
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function settled() {
|
|
76
|
-
await Bun.sleep(20)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
describe("RemoteWS", () => {
|
|
80
|
-
let server: ReturnType<typeof createServer>
|
|
81
|
-
let conn: RemoteWS.Connection | undefined
|
|
82
|
-
|
|
83
|
-
afterEach(() => {
|
|
84
|
-
conn?.close()
|
|
85
|
-
conn = undefined
|
|
86
|
-
server?.stop()
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
test("connects and sends heartbeat", async () => {
|
|
90
|
-
server = createServer()
|
|
91
|
-
const connecting = server.waitForConnect()
|
|
92
|
-
const msg = server.waitForMessage()
|
|
93
|
-
|
|
94
|
-
conn = RemoteWS.connect({
|
|
95
|
-
url: server.url,
|
|
96
|
-
getToken: async () => "tok",
|
|
97
|
-
getSessions: async () => ({ sessions: [{ id: "s1", status: "active", title: "Test" }] }),
|
|
98
|
-
log: nolog(),
|
|
99
|
-
heartbeat: 100,
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
await connecting
|
|
103
|
-
await settled()
|
|
104
|
-
expect(conn.connected).toBe(true)
|
|
105
|
-
|
|
106
|
-
const raw = await msg
|
|
107
|
-
const parsed = JSON.parse(raw)
|
|
108
|
-
expect(parsed.type).toBe("heartbeat")
|
|
109
|
-
expect(parsed.sessions).toEqual([{ id: "s1", status: "active", title: "Test" }])
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test("buffers when disconnected, flushes on reconnect", async () => {
|
|
113
|
-
server = createServer()
|
|
114
|
-
const connecting = server.waitForConnect()
|
|
115
|
-
|
|
116
|
-
conn = RemoteWS.connect({
|
|
117
|
-
url: server.url,
|
|
118
|
-
getToken: async () => "tok",
|
|
119
|
-
getSessions: async () => ({ sessions: [] }),
|
|
120
|
-
log: nolog(),
|
|
121
|
-
heartbeat: 60_000,
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
await connecting
|
|
125
|
-
await settled()
|
|
126
|
-
|
|
127
|
-
for (const ws of [...server.clients]) ws.close()
|
|
128
|
-
await Bun.sleep(50)
|
|
129
|
-
|
|
130
|
-
expect(conn.connected).toBe(false)
|
|
131
|
-
|
|
132
|
-
conn.send({ type: "event", sessionId: "s1", event: "test", data: { a: 1 } })
|
|
133
|
-
conn.send({ type: "event", sessionId: "s2", event: "test", data: { b: 2 } })
|
|
134
|
-
|
|
135
|
-
const msg1 = server.waitForMessage()
|
|
136
|
-
const msg2 = server.waitForMessage()
|
|
137
|
-
await server.waitForConnect()
|
|
138
|
-
await settled()
|
|
139
|
-
|
|
140
|
-
const r1 = JSON.parse(await msg1)
|
|
141
|
-
const r2 = JSON.parse(await msg2)
|
|
142
|
-
expect(r1.sessionId).toBe("s1")
|
|
143
|
-
expect(r2.sessionId).toBe("s2")
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
test("reconnects with backoff after server close", async () => {
|
|
147
|
-
server = createServer()
|
|
148
|
-
|
|
149
|
-
conn = RemoteWS.connect({
|
|
150
|
-
url: server.url,
|
|
151
|
-
getToken: async () => "tok",
|
|
152
|
-
getSessions: async () => ({ sessions: [] }),
|
|
153
|
-
log: nolog(),
|
|
154
|
-
heartbeat: 60_000,
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
const ws1 = await server.waitForConnect()
|
|
158
|
-
await settled()
|
|
159
|
-
|
|
160
|
-
const reconnecting = server.waitForConnect()
|
|
161
|
-
ws1.close()
|
|
162
|
-
await Bun.sleep(50)
|
|
163
|
-
|
|
164
|
-
expect(conn.connected).toBe(false)
|
|
165
|
-
|
|
166
|
-
const ws2 = await reconnecting
|
|
167
|
-
expect(ws2).toBeDefined()
|
|
168
|
-
await settled()
|
|
169
|
-
expect(conn.connected).toBe(true)
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
test("stops reconnecting on 4401", async () => {
|
|
173
|
-
server = createServer()
|
|
174
|
-
|
|
175
|
-
conn = RemoteWS.connect({
|
|
176
|
-
url: server.url,
|
|
177
|
-
getToken: async () => "tok",
|
|
178
|
-
getSessions: async () => ({ sessions: [] }),
|
|
179
|
-
log: nolog(),
|
|
180
|
-
heartbeat: 60_000,
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
const ws1 = await server.waitForConnect()
|
|
184
|
-
await settled()
|
|
185
|
-
|
|
186
|
-
ws1.close(4401, "unauthorized")
|
|
187
|
-
|
|
188
|
-
await Bun.sleep(2000)
|
|
189
|
-
|
|
190
|
-
expect(conn.connected).toBe(false)
|
|
191
|
-
expect(server.clients.length).toBe(0)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
test("onClose callback fires on permanent close", async () => {
|
|
195
|
-
server = createServer()
|
|
196
|
-
const codes: number[] = []
|
|
197
|
-
|
|
198
|
-
conn = RemoteWS.connect({
|
|
199
|
-
url: server.url,
|
|
200
|
-
getToken: async () => "tok",
|
|
201
|
-
getSessions: async () => ({ sessions: [] }),
|
|
202
|
-
log: nolog(),
|
|
203
|
-
heartbeat: 60_000,
|
|
204
|
-
onClose: (code) => codes.push(code),
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
const ws1 = await server.waitForConnect()
|
|
208
|
-
await settled()
|
|
209
|
-
|
|
210
|
-
ws1.close(4401, "unauthorized")
|
|
211
|
-
await Bun.sleep(100)
|
|
212
|
-
|
|
213
|
-
expect(codes).toEqual([4401])
|
|
214
|
-
expect(conn.connected).toBe(false)
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
test("incoming message delivered to onMessage", async () => {
|
|
218
|
-
server = createServer()
|
|
219
|
-
const received: unknown[] = []
|
|
220
|
-
const cap = capture()
|
|
221
|
-
const secret = "user secret prompt"
|
|
222
|
-
|
|
223
|
-
conn = RemoteWS.connect({
|
|
224
|
-
url: server.url,
|
|
225
|
-
getToken: async () => "tok",
|
|
226
|
-
getSessions: async () => ({ sessions: [] }),
|
|
227
|
-
log: cap.log,
|
|
228
|
-
heartbeat: 60_000,
|
|
229
|
-
onMessage: (msg) => received.push(msg),
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
const ws = await server.waitForConnect()
|
|
233
|
-
await settled()
|
|
234
|
-
|
|
235
|
-
ws.send(
|
|
236
|
-
JSON.stringify({
|
|
237
|
-
type: "command",
|
|
238
|
-
id: "c1",
|
|
239
|
-
command: "send_message",
|
|
240
|
-
sessionId: "s1",
|
|
241
|
-
data: { text: secret },
|
|
242
|
-
}),
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
await Bun.sleep(50)
|
|
246
|
-
expect(received.length).toBe(1)
|
|
247
|
-
expect(received[0]).toEqual({
|
|
248
|
-
type: "command",
|
|
249
|
-
id: "c1",
|
|
250
|
-
command: "send_message",
|
|
251
|
-
sessionId: "s1",
|
|
252
|
-
data: { text: secret },
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
const seen = JSON.stringify(cap.calls)
|
|
256
|
-
expect(seen.includes(secret)).toBe(false)
|
|
257
|
-
expect(cap.calls).toContainEqual(["remote-ws received", { bytes: expect.any(Number), type: "command", id: "c1" }])
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
test("close() prevents further reconnection and stops heartbeat", async () => {
|
|
261
|
-
server = createServer()
|
|
262
|
-
|
|
263
|
-
conn = RemoteWS.connect({
|
|
264
|
-
url: server.url,
|
|
265
|
-
getToken: async () => "tok",
|
|
266
|
-
getSessions: async () => ({ sessions: [{ id: "s1", status: "active", title: "Test" }] }),
|
|
267
|
-
log: nolog(),
|
|
268
|
-
heartbeat: 100,
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
await server.waitForConnect()
|
|
272
|
-
await settled()
|
|
273
|
-
|
|
274
|
-
// Drain initial heartbeat message(s)
|
|
275
|
-
server.messages.length = 0
|
|
276
|
-
|
|
277
|
-
conn.close()
|
|
278
|
-
conn = undefined
|
|
279
|
-
|
|
280
|
-
// Wait long enough for heartbeat and reconnect if they were still running
|
|
281
|
-
await Bun.sleep(500)
|
|
282
|
-
|
|
283
|
-
// No new connections and no new heartbeat messages
|
|
284
|
-
expect(server.clients.length).toBe(0)
|
|
285
|
-
expect(server.messages.length).toBe(0)
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
test("force-reconnects on activity timeout", async () => {
|
|
289
|
-
server = createServer()
|
|
290
|
-
const ws1 = server.waitForConnect()
|
|
291
|
-
|
|
292
|
-
conn = RemoteWS.connect({
|
|
293
|
-
url: server.url,
|
|
294
|
-
getToken: async () => "tok",
|
|
295
|
-
getSessions: async () => ({ sessions: [] }),
|
|
296
|
-
log: nolog(),
|
|
297
|
-
heartbeat: 60_000,
|
|
298
|
-
timeout: 200,
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
await ws1
|
|
302
|
-
await settled()
|
|
303
|
-
expect(conn.connected).toBe(true)
|
|
304
|
-
|
|
305
|
-
// Don't send any server messages — timeout should fire
|
|
306
|
-
const ws2 = server.waitForConnect()
|
|
307
|
-
await Bun.sleep(450)
|
|
308
|
-
|
|
309
|
-
// Should have reconnected
|
|
310
|
-
await ws2
|
|
311
|
-
await settled()
|
|
312
|
-
expect(conn.connected).toBe(true)
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
test("resets activity timer on incoming messages", async () => {
|
|
316
|
-
server = createServer()
|
|
317
|
-
const ws1p = server.waitForConnect()
|
|
318
|
-
|
|
319
|
-
conn = RemoteWS.connect({
|
|
320
|
-
url: server.url,
|
|
321
|
-
getToken: async () => "tok",
|
|
322
|
-
getSessions: async () => ({ sessions: [] }),
|
|
323
|
-
log: nolog(),
|
|
324
|
-
heartbeat: 60_000,
|
|
325
|
-
timeout: 300,
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
const ws1 = await ws1p
|
|
329
|
-
await settled()
|
|
330
|
-
|
|
331
|
-
// Send server messages at 100ms intervals — each resets the timer
|
|
332
|
-
for (let i = 0; i < 4; i++) {
|
|
333
|
-
await Bun.sleep(100)
|
|
334
|
-
ws1.send(JSON.stringify({ type: "subscribe", sessionId: `s${i}` }))
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
await settled()
|
|
338
|
-
// Connection should still be alive — activity kept resetting the timer
|
|
339
|
-
expect(conn.connected).toBe(true)
|
|
340
|
-
expect(server.clients.length).toBe(1)
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
test("activity timeout uses custom timeout option", async () => {
|
|
344
|
-
server = createServer()
|
|
345
|
-
const ws1 = server.waitForConnect()
|
|
346
|
-
|
|
347
|
-
conn = RemoteWS.connect({
|
|
348
|
-
url: server.url,
|
|
349
|
-
getToken: async () => "tok",
|
|
350
|
-
getSessions: async () => ({ sessions: [] }),
|
|
351
|
-
log: nolog(),
|
|
352
|
-
heartbeat: 60_000,
|
|
353
|
-
timeout: 100,
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
await ws1
|
|
357
|
-
await settled()
|
|
358
|
-
|
|
359
|
-
// With 100ms timeout, should reconnect faster than default 30s
|
|
360
|
-
const ws2 = server.waitForConnect()
|
|
361
|
-
await Bun.sleep(250)
|
|
362
|
-
|
|
363
|
-
await ws2
|
|
364
|
-
await settled()
|
|
365
|
-
expect(conn.connected).toBe(true)
|
|
366
|
-
})
|
|
367
|
-
})
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test"
|
|
2
|
-
import { tmpdir } from "../../fixture/fixture"
|
|
3
|
-
import { Auth } from "../../../src/auth"
|
|
4
|
-
import { Vcs } from "../../../src/project/vcs"
|
|
5
|
-
import { RemoteWS } from "../../../src/kilo-sessions/remote-ws"
|
|
6
|
-
import { RemoteSender } from "../../../src/kilo-sessions/remote-sender"
|
|
7
|
-
import { clearInFlightCache } from "../../../src/kilo-sessions/inflight-cache"
|
|
8
|
-
import { KiloSessions } from "../../../src/kilo-sessions/kilo-sessions"
|
|
9
|
-
import { Instance } from "../../../src/project/instance"
|
|
10
|
-
import { Bus } from "../../../src/bus"
|
|
11
|
-
|
|
12
|
-
const state = {
|
|
13
|
-
connects: 0,
|
|
14
|
-
closes: 0,
|
|
15
|
-
disposes: 0,
|
|
16
|
-
userStatus: 200,
|
|
17
|
-
gate: Promise.resolve(),
|
|
18
|
-
userError: false,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe("KiloSessions.enableRemote", () => {
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
state.connects = 0
|
|
24
|
-
state.closes = 0
|
|
25
|
-
state.disposes = 0
|
|
26
|
-
state.userStatus = 200
|
|
27
|
-
state.gate = Promise.resolve()
|
|
28
|
-
state.userError = false
|
|
29
|
-
process.env["KILO_DISABLE_SESSION_INGEST"] = "0"
|
|
30
|
-
delete process.env["SAEEOLCODE_SESSION_INGEST_URL"]
|
|
31
|
-
|
|
32
|
-
spyOn(Auth, "get").mockResolvedValue({ type: "api", key: "tok" } as any)
|
|
33
|
-
spyOn(Vcs, "branch").mockResolvedValue("main")
|
|
34
|
-
spyOn(RemoteWS, "connect").mockImplementation(
|
|
35
|
-
() =>
|
|
36
|
-
({
|
|
37
|
-
connectionId: `conn-${++state.connects}`,
|
|
38
|
-
send() {},
|
|
39
|
-
close() {
|
|
40
|
-
state.closes += 1
|
|
41
|
-
},
|
|
42
|
-
get connected() {
|
|
43
|
-
return true
|
|
44
|
-
},
|
|
45
|
-
}) as RemoteWS.Connection,
|
|
46
|
-
)
|
|
47
|
-
spyOn(RemoteSender, "create").mockImplementation(
|
|
48
|
-
() =>
|
|
49
|
-
({
|
|
50
|
-
handle() {},
|
|
51
|
-
dispose() {
|
|
52
|
-
state.disposes += 1
|
|
53
|
-
},
|
|
54
|
-
}) as RemoteSender.Sender,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
// Clear inflight caches so each test gets fresh Auth.get / authValid calls
|
|
58
|
-
clearInFlightCache("kilo-sessions:token")
|
|
59
|
-
clearInFlightCache("kilo-sessions:token-valid:tok")
|
|
60
|
-
|
|
61
|
-
globalThis.fetch = mock(async (input) => {
|
|
62
|
-
await state.gate
|
|
63
|
-
if (String(input).endsWith("/api/user")) {
|
|
64
|
-
if (state.userError) throw new Error("network down")
|
|
65
|
-
return new Response(null, { status: state.userStatus })
|
|
66
|
-
}
|
|
67
|
-
return new Response(null, { status: 200 })
|
|
68
|
-
}) as unknown as typeof fetch
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
afterEach(() => {
|
|
72
|
-
// Stub Bus.publish so disableRemote's fire-and-forget publish doesn't reject
|
|
73
|
-
// outside an Instance context (it needs InstanceState which requires ALS).
|
|
74
|
-
const pub = spyOn(Bus, "publish").mockResolvedValue(undefined as never)
|
|
75
|
-
KiloSessions.disableRemote()
|
|
76
|
-
pub.mockRestore()
|
|
77
|
-
mock.restore()
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test("concurrent enableRemote shares one connection", async () => {
|
|
81
|
-
await using tmp = await tmpdir({ git: true })
|
|
82
|
-
|
|
83
|
-
await Instance.provide({
|
|
84
|
-
directory: tmp.path,
|
|
85
|
-
fn: async () => {
|
|
86
|
-
await Promise.all([KiloSessions.enableRemote(), KiloSessions.enableRemote(), KiloSessions.enableRemote()])
|
|
87
|
-
expect(state.connects).toBe(1)
|
|
88
|
-
expect(KiloSessions.remoteStatus()).toEqual({ enabled: true, connected: true })
|
|
89
|
-
},
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
test("enableRemote fails when token is invalid", async () => {
|
|
94
|
-
state.userStatus = 401
|
|
95
|
-
await using tmp = await tmpdir({ git: true })
|
|
96
|
-
|
|
97
|
-
KiloSessions.disableRemote()
|
|
98
|
-
clearInFlightCache("kilo-sessions:token-valid:tok")
|
|
99
|
-
|
|
100
|
-
await Instance.provide({
|
|
101
|
-
directory: tmp.path,
|
|
102
|
-
fn: async () => {
|
|
103
|
-
await expect(KiloSessions.enableRemote()).rejects.toThrow(
|
|
104
|
-
"Unable to enable remote: invalid or expired Kilo credentials. Run `kilo auth login`.",
|
|
105
|
-
)
|
|
106
|
-
expect(state.connects).toBe(0)
|
|
107
|
-
expect(KiloSessions.remoteStatus()).toEqual({ enabled: false, connected: false })
|
|
108
|
-
},
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test("disableRemote cancels in-flight enableRemote", async () => {
|
|
113
|
-
let release = () => {}
|
|
114
|
-
state.gate = new Promise<void>((resolve) => {
|
|
115
|
-
release = resolve
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
await using tmp = await tmpdir({ git: true })
|
|
119
|
-
|
|
120
|
-
clearInFlightCache("kilo-sessions:token-valid:tok")
|
|
121
|
-
|
|
122
|
-
await Instance.provide({
|
|
123
|
-
directory: tmp.path,
|
|
124
|
-
fn: async () => {
|
|
125
|
-
const pending = KiloSessions.enableRemote()
|
|
126
|
-
KiloSessions.disableRemote()
|
|
127
|
-
release()
|
|
128
|
-
await pending
|
|
129
|
-
expect(state.connects).toBe(1)
|
|
130
|
-
expect(state.disposes).toBe(1)
|
|
131
|
-
expect(state.closes).toBe(1)
|
|
132
|
-
expect(KiloSessions.remoteStatus()).toEqual({ enabled: false, connected: false })
|
|
133
|
-
},
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test("transient auth check failure is retryable and does not connect", async () => {
|
|
138
|
-
state.userError = true
|
|
139
|
-
await using tmp = await tmpdir({ git: true })
|
|
140
|
-
|
|
141
|
-
KiloSessions.disableRemote()
|
|
142
|
-
clearInFlightCache("kilo-sessions:token-valid:tok")
|
|
143
|
-
|
|
144
|
-
await Instance.provide({
|
|
145
|
-
directory: tmp.path,
|
|
146
|
-
fn: async () => {
|
|
147
|
-
await expect(KiloSessions.enableRemote()).rejects.toThrow(
|
|
148
|
-
"Unable to enable remote: failed to verify Kilo credentials.",
|
|
149
|
-
)
|
|
150
|
-
expect(state.connects).toBe(0)
|
|
151
|
-
expect(KiloSessions.remoteStatus()).toEqual({ enabled: false, connected: false })
|
|
152
|
-
},
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
test("disable then re-enable replaces stale pending connection", async () => {
|
|
157
|
-
let release = () => {}
|
|
158
|
-
state.gate = new Promise<void>((resolve) => {
|
|
159
|
-
release = resolve
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
await using tmp = await tmpdir({ git: true })
|
|
163
|
-
|
|
164
|
-
clearInFlightCache("kilo-sessions:token-valid:tok")
|
|
165
|
-
|
|
166
|
-
await Instance.provide({
|
|
167
|
-
directory: tmp.path,
|
|
168
|
-
fn: async () => {
|
|
169
|
-
const first = KiloSessions.enableRemote()
|
|
170
|
-
KiloSessions.disableRemote()
|
|
171
|
-
const second = KiloSessions.enableRemote()
|
|
172
|
-
release()
|
|
173
|
-
await Promise.all([first, second])
|
|
174
|
-
expect(state.connects).toBe(2)
|
|
175
|
-
expect(state.disposes).toBe(1)
|
|
176
|
-
expect(state.closes).toBe(1)
|
|
177
|
-
expect(KiloSessions.remoteStatus()).toEqual({ enabled: true, connected: true })
|
|
178
|
-
},
|
|
179
|
-
})
|
|
180
|
-
})
|
|
181
|
-
})
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Regression test for the Slot wrapper in plugin/slots.tsx.
|
|
3
|
-
*
|
|
4
|
-
* This test locks in two things:
|
|
5
|
-
* 1. A static invariant: the wrapper does NOT spread raw props (`...props`),
|
|
6
|
-
* which would silently reintroduce the regression on refactors.
|
|
7
|
-
* 2. A runtime check: forwarding props through the same pattern used in
|
|
8
|
-
* slots.tsx preserves reactivity for arbitrary props (not just children).
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { describe, expect, test } from "bun:test"
|
|
12
|
-
import fs from "node:fs"
|
|
13
|
-
import path from "node:path"
|
|
14
|
-
import { children, createEffect, createRoot, createSignal, mergeProps } from "solid-js"
|
|
15
|
-
|
|
16
|
-
const SLOTS_FILE = path.resolve(import.meta.dir, "../../src/cli/cmd/tui/plugin/slots.tsx")
|
|
17
|
-
|
|
18
|
-
describe("Slot wrapper preserves prop reactivity", () => {
|
|
19
|
-
test("slots.tsx does not use `{...props}` spread to forward props", () => {
|
|
20
|
-
// Spread on a plain object in Solid evaluates every prop once and freezes
|
|
21
|
-
// it. mergeProps (or a getter per prop) is required to keep reactivity.
|
|
22
|
-
const content = fs.readFileSync(SLOTS_FILE, "utf-8")
|
|
23
|
-
const wrapper = content.match(/export const Slot[\s\S]*?^}/m)?.[0] ?? ""
|
|
24
|
-
expect(wrapper).not.toBe("")
|
|
25
|
-
expect(wrapper).not.toMatch(/\.\.\.props/)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test("slots.tsx forwards props through mergeProps (or per-prop getters)", () => {
|
|
29
|
-
const content = fs.readFileSync(SLOTS_FILE, "utf-8")
|
|
30
|
-
const wrapper = content.match(/export const Slot[\s\S]*?^}/m)?.[0] ?? ""
|
|
31
|
-
const usesMergeProps = /mergeProps\s*\(/.test(wrapper)
|
|
32
|
-
expect(usesMergeProps).toBe(true)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test("mergeProps preserves reactivity of non-children props", () => {
|
|
36
|
-
// Simulates the exact pattern used in slots.tsx: resolve children via the
|
|
37
|
-
// `children()` helper and forward the rest via mergeProps. Non-children
|
|
38
|
-
// reactive props (like `visible`, `disabled`, `ref`) must keep tracking
|
|
39
|
-
// their source signals — otherwise the slot-internal consumer (opentui
|
|
40
|
-
// registry → plugin) sees a frozen initial value.
|
|
41
|
-
const [visible, setVisible] = createSignal(true)
|
|
42
|
-
const [disabled, setDisabled] = createSignal(false)
|
|
43
|
-
const refCalls: Array<string> = []
|
|
44
|
-
const refA = () => refCalls.push("a")
|
|
45
|
-
const refB = () => refCalls.push("b")
|
|
46
|
-
const [ref, setRef] = createSignal<() => void>(refA)
|
|
47
|
-
|
|
48
|
-
const seen: Array<{ visible: boolean; disabled: boolean }> = []
|
|
49
|
-
const refSeen: Array<() => void> = []
|
|
50
|
-
|
|
51
|
-
const dispose = createRoot((dispose) => {
|
|
52
|
-
// Pretend JSX: reactive props passed into the Slot wrapper.
|
|
53
|
-
const sourceProps = {
|
|
54
|
-
get visible() {
|
|
55
|
-
return visible()
|
|
56
|
-
},
|
|
57
|
-
get disabled() {
|
|
58
|
-
return disabled()
|
|
59
|
-
},
|
|
60
|
-
get ref() {
|
|
61
|
-
return ref()
|
|
62
|
-
},
|
|
63
|
-
children: "unused",
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// This mirrors plugin/slots.tsx exactly.
|
|
67
|
-
const value = children(() => sourceProps.children)
|
|
68
|
-
const merged = mergeProps(sourceProps, {
|
|
69
|
-
get children() {
|
|
70
|
-
return value()
|
|
71
|
-
},
|
|
72
|
-
}) as typeof sourceProps
|
|
73
|
-
|
|
74
|
-
createEffect(() => {
|
|
75
|
-
seen.push({ visible: merged.visible, disabled: merged.disabled })
|
|
76
|
-
})
|
|
77
|
-
createEffect(() => {
|
|
78
|
-
refSeen.push(merged.ref)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
return dispose
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
// Initial render tracked.
|
|
85
|
-
expect(seen).toEqual([{ visible: true, disabled: false }])
|
|
86
|
-
expect(refSeen.length).toBe(1)
|
|
87
|
-
expect(refSeen[0]).toBe(refA)
|
|
88
|
-
|
|
89
|
-
// Flip the source signals — the merged view must update.
|
|
90
|
-
setVisible(false)
|
|
91
|
-
expect(seen).toEqual([
|
|
92
|
-
{ visible: true, disabled: false },
|
|
93
|
-
{ visible: false, disabled: false },
|
|
94
|
-
])
|
|
95
|
-
|
|
96
|
-
setDisabled(true)
|
|
97
|
-
expect(seen[seen.length - 1]).toEqual({ visible: false, disabled: true })
|
|
98
|
-
|
|
99
|
-
// Ref callback must also track through the wrapper — this is what makes
|
|
100
|
-
// the session prompt ref={bind} actually attach/re-attach correctly.
|
|
101
|
-
setRef(() => refB)
|
|
102
|
-
expect(refSeen.length).toBe(2)
|
|
103
|
-
expect(refSeen[1]).toBe(refB)
|
|
104
|
-
|
|
105
|
-
dispose()
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
test("plain `{...props}` spread does NOT preserve reactivity (proves the regression)", () => {
|
|
109
|
-
// Negative control: the exact bug we're guarding against. A spread into a
|
|
110
|
-
// plain object decouples the reactive source, so an effect on the copy
|
|
111
|
-
// only fires once.
|
|
112
|
-
const [visible, setVisible] = createSignal(true)
|
|
113
|
-
let fires = 0
|
|
114
|
-
|
|
115
|
-
const dispose = createRoot((dispose) => {
|
|
116
|
-
const sourceProps = {
|
|
117
|
-
get visible() {
|
|
118
|
-
return visible()
|
|
119
|
-
},
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// BUG pattern — copies the value at evaluation time.
|
|
123
|
-
const frozen = { ...sourceProps } as { visible: boolean }
|
|
124
|
-
|
|
125
|
-
createEffect(() => {
|
|
126
|
-
// Touch frozen.visible to subscribe (but it's a static property now).
|
|
127
|
-
void frozen.visible
|
|
128
|
-
fires++
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
return dispose
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
expect(fires).toBe(1)
|
|
135
|
-
setVisible(false)
|
|
136
|
-
// A correctly reactive wrapper would have fired again; the frozen copy
|
|
137
|
-
// does not. Keeping this assertion documents why mergeProps is required.
|
|
138
|
-
expect(fires).toBe(1)
|
|
139
|
-
|
|
140
|
-
dispose()
|
|
141
|
-
})
|
|
142
|
-
})
|