@build-astron-co/nimbus 0.4.1 → 0.4.3
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/CHANGELOG.md +268 -89
- package/README.md +26 -567
- package/dist/src/agent/compaction-agent.js +24 -12
- package/dist/src/agent/context-manager.js +2 -1
- package/dist/src/agent/expand-files.js +2 -1
- package/dist/src/agent/loop.js +71 -33
- package/dist/src/agent/permissions.js +4 -2
- package/dist/src/agent/system-prompt.js +34 -17
- package/dist/src/app.js +1 -1
- package/dist/src/auth/keychain.js +8 -4
- package/dist/src/auth/store.js +70 -107
- package/dist/src/cli/init.js +35 -19
- package/dist/src/cli/run.js +18 -10
- package/dist/src/cli/serve.js +4 -2
- package/dist/src/cli.js +52 -11
- package/dist/src/commands/alias.js +5 -3
- package/dist/src/commands/audit/index.js +2 -1
- package/dist/src/commands/aws-terraform.js +36 -18
- package/dist/src/commands/completions.js +1 -1
- package/dist/src/commands/config.js +3 -2
- package/dist/src/commands/connect-github.js +92 -0
- package/dist/src/commands/cost/index.js +3 -2
- package/dist/src/commands/deploy.js +15 -10
- package/dist/src/commands/doctor.js +9 -6
- package/dist/src/commands/drift/index.js +2 -1
- package/dist/src/commands/export.js +5 -3
- package/dist/src/commands/generate-terraform.js +110 -2
- package/dist/src/commands/import.js +3 -3
- package/dist/src/commands/incident.js +10 -5
- package/dist/src/commands/login.js +8 -93
- package/dist/src/commands/logs.js +16 -8
- package/dist/src/commands/onboarding.js +6 -4
- package/dist/src/commands/pipeline.js +6 -3
- package/dist/src/commands/plugin.js +3 -2
- package/dist/src/commands/profile.js +27 -14
- package/dist/src/commands/questionnaire.js +1 -1
- package/dist/src/commands/rollback.js +3 -2
- package/dist/src/commands/rollout.js +5 -3
- package/dist/src/commands/runbook.js +17 -10
- package/dist/src/commands/schedule.js +10 -5
- package/dist/src/commands/status.js +2 -1
- package/dist/src/commands/team-context.js +12 -7
- package/dist/src/commands/template.js +1 -1
- package/dist/src/commands/tf/index.js +6 -3
- package/dist/src/commands/upgrade.js +5 -3
- package/dist/src/commands/version.js +6 -3
- package/dist/src/commands/watch.js +6 -3
- package/dist/src/compat/sqlite.js +5 -3
- package/dist/src/config/mode-store.js +2 -1
- package/dist/src/config/profiles.js +4 -2
- package/dist/src/config/types.js +2 -1
- package/dist/src/engine/executor.js +8 -4
- package/dist/src/engine/planner.js +9 -5
- package/dist/src/llm/providers/anthropic.js +6 -3
- package/dist/src/llm/providers/ollama.js +1 -1
- package/dist/src/llm/router.js +22 -7
- package/dist/src/nimbus.js +1 -0
- package/dist/src/sessions/manager.js +6 -3
- package/dist/src/sharing/viewer.js +2 -1
- package/dist/src/tools/file-ops.js +1 -2
- package/dist/src/tools/schemas/devops.js +197 -108
- package/dist/src/tools/schemas/standard.js +1 -1
- package/dist/src/ui/App.js +25 -13
- package/dist/src/ui/FileDiffModal.js +22 -11
- package/dist/src/ui/HelpModal.js +2 -1
- package/dist/src/ui/InputBox.js +6 -3
- package/dist/src/ui/MessageList.js +40 -20
- package/dist/src/ui/TerminalPane.js +2 -1
- package/dist/src/ui/ToolCallDisplay.js +12 -6
- package/dist/src/ui/TreePane.js +2 -1
- package/dist/src/ui/ink/index.js +37 -21
- package/dist/src/version.js +1 -1
- package/dist/src/watcher/index.js +8 -4
- package/package.json +3 -5
- package/src/__tests__/alias.test.ts +0 -133
- package/src/__tests__/app.test.ts +0 -76
- package/src/__tests__/audit.test.ts +0 -877
- package/src/__tests__/circuit-breaker.test.ts +0 -116
- package/src/__tests__/cli-run.test.ts +0 -351
- package/src/__tests__/compat-sqlite.test.ts +0 -68
- package/src/__tests__/context-manager.test.ts +0 -632
- package/src/__tests__/context.test.ts +0 -242
- package/src/__tests__/devops-terminal-gaps.test.ts +0 -718
- package/src/__tests__/doctor.test.ts +0 -48
- package/src/__tests__/enterprise.test.ts +0 -401
- package/src/__tests__/export.test.ts +0 -236
- package/src/__tests__/gap-11-18-20.test.ts +0 -958
- package/src/__tests__/generator.test.ts +0 -433
- package/src/__tests__/helm-streaming.test.ts +0 -127
- package/src/__tests__/hooks.test.ts +0 -582
- package/src/__tests__/incident.test.ts +0 -179
- package/src/__tests__/init.test.ts +0 -487
- package/src/__tests__/intent-parser.test.ts +0 -229
- package/src/__tests__/llm-router.test.ts +0 -209
- package/src/__tests__/logs.test.ts +0 -107
- package/src/__tests__/loop-errors.test.ts +0 -244
- package/src/__tests__/lsp.test.ts +0 -293
- package/src/__tests__/modes.test.ts +0 -336
- package/src/__tests__/perf-optimizations.test.ts +0 -847
- package/src/__tests__/permissions.test.ts +0 -338
- package/src/__tests__/pipeline.test.ts +0 -50
- package/src/__tests__/polish-phase3.test.ts +0 -340
- package/src/__tests__/profile.test.ts +0 -237
- package/src/__tests__/rollback.test.ts +0 -83
- package/src/__tests__/runbook.test.ts +0 -219
- package/src/__tests__/schedule.test.ts +0 -206
- package/src/__tests__/serve.test.ts +0 -275
- package/src/__tests__/sessions.test.ts +0 -322
- package/src/__tests__/sharing.test.ts +0 -340
- package/src/__tests__/snapshots.test.ts +0 -581
- package/src/__tests__/standalone-migration.test.ts +0 -199
- package/src/__tests__/state-db.test.ts +0 -334
- package/src/__tests__/status.test.ts +0 -158
- package/src/__tests__/stream-with-tools.test.ts +0 -778
- package/src/__tests__/subagents.test.ts +0 -176
- package/src/__tests__/system-prompt.test.ts +0 -248
- package/src/__tests__/terminal-gap-v2.test.ts +0 -395
- package/src/__tests__/terminal-parity.test.ts +0 -393
- package/src/__tests__/tf-apply.test.ts +0 -187
- package/src/__tests__/tool-converter.test.ts +0 -256
- package/src/__tests__/tool-schemas.test.ts +0 -602
- package/src/__tests__/tools.test.ts +0 -144
- package/src/__tests__/version-json.test.ts +0 -184
- package/src/__tests__/version.test.ts +0 -49
- package/src/__tests__/watch.test.ts +0 -129
- package/src/agent/compaction-agent.ts +0 -266
- package/src/agent/context-manager.ts +0 -499
- package/src/agent/context.ts +0 -427
- package/src/agent/deploy-preview.ts +0 -487
- package/src/agent/expand-files.ts +0 -108
- package/src/agent/index.ts +0 -68
- package/src/agent/loop.ts +0 -1998
- package/src/agent/modes.ts +0 -429
- package/src/agent/permissions.ts +0 -513
- package/src/agent/subagents/base.ts +0 -116
- package/src/agent/subagents/cost.ts +0 -51
- package/src/agent/subagents/explore.ts +0 -42
- package/src/agent/subagents/general.ts +0 -54
- package/src/agent/subagents/index.ts +0 -102
- package/src/agent/subagents/infra.ts +0 -59
- package/src/agent/subagents/security.ts +0 -69
- package/src/agent/system-prompt.ts +0 -990
- package/src/app.ts +0 -180
- package/src/audit/activity-log.ts +0 -290
- package/src/audit/compliance-checker.ts +0 -540
- package/src/audit/cost-tracker.ts +0 -318
- package/src/audit/index.ts +0 -23
- package/src/audit/security-scanner.ts +0 -641
- package/src/auth/guard.ts +0 -75
- package/src/auth/index.ts +0 -56
- package/src/auth/keychain.ts +0 -82
- package/src/auth/oauth.ts +0 -465
- package/src/auth/providers.ts +0 -470
- package/src/auth/sso.ts +0 -113
- package/src/auth/store.ts +0 -505
- package/src/auth/types.ts +0 -187
- package/src/build.ts +0 -141
- package/src/cli/index.ts +0 -16
- package/src/cli/init.ts +0 -1227
- package/src/cli/openapi-spec.ts +0 -356
- package/src/cli/run.ts +0 -628
- package/src/cli/serve-auth.ts +0 -80
- package/src/cli/serve.ts +0 -539
- package/src/cli/web.ts +0 -71
- package/src/cli.ts +0 -1728
- package/src/clients/core-engine-client.ts +0 -227
- package/src/clients/enterprise-client.ts +0 -334
- package/src/clients/generator-client.ts +0 -351
- package/src/clients/git-client.ts +0 -627
- package/src/clients/github-client.ts +0 -410
- package/src/clients/helm-client.ts +0 -504
- package/src/clients/index.ts +0 -80
- package/src/clients/k8s-client.ts +0 -497
- package/src/clients/llm-client.ts +0 -161
- package/src/clients/rest-client.ts +0 -130
- package/src/clients/service-discovery.ts +0 -38
- package/src/clients/terraform-client.ts +0 -482
- package/src/clients/tools-client.ts +0 -1843
- package/src/clients/ws-client.ts +0 -115
- package/src/commands/alias.ts +0 -100
- package/src/commands/analyze/index.ts +0 -352
- package/src/commands/apply/helm.ts +0 -473
- package/src/commands/apply/index.ts +0 -213
- package/src/commands/apply/k8s.ts +0 -454
- package/src/commands/apply/terraform.ts +0 -582
- package/src/commands/ask.ts +0 -167
- package/src/commands/audit/index.ts +0 -357
- package/src/commands/auth-cloud.ts +0 -407
- package/src/commands/auth-list.ts +0 -134
- package/src/commands/auth-profile.ts +0 -121
- package/src/commands/auth-refresh.ts +0 -187
- package/src/commands/auth-status.ts +0 -141
- package/src/commands/aws/ec2.ts +0 -501
- package/src/commands/aws/iam.ts +0 -397
- package/src/commands/aws/index.ts +0 -133
- package/src/commands/aws/lambda.ts +0 -396
- package/src/commands/aws/rds.ts +0 -439
- package/src/commands/aws/s3.ts +0 -439
- package/src/commands/aws/vpc.ts +0 -393
- package/src/commands/aws-discover.ts +0 -542
- package/src/commands/aws-terraform.ts +0 -755
- package/src/commands/azure/aks.ts +0 -376
- package/src/commands/azure/functions.ts +0 -253
- package/src/commands/azure/index.ts +0 -116
- package/src/commands/azure/storage.ts +0 -478
- package/src/commands/azure/vm.ts +0 -355
- package/src/commands/billing/index.ts +0 -256
- package/src/commands/chat.ts +0 -320
- package/src/commands/completions.ts +0 -268
- package/src/commands/config.ts +0 -372
- package/src/commands/cost/cloud-cost-estimator.ts +0 -266
- package/src/commands/cost/estimator.ts +0 -79
- package/src/commands/cost/index.ts +0 -810
- package/src/commands/cost/parsers/terraform.ts +0 -273
- package/src/commands/cost/parsers/types.ts +0 -25
- package/src/commands/cost/pricing/aws.ts +0 -544
- package/src/commands/cost/pricing/azure.ts +0 -499
- package/src/commands/cost/pricing/gcp.ts +0 -396
- package/src/commands/cost/pricing/index.ts +0 -40
- package/src/commands/demo.ts +0 -250
- package/src/commands/deploy.ts +0 -260
- package/src/commands/doctor.ts +0 -1386
- package/src/commands/drift/index.ts +0 -787
- package/src/commands/explain.ts +0 -277
- package/src/commands/export.ts +0 -146
- package/src/commands/feedback.ts +0 -389
- package/src/commands/fix.ts +0 -324
- package/src/commands/fs/index.ts +0 -402
- package/src/commands/gcp/compute.ts +0 -325
- package/src/commands/gcp/functions.ts +0 -271
- package/src/commands/gcp/gke.ts +0 -438
- package/src/commands/gcp/iam.ts +0 -344
- package/src/commands/gcp/index.ts +0 -129
- package/src/commands/gcp/storage.ts +0 -284
- package/src/commands/generate-helm.ts +0 -1249
- package/src/commands/generate-k8s.ts +0 -1508
- package/src/commands/generate-terraform.ts +0 -1202
- package/src/commands/gh/index.ts +0 -863
- package/src/commands/git/index.ts +0 -1343
- package/src/commands/helm/index.ts +0 -1126
- package/src/commands/help.ts +0 -715
- package/src/commands/history.ts +0 -149
- package/src/commands/import.ts +0 -868
- package/src/commands/incident.ts +0 -166
- package/src/commands/index.ts +0 -367
- package/src/commands/init.ts +0 -1051
- package/src/commands/k8s/index.ts +0 -1137
- package/src/commands/login.ts +0 -716
- package/src/commands/logout.ts +0 -83
- package/src/commands/logs.ts +0 -167
- package/src/commands/onboarding.ts +0 -405
- package/src/commands/pipeline.ts +0 -186
- package/src/commands/plan/display.ts +0 -279
- package/src/commands/plan/index.ts +0 -599
- package/src/commands/plugin.ts +0 -398
- package/src/commands/preview.ts +0 -452
- package/src/commands/profile.ts +0 -342
- package/src/commands/questionnaire.ts +0 -1172
- package/src/commands/resume.ts +0 -47
- package/src/commands/rollback.ts +0 -315
- package/src/commands/rollout.ts +0 -88
- package/src/commands/runbook.ts +0 -346
- package/src/commands/schedule.ts +0 -236
- package/src/commands/status.ts +0 -252
- package/src/commands/team/index.ts +0 -346
- package/src/commands/team-context.ts +0 -220
- package/src/commands/template.ts +0 -233
- package/src/commands/tf/index.ts +0 -1093
- package/src/commands/upgrade.ts +0 -607
- package/src/commands/usage/index.ts +0 -134
- package/src/commands/version.ts +0 -174
- package/src/commands/watch.ts +0 -153
- package/src/compat/index.ts +0 -2
- package/src/compat/runtime.ts +0 -12
- package/src/compat/sqlite.ts +0 -177
- package/src/config/index.ts +0 -17
- package/src/config/manager.ts +0 -530
- package/src/config/mode-store.ts +0 -62
- package/src/config/profiles.ts +0 -84
- package/src/config/safety-policy.ts +0 -358
- package/src/config/schema.ts +0 -125
- package/src/config/types.ts +0 -609
- package/src/config/workspace-state.ts +0 -53
- package/src/context/context-db.ts +0 -199
- package/src/demo/index.ts +0 -349
- package/src/demo/scenarios/full-journey.ts +0 -229
- package/src/demo/scenarios/getting-started.ts +0 -127
- package/src/demo/scenarios/helm-release.ts +0 -341
- package/src/demo/scenarios/k8s-deployment.ts +0 -194
- package/src/demo/scenarios/terraform-vpc.ts +0 -170
- package/src/demo/types.ts +0 -92
- package/src/engine/cost-estimator.ts +0 -480
- package/src/engine/diagram-generator.ts +0 -256
- package/src/engine/drift-detector.ts +0 -902
- package/src/engine/executor.ts +0 -1066
- package/src/engine/index.ts +0 -76
- package/src/engine/orchestrator.ts +0 -636
- package/src/engine/planner.ts +0 -787
- package/src/engine/safety.ts +0 -743
- package/src/engine/verifier.ts +0 -770
- package/src/enterprise/audit.ts +0 -348
- package/src/enterprise/auth.ts +0 -270
- package/src/enterprise/billing.ts +0 -822
- package/src/enterprise/index.ts +0 -17
- package/src/enterprise/teams.ts +0 -443
- package/src/generator/best-practices.ts +0 -1608
- package/src/generator/helm.ts +0 -630
- package/src/generator/index.ts +0 -37
- package/src/generator/intent-parser.ts +0 -514
- package/src/generator/kubernetes.ts +0 -976
- package/src/generator/terraform.ts +0 -1875
- package/src/history/index.ts +0 -8
- package/src/history/manager.ts +0 -250
- package/src/history/types.ts +0 -34
- package/src/hooks/config.ts +0 -432
- package/src/hooks/engine.ts +0 -392
- package/src/hooks/index.ts +0 -4
- package/src/llm/auth-bridge.ts +0 -198
- package/src/llm/circuit-breaker.ts +0 -140
- package/src/llm/config-loader.ts +0 -201
- package/src/llm/cost-calculator.ts +0 -171
- package/src/llm/index.ts +0 -8
- package/src/llm/model-aliases.ts +0 -115
- package/src/llm/provider-registry.ts +0 -63
- package/src/llm/providers/anthropic.ts +0 -462
- package/src/llm/providers/bedrock.ts +0 -477
- package/src/llm/providers/google.ts +0 -405
- package/src/llm/providers/ollama.ts +0 -767
- package/src/llm/providers/openai-compatible.ts +0 -340
- package/src/llm/providers/openai.ts +0 -328
- package/src/llm/providers/openrouter.ts +0 -338
- package/src/llm/router.ts +0 -1104
- package/src/llm/types.ts +0 -232
- package/src/lsp/client.ts +0 -298
- package/src/lsp/languages.ts +0 -119
- package/src/lsp/manager.ts +0 -294
- package/src/mcp/client.ts +0 -402
- package/src/mcp/index.ts +0 -5
- package/src/mcp/manager.ts +0 -133
- package/src/nimbus.ts +0 -233
- package/src/plugins/index.ts +0 -27
- package/src/plugins/loader.ts +0 -334
- package/src/plugins/manager.ts +0 -376
- package/src/plugins/types.ts +0 -284
- package/src/scanners/cicd-scanner.ts +0 -258
- package/src/scanners/cloud-scanner.ts +0 -466
- package/src/scanners/framework-scanner.ts +0 -469
- package/src/scanners/iac-scanner.ts +0 -388
- package/src/scanners/index.ts +0 -539
- package/src/scanners/language-scanner.ts +0 -276
- package/src/scanners/package-manager-scanner.ts +0 -277
- package/src/scanners/types.ts +0 -172
- package/src/sessions/manager.ts +0 -472
- package/src/sessions/types.ts +0 -44
- package/src/sharing/sync.ts +0 -300
- package/src/sharing/viewer.ts +0 -163
- package/src/snapshots/index.ts +0 -2
- package/src/snapshots/manager.ts +0 -530
- package/src/state/artifacts.ts +0 -147
- package/src/state/audit.ts +0 -137
- package/src/state/billing.ts +0 -240
- package/src/state/checkpoints.ts +0 -117
- package/src/state/config.ts +0 -67
- package/src/state/conversations.ts +0 -14
- package/src/state/credentials.ts +0 -154
- package/src/state/db.ts +0 -58
- package/src/state/index.ts +0 -26
- package/src/state/messages.ts +0 -115
- package/src/state/projects.ts +0 -123
- package/src/state/schema.ts +0 -236
- package/src/state/sessions.ts +0 -147
- package/src/state/teams.ts +0 -200
- package/src/telemetry.ts +0 -108
- package/src/tools/aws-ops.ts +0 -952
- package/src/tools/azure-ops.ts +0 -579
- package/src/tools/file-ops.ts +0 -615
- package/src/tools/gcp-ops.ts +0 -625
- package/src/tools/git-ops.ts +0 -773
- package/src/tools/github-ops.ts +0 -799
- package/src/tools/helm-ops.ts +0 -943
- package/src/tools/index.ts +0 -17
- package/src/tools/k8s-ops.ts +0 -819
- package/src/tools/schemas/converter.ts +0 -184
- package/src/tools/schemas/devops.ts +0 -3502
- package/src/tools/schemas/index.ts +0 -73
- package/src/tools/schemas/standard.ts +0 -1148
- package/src/tools/schemas/types.ts +0 -735
- package/src/tools/spawn-exec.ts +0 -148
- package/src/tools/terraform-ops.ts +0 -862
- package/src/types/ambient.d.ts +0 -193
- package/src/types/config.ts +0 -83
- package/src/types/drift.ts +0 -116
- package/src/types/enterprise.ts +0 -335
- package/src/types/index.ts +0 -20
- package/src/types/plan.ts +0 -44
- package/src/types/request.ts +0 -65
- package/src/types/response.ts +0 -54
- package/src/types/service.ts +0 -51
- package/src/ui/App.tsx +0 -2114
- package/src/ui/DeployPreview.tsx +0 -174
- package/src/ui/FileDiffModal.tsx +0 -162
- package/src/ui/Header.tsx +0 -131
- package/src/ui/HelpModal.tsx +0 -57
- package/src/ui/InputBox.tsx +0 -503
- package/src/ui/MessageList.tsx +0 -1032
- package/src/ui/PermissionPrompt.tsx +0 -163
- package/src/ui/StatusBar.tsx +0 -277
- package/src/ui/TerminalPane.tsx +0 -84
- package/src/ui/ToolCallDisplay.tsx +0 -643
- package/src/ui/TreePane.tsx +0 -132
- package/src/ui/chat-ui.ts +0 -850
- package/src/ui/index.ts +0 -33
- package/src/ui/ink/index.ts +0 -1444
- package/src/ui/streaming.ts +0 -176
- package/src/ui/theme.ts +0 -104
- package/src/ui/types.ts +0 -75
- package/src/utils/analytics.ts +0 -72
- package/src/utils/cost-warning.ts +0 -27
- package/src/utils/env.ts +0 -46
- package/src/utils/errors.ts +0 -69
- package/src/utils/event-bus.ts +0 -38
- package/src/utils/index.ts +0 -24
- package/src/utils/logger.ts +0 -171
- package/src/utils/rate-limiter.ts +0 -121
- package/src/utils/service-auth.ts +0 -49
- package/src/utils/validation.ts +0 -53
- package/src/version.ts +0 -4
- package/src/watcher/index.ts +0 -214
- package/src/wizard/approval.ts +0 -383
- package/src/wizard/index.ts +0 -25
- package/src/wizard/prompts.ts +0 -338
- package/src/wizard/types.ts +0 -172
- package/src/wizard/ui.ts +0 -556
- package/src/wizard/wizard.ts +0 -304
- package/tsconfig.json +0 -24
package/src/sessions/manager.ts
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Manager — Multi-Session Lifecycle
|
|
3
|
-
*
|
|
4
|
-
* Manages creation, switching, suspension, and destruction of parallel
|
|
5
|
-
* agent sessions. Each session has its own conversation history, tool
|
|
6
|
-
* state, and working context, but shares project config (NIMBUS.md).
|
|
7
|
-
*
|
|
8
|
-
* File conflict detection warns when two sessions edit the same file.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { getDb } from '../state/db';
|
|
12
|
-
import type { Database } from '../compat/sqlite';
|
|
13
|
-
import type { SessionRecord, SessionStatus, SessionEvent, SessionFileEdit } from './types';
|
|
14
|
-
import type { LLMMessage } from '../llm/types';
|
|
15
|
-
|
|
16
|
-
/** Infra context persisted per session (terraform workspace, kubectl context, etc.) */
|
|
17
|
-
export interface SessionInfraContext {
|
|
18
|
-
terraformWorkspace?: string;
|
|
19
|
-
kubectlContext?: string;
|
|
20
|
-
awsProfile?: string;
|
|
21
|
-
awsRegion?: string;
|
|
22
|
-
gcpProject?: string;
|
|
23
|
-
azureSubscription?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Singleton session manager instance. */
|
|
27
|
-
let instance: SessionManager | null = null;
|
|
28
|
-
|
|
29
|
-
export class SessionManager {
|
|
30
|
-
private db: Database;
|
|
31
|
-
private activeSessionId: string | null = null;
|
|
32
|
-
private fileEdits: Map<string, SessionFileEdit[]> = new Map();
|
|
33
|
-
private eventListeners: Array<(event: SessionEvent) => void> = [];
|
|
34
|
-
|
|
35
|
-
/** Pending conversation writes accumulated before the next debounced flush. */
|
|
36
|
-
private pendingConversationFlush: Map<string, {
|
|
37
|
-
messages: LLMMessage[];
|
|
38
|
-
stats?: Partial<Pick<SessionRecord, 'tokenCount' | 'costUSD' | 'snapshotCount' | 'mode' | 'model'>>;
|
|
39
|
-
}> = new Map();
|
|
40
|
-
private _flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
41
|
-
private readonly flushDebounceMs: number;
|
|
42
|
-
|
|
43
|
-
constructor(db?: Database, options?: { flushDebounceMs?: number }) {
|
|
44
|
-
this.db = db || getDb();
|
|
45
|
-
this.flushDebounceMs = options?.flushDebounceMs ?? 5000;
|
|
46
|
-
this.ensureTable();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Get the singleton instance. */
|
|
50
|
-
static getInstance(db?: Database): SessionManager {
|
|
51
|
-
if (!instance) {
|
|
52
|
-
instance = new SessionManager(db);
|
|
53
|
-
}
|
|
54
|
-
return instance;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Reset the singleton (for testing). */
|
|
58
|
-
static resetInstance(): void {
|
|
59
|
-
instance = null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Ensure the sessions table exists with the status column. */
|
|
63
|
-
private ensureTable(): void {
|
|
64
|
-
this.db.exec(`
|
|
65
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
66
|
-
id TEXT PRIMARY KEY,
|
|
67
|
-
name TEXT NOT NULL,
|
|
68
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
69
|
-
mode TEXT NOT NULL DEFAULT 'plan',
|
|
70
|
-
model TEXT NOT NULL DEFAULT 'default',
|
|
71
|
-
cwd TEXT NOT NULL DEFAULT '.',
|
|
72
|
-
token_count INTEGER NOT NULL DEFAULT 0,
|
|
73
|
-
cost_usd REAL NOT NULL DEFAULT 0,
|
|
74
|
-
snapshot_count INTEGER NOT NULL DEFAULT 0,
|
|
75
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
76
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
77
|
-
metadata TEXT
|
|
78
|
-
)
|
|
79
|
-
`);
|
|
80
|
-
|
|
81
|
-
this.db.exec(`
|
|
82
|
-
CREATE TABLE IF NOT EXISTS conversations (
|
|
83
|
-
id TEXT PRIMARY KEY,
|
|
84
|
-
title TEXT NOT NULL DEFAULT 'Untitled',
|
|
85
|
-
messages TEXT NOT NULL DEFAULT '[]',
|
|
86
|
-
model TEXT NOT NULL DEFAULT 'default',
|
|
87
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
88
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
89
|
-
)
|
|
90
|
-
`);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Create a new session. */
|
|
94
|
-
create(options: {
|
|
95
|
-
name: string;
|
|
96
|
-
mode?: SessionRecord['mode'];
|
|
97
|
-
model?: string;
|
|
98
|
-
cwd?: string;
|
|
99
|
-
}): SessionRecord {
|
|
100
|
-
const id = crypto.randomUUID();
|
|
101
|
-
const now = new Date().toISOString();
|
|
102
|
-
const mode = options.mode ?? 'plan';
|
|
103
|
-
const model = options.model ?? 'default';
|
|
104
|
-
const cwd = options.cwd ?? process.cwd();
|
|
105
|
-
|
|
106
|
-
this.db
|
|
107
|
-
.prepare(
|
|
108
|
-
`
|
|
109
|
-
INSERT INTO sessions (id, name, status, mode, model, cwd, token_count, cost_usd, snapshot_count, created_at, updated_at)
|
|
110
|
-
VALUES (?, ?, 'active', ?, ?, ?, 0, 0, 0, ?, ?)
|
|
111
|
-
`
|
|
112
|
-
)
|
|
113
|
-
.run(id, options.name, mode, model, cwd, now, now);
|
|
114
|
-
|
|
115
|
-
const session: SessionRecord = {
|
|
116
|
-
id,
|
|
117
|
-
name: options.name,
|
|
118
|
-
status: 'active',
|
|
119
|
-
mode,
|
|
120
|
-
model,
|
|
121
|
-
cwd,
|
|
122
|
-
tokenCount: 0,
|
|
123
|
-
costUSD: 0,
|
|
124
|
-
snapshotCount: 0,
|
|
125
|
-
createdAt: now,
|
|
126
|
-
updatedAt: now,
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
this.emit({ type: 'created', sessionId: id, timestamp: new Date() });
|
|
130
|
-
return session;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** List all sessions, optionally filtered by status. */
|
|
134
|
-
list(status?: SessionStatus): SessionRecord[] {
|
|
135
|
-
let rows: any[];
|
|
136
|
-
if (status) {
|
|
137
|
-
rows = this.db
|
|
138
|
-
.prepare('SELECT * FROM sessions WHERE status = ? ORDER BY updated_at DESC')
|
|
139
|
-
.all(status) as any[];
|
|
140
|
-
} else {
|
|
141
|
-
rows = this.db.prepare('SELECT * FROM sessions ORDER BY updated_at DESC').all() as any[];
|
|
142
|
-
}
|
|
143
|
-
return rows.map(rowToSession);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** List only active sessions. */
|
|
147
|
-
listActive(): SessionRecord[] {
|
|
148
|
-
return this.list('active');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** Get a session by ID. */
|
|
152
|
-
get(id: string): SessionRecord | null {
|
|
153
|
-
const row: any = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);
|
|
154
|
-
return row ? rowToSession(row) : null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** Get the currently active session ID. */
|
|
158
|
-
getActiveSessionId(): string | null {
|
|
159
|
-
return this.activeSessionId;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** Switch to a different session. Suspends the current one. */
|
|
163
|
-
switchTo(sessionId: string): SessionRecord | null {
|
|
164
|
-
const session = this.get(sessionId);
|
|
165
|
-
if (!session) {
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Suspend current session
|
|
170
|
-
if (this.activeSessionId && this.activeSessionId !== sessionId) {
|
|
171
|
-
this.updateStatus(this.activeSessionId, 'suspended');
|
|
172
|
-
this.emit({
|
|
173
|
-
type: 'suspended',
|
|
174
|
-
sessionId: this.activeSessionId,
|
|
175
|
-
timestamp: new Date(),
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Activate target session
|
|
180
|
-
this.updateStatus(sessionId, 'active');
|
|
181
|
-
this.activeSessionId = sessionId;
|
|
182
|
-
|
|
183
|
-
this.emit({ type: 'switched', sessionId, timestamp: new Date() });
|
|
184
|
-
return this.get(sessionId);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** Suspend a session (keeps state, stops processing). */
|
|
188
|
-
suspend(sessionId: string): void {
|
|
189
|
-
this.updateStatus(sessionId, 'suspended');
|
|
190
|
-
if (this.activeSessionId === sessionId) {
|
|
191
|
-
this.activeSessionId = null;
|
|
192
|
-
}
|
|
193
|
-
this.emit({ type: 'suspended', sessionId, timestamp: new Date() });
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/** Resume a suspended session. */
|
|
197
|
-
resume(sessionId: string): SessionRecord | null {
|
|
198
|
-
const session = this.get(sessionId);
|
|
199
|
-
if (!session || session.status === 'completed') {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
this.updateStatus(sessionId, 'active');
|
|
204
|
-
this.activeSessionId = sessionId;
|
|
205
|
-
this.emit({ type: 'resumed', sessionId, timestamp: new Date() });
|
|
206
|
-
return this.get(sessionId);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/** Mark a session as completed. */
|
|
210
|
-
complete(sessionId: string): void {
|
|
211
|
-
this.updateStatus(sessionId, 'completed');
|
|
212
|
-
if (this.activeSessionId === sessionId) {
|
|
213
|
-
this.activeSessionId = null;
|
|
214
|
-
}
|
|
215
|
-
this.emit({ type: 'completed', sessionId, timestamp: new Date() });
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/** Destroy a session (removes from DB). */
|
|
219
|
-
destroy(sessionId: string): void {
|
|
220
|
-
this.db.prepare('DELETE FROM sessions WHERE id = ?').run(sessionId);
|
|
221
|
-
if (this.activeSessionId === sessionId) {
|
|
222
|
-
this.activeSessionId = null;
|
|
223
|
-
}
|
|
224
|
-
// Clean up file edits for this session
|
|
225
|
-
for (const [path, edits] of this.fileEdits) {
|
|
226
|
-
const filtered = edits.filter(e => e.sessionId !== sessionId);
|
|
227
|
-
if (filtered.length === 0) {
|
|
228
|
-
this.fileEdits.delete(path);
|
|
229
|
-
} else {
|
|
230
|
-
this.fileEdits.set(path, filtered);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
this.emit({ type: 'destroyed', sessionId, timestamp: new Date() });
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/** M2: Rename a session (update its display name). */
|
|
237
|
-
rename(sessionId: string, name: string): void {
|
|
238
|
-
this.db.prepare('UPDATE sessions SET name = ? WHERE id = ?').run(name, sessionId);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/** Update session metadata (tokens, cost, mode, etc.). */
|
|
242
|
-
updateSession(
|
|
243
|
-
sessionId: string,
|
|
244
|
-
updates: Partial<
|
|
245
|
-
Pick<SessionRecord, 'tokenCount' | 'costUSD' | 'snapshotCount' | 'mode' | 'model'>
|
|
246
|
-
>
|
|
247
|
-
): void {
|
|
248
|
-
const parts: string[] = [];
|
|
249
|
-
const values: any[] = [];
|
|
250
|
-
|
|
251
|
-
if (updates.tokenCount !== undefined) {
|
|
252
|
-
parts.push('token_count = ?');
|
|
253
|
-
values.push(updates.tokenCount);
|
|
254
|
-
}
|
|
255
|
-
if (updates.costUSD !== undefined) {
|
|
256
|
-
parts.push('cost_usd = ?');
|
|
257
|
-
values.push(updates.costUSD);
|
|
258
|
-
}
|
|
259
|
-
if (updates.snapshotCount !== undefined) {
|
|
260
|
-
parts.push('snapshot_count = ?');
|
|
261
|
-
values.push(updates.snapshotCount);
|
|
262
|
-
}
|
|
263
|
-
if (updates.mode !== undefined) {
|
|
264
|
-
parts.push('mode = ?');
|
|
265
|
-
values.push(updates.mode);
|
|
266
|
-
}
|
|
267
|
-
if (updates.model !== undefined) {
|
|
268
|
-
parts.push('model = ?');
|
|
269
|
-
values.push(updates.model);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (parts.length === 0) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
parts.push("updated_at = datetime('now')");
|
|
277
|
-
values.push(sessionId);
|
|
278
|
-
|
|
279
|
-
this.db.prepare(`UPDATE sessions SET ${parts.join(', ')} WHERE id = ?`).run(...values);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** Save conversation messages for a session. */
|
|
283
|
-
saveConversation(sessionId: string, messages: LLMMessage[]): void {
|
|
284
|
-
const existing = this.db.prepare('SELECT id FROM conversations WHERE id = ?').get(sessionId);
|
|
285
|
-
const session = this.get(sessionId);
|
|
286
|
-
const title = session?.name ?? 'Untitled';
|
|
287
|
-
const messagesJson = JSON.stringify(messages);
|
|
288
|
-
|
|
289
|
-
if (existing) {
|
|
290
|
-
this.db
|
|
291
|
-
.prepare("UPDATE conversations SET messages = ?, updated_at = datetime('now') WHERE id = ?")
|
|
292
|
-
.run(messagesJson, sessionId);
|
|
293
|
-
} else {
|
|
294
|
-
this.db
|
|
295
|
-
.prepare(
|
|
296
|
-
"INSERT INTO conversations (id, title, messages, model, created_at, updated_at) VALUES (?, ?, ?, ?, datetime('now'), datetime('now'))"
|
|
297
|
-
)
|
|
298
|
-
.run(sessionId, title, messagesJson, session?.model ?? 'default');
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Atomically save conversation messages AND update session stats.
|
|
304
|
-
* Writes are debounced (default 5s) and batched for performance.
|
|
305
|
-
* Use `flushAll()` for immediate persistence (shutdown / completion).
|
|
306
|
-
*/
|
|
307
|
-
saveConversationAndStats(
|
|
308
|
-
sessionId: string,
|
|
309
|
-
messages: LLMMessage[],
|
|
310
|
-
stats: Partial<Pick<SessionRecord, 'tokenCount' | 'costUSD' | 'snapshotCount' | 'mode' | 'model'>>
|
|
311
|
-
): void {
|
|
312
|
-
// Accumulate into the pending flush map (latest write wins per session)
|
|
313
|
-
const existing = this.pendingConversationFlush.get(sessionId);
|
|
314
|
-
this.pendingConversationFlush.set(sessionId, {
|
|
315
|
-
messages,
|
|
316
|
-
stats: existing?.stats ? { ...existing.stats, ...stats } : stats,
|
|
317
|
-
});
|
|
318
|
-
this._scheduleFlush();
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/** Schedule a debounced flush (no-op if already scheduled). */
|
|
322
|
-
private _scheduleFlush(): void {
|
|
323
|
-
if (this._flushTimer !== null) return;
|
|
324
|
-
if (this.flushDebounceMs === 0) {
|
|
325
|
-
// Immediate flush path (used in tests)
|
|
326
|
-
this._flushNow();
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
this._flushTimer = setTimeout(() => {
|
|
330
|
-
this._flushTimer = null;
|
|
331
|
-
this._flushNow();
|
|
332
|
-
}, this.flushDebounceMs);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/** Write all pending conversation entries to SQLite. */
|
|
336
|
-
private _flushNow(): void {
|
|
337
|
-
if (this.pendingConversationFlush.size === 0) return;
|
|
338
|
-
const pending = this.pendingConversationFlush;
|
|
339
|
-
this.pendingConversationFlush = new Map();
|
|
340
|
-
const txn = this.db.transaction(() => {
|
|
341
|
-
for (const [sessionId, { messages, stats }] of pending) {
|
|
342
|
-
this.saveConversation(sessionId, messages);
|
|
343
|
-
if (stats && Object.keys(stats).length > 0) {
|
|
344
|
-
this.updateSession(sessionId, stats);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
txn();
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Flush all pending conversation writes immediately.
|
|
353
|
-
* Must be called on clean shutdown and session completion.
|
|
354
|
-
*/
|
|
355
|
-
flushAll(): void {
|
|
356
|
-
if (this._flushTimer !== null) {
|
|
357
|
-
clearTimeout(this._flushTimer);
|
|
358
|
-
this._flushTimer = null;
|
|
359
|
-
}
|
|
360
|
-
this._flushNow();
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/** Load conversation messages for a session. Returns empty array if not found. */
|
|
364
|
-
loadConversation(sessionId: string): LLMMessage[] {
|
|
365
|
-
const row: any = this.db
|
|
366
|
-
.prepare('SELECT messages FROM conversations WHERE id = ?')
|
|
367
|
-
.get(sessionId);
|
|
368
|
-
if (!row?.messages) {
|
|
369
|
-
return [];
|
|
370
|
-
}
|
|
371
|
-
try {
|
|
372
|
-
return JSON.parse(row.messages);
|
|
373
|
-
} catch {
|
|
374
|
-
return [];
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/** Record a file edit for conflict detection. */
|
|
379
|
-
recordFileEdit(sessionId: string, filePath: string): string[] {
|
|
380
|
-
const normalizedPath = filePath;
|
|
381
|
-
const edit: SessionFileEdit = { sessionId, filePath: normalizedPath, timestamp: new Date() };
|
|
382
|
-
|
|
383
|
-
const existing = this.fileEdits.get(normalizedPath) || [];
|
|
384
|
-
existing.push(edit);
|
|
385
|
-
this.fileEdits.set(normalizedPath, existing);
|
|
386
|
-
|
|
387
|
-
// Check for conflicts (other sessions editing the same file)
|
|
388
|
-
const conflicts: string[] = [];
|
|
389
|
-
const otherEditors = existing.filter(
|
|
390
|
-
e => e.sessionId !== sessionId && e.timestamp.getTime() > Date.now() - 5 * 60 * 1000 // Within last 5 minutes
|
|
391
|
-
);
|
|
392
|
-
|
|
393
|
-
for (const editor of otherEditors) {
|
|
394
|
-
conflicts.push(editor.sessionId);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
if (conflicts.length > 0) {
|
|
398
|
-
this.emit({
|
|
399
|
-
type: 'file_conflict',
|
|
400
|
-
sessionId,
|
|
401
|
-
timestamp: new Date(),
|
|
402
|
-
details: `File "${filePath}" is also being edited by session(s): ${conflicts.join(', ')}`,
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return conflicts;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/** Persist infra context (terraform workspace, kubectl context, etc.) for a session. */
|
|
410
|
-
setInfraContext(sessionId: string, ctx: SessionInfraContext): void {
|
|
411
|
-
const row: any = this.db.prepare('SELECT metadata FROM sessions WHERE id = ?').get(sessionId);
|
|
412
|
-
const existing = row?.metadata ? JSON.parse(row.metadata) : {};
|
|
413
|
-
const updated = { ...existing, infraContext: ctx };
|
|
414
|
-
this.db
|
|
415
|
-
.prepare("UPDATE sessions SET metadata = ?, updated_at = datetime('now') WHERE id = ?")
|
|
416
|
-
.run(JSON.stringify(updated), sessionId);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/** Retrieve infra context for a session. Returns null if not set. */
|
|
420
|
-
getInfraContext(sessionId: string): SessionInfraContext | null {
|
|
421
|
-
const row: any = this.db.prepare('SELECT metadata FROM sessions WHERE id = ?').get(sessionId);
|
|
422
|
-
if (!row?.metadata) return null;
|
|
423
|
-
try {
|
|
424
|
-
const meta = JSON.parse(row.metadata);
|
|
425
|
-
return meta.infraContext ?? null;
|
|
426
|
-
} catch {
|
|
427
|
-
return null;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/** Listen for session events. */
|
|
432
|
-
onEvent(listener: (event: SessionEvent) => void): () => void {
|
|
433
|
-
this.eventListeners.push(listener);
|
|
434
|
-
return () => {
|
|
435
|
-
this.eventListeners = this.eventListeners.filter(l => l !== listener);
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
private emit(event: SessionEvent): void {
|
|
440
|
-
for (const listener of this.eventListeners) {
|
|
441
|
-
try {
|
|
442
|
-
listener(event);
|
|
443
|
-
} catch {
|
|
444
|
-
/* ignore */
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
private updateStatus(sessionId: string, status: SessionStatus): void {
|
|
450
|
-
this.db
|
|
451
|
-
.prepare("UPDATE sessions SET status = ?, updated_at = datetime('now') WHERE id = ?")
|
|
452
|
-
.run(status, sessionId);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/** Convert a raw DB row to a SessionRecord. */
|
|
457
|
-
function rowToSession(row: any): SessionRecord {
|
|
458
|
-
return {
|
|
459
|
-
id: row.id,
|
|
460
|
-
name: row.name,
|
|
461
|
-
status: row.status as SessionStatus,
|
|
462
|
-
mode: row.mode,
|
|
463
|
-
model: row.model,
|
|
464
|
-
cwd: row.cwd,
|
|
465
|
-
tokenCount: row.token_count,
|
|
466
|
-
costUSD: row.cost_usd,
|
|
467
|
-
snapshotCount: row.snapshot_count,
|
|
468
|
-
createdAt: row.created_at,
|
|
469
|
-
updatedAt: row.updated_at,
|
|
470
|
-
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
471
|
-
};
|
|
472
|
-
}
|
package/src/sessions/types.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session types for multi-session support.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/** Status of a session. */
|
|
6
|
-
export type SessionStatus = 'active' | 'suspended' | 'completed';
|
|
7
|
-
|
|
8
|
-
/** Core session information stored in the database. */
|
|
9
|
-
export interface SessionRecord {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
status: SessionStatus;
|
|
13
|
-
mode: 'plan' | 'build' | 'deploy';
|
|
14
|
-
model: string;
|
|
15
|
-
cwd: string;
|
|
16
|
-
tokenCount: number;
|
|
17
|
-
costUSD: number;
|
|
18
|
-
snapshotCount: number;
|
|
19
|
-
createdAt: string;
|
|
20
|
-
updatedAt: string;
|
|
21
|
-
metadata?: Record<string, unknown>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Event emitted by the session manager. */
|
|
25
|
-
export interface SessionEvent {
|
|
26
|
-
type:
|
|
27
|
-
| 'created'
|
|
28
|
-
| 'switched'
|
|
29
|
-
| 'suspended'
|
|
30
|
-
| 'resumed'
|
|
31
|
-
| 'completed'
|
|
32
|
-
| 'destroyed'
|
|
33
|
-
| 'file_conflict';
|
|
34
|
-
sessionId: string;
|
|
35
|
-
timestamp: Date;
|
|
36
|
-
details?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Info about a file being edited in a session (for conflict detection). */
|
|
40
|
-
export interface SessionFileEdit {
|
|
41
|
-
sessionId: string;
|
|
42
|
-
filePath: string;
|
|
43
|
-
timestamp: Date;
|
|
44
|
-
}
|