2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import type { SDKSessionInfo } from '@anthropic-ai/claude-agent-sdk';
7
>
import { URI } from '../../../../base/common/uri.js';
8
>
import { ClaudePermissionMode, narrowClaudePermissionMode } from '../../common/claudeSessionConfigKeys.js';
9
>
import { AgentProvider, AgentSession, IAgentSessionMetadata } from '../../common/agentService.js';
10
>
import { ISessionDataService } from '../../common/sessionDataService.js';
11
>
import type { AgentSelection, ModelSelection } from '../../common/state/protocol/state.js';
12
>
13
>
/**
14
>
* Read view of Claude's per-session DB overlay. SDK-supplied fields
15
>
* (summary, cwd, timestamps) live on {@link SDKSessionInfo} and are
16
>
* combined with the overlay in {@link ClaudeSessionMetadataStore.project}.
17
>
*/
18
>
export interface IClaudeSessionOverlay {
19
>
readonly customizationDirectory?: URI;
20
>
readonly model?: ModelSelection;
21
>
readonly permissionMode?: ClaudePermissionMode;
22
>
readonly agent?: AgentSelection;
23
>
/**
24
>
* Transport the session most recently materialized under (Phase 19).
25
>
* Forward-compat only — written at materialize time but NOT read for
26
>
* transport resolution in v1 (transport is resolved host-level). Lets a
27
>
* future per-session-transport feature land without a data migration.
28
>
*/
29
>
readonly transport?: 'proxy' | 'native';
30
>
}
31
>
32
>
/**
33
>
* Write view: any subset of the overlay fields. Fields left `undefined`
34
>
* are not touched (only-write-on-defined semantics). Pass `null` for
35
>
* `agent` to clear a previously persisted selection.
36
>
*/
37
>
export interface IClaudeSessionOverlayUpdate {
38
>
readonly customizationDirectory?: URI;
39
>
readonly model?: ModelSelection;
40
>
readonly permissionMode?: ClaudePermissionMode;
41
>
readonly agent?: AgentSelection | null;
42
>
readonly transport?: 'proxy' | 'native';
43
>
}
44
>
45
>
/**
46
>
* Owns Claude's per-session metadata layer:
47
>
*
48
>
* - the three `_META_*` DB keys,
49
>
* - the {@link ModelSelection} JSON codec used to persist the parallel
50
>
* `{ id, config }` shape,
51
>
* - the read/write helpers that open a per-call DB ref,
52
>
* - the projection from {@link SDKSessionInfo} + overlay onto the
53
>
* platform's {@link IAgentSessionMetadata} shape.
54
>
*
55
>
* One instance per {@link ClaudeAgent}: the {@link AgentProvider} id
56
>
* passed at construction is the one stamped on every projected URI.
57
>
*
58
>
* The SDK is the source of truth for session existence; the overlay
59
>
* merely decorates. External Claude CLI sessions have no overlay DB,
60
>
* so {@link read} returns `{}` rather than throwing — every caller
61
>
* must tolerate an empty overlay.
62
>
*/
63
>
export class ClaudeSessionMetadataStore {
64
>
65
>
private static readonly KEY_CUSTOMIZATION_DIRECTORY = 'claude.customizationDirectory';
66
>
private static readonly KEY_MODEL = 'claude.model';
67
>
private static readonly KEY_PERMISSION_MODE = 'claude.permissionMode';
68
>
private static readonly KEY_AGENT = 'claude.agent';
69
>
private static readonly KEY_TRANSPORT = 'claude.transport';
70
>
71
>
constructor(
72
private readonly _provider: AgentProvider,
73
@ISessionDataService private readonly _sessionDataService: ISessionDataService,
74
) { }
76
>
/**
77
>
* Persist the supplied overlay fields to the per-session DB. Mirrors
78
>
* CopilotAgent's `_storeSessionMetadata` pattern
79
>
* (`copilotAgent.ts:1532`): single `openDatabase` ref, `Promise.all`
80
>
* batching, only-write-on-defined.
81
>
*/
82
>
async write(session: URI, fields: IClaudeSessionOverlayUpdate): Promise<void> {
83
const dbRef = this._sessionDataService.openDatabase(session);
84
const db = dbRef.object;