@asaidimu/utils-workspace 5.0.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -944,6 +944,9 @@ interface SessionMetadata {
944
944
  created?: Timestamp;
945
945
  /** UTC timestamp of the last activity within the session. */
946
946
  updated?: Timestamp;
947
+ /** The current model being use by the session */
948
+ model?: string;
949
+ [key: string]: any;
947
950
  };
948
951
  /** The current chronological leaf-node of the conversation DAG. */
949
952
  head?: {
@@ -1018,8 +1021,9 @@ interface TopicIndex {
1018
1021
  entries?: number;
1019
1022
  };
1020
1023
  }
1021
- /** The complete in-memory read-model of the Workspace state. */
1022
- interface Index {
1024
+ type IndexExtensions = Record<string, Record<string, any>>;
1025
+ interface Index<T extends IndexExtensions = IndexExtensions> {
1026
+ /** The complete in-memory read-model of the Workspace state. */
1023
1027
  /** Lookup dictionary of Roles by their string name. */
1024
1028
  roles: Record<string, RoleSummary>;
1025
1029
  /** Lookup dictionary of Preferences by their UUID. */
@@ -1034,9 +1038,10 @@ interface Index {
1034
1038
  blobs: Record<SHA256, BlobRecord>;
1035
1039
  /** Lookup dictionary of registered Tool capabilities by their string name. */
1036
1040
  tools: Record<string, ToolSummary>;
1041
+ extensions: T;
1037
1042
  }
1038
1043
  /** The root container for a user's workspace. */
1039
- interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>> {
1044
+ interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>, Extentions extends Record<string, Record<string, any>> = IndexExtensions> {
1040
1045
  /** Unique identifier for the entire workspace environment. */
1041
1046
  id: UUID;
1042
1047
  /** Global user and systemic settings. */
@@ -1044,7 +1049,7 @@ interface Workspace<ProjectMetadata extends Record<string, any> = Record<string,
1044
1049
  /** High-level project metadata. */
1045
1050
  project: Project<ProjectMetadata>;
1046
1051
  /** The in-memory read-projection of all underlying stores. */
1047
- index: Index;
1052
+ index: Index<Extentions>;
1048
1053
  }
1049
1054
  /**
1050
1055
  * Format used for exporting/importing a complete workspace state,
@@ -1433,6 +1438,8 @@ interface SessionSnapshot {
1433
1438
  id: UUID;
1434
1439
  /** Top-level session definition fields. */
1435
1440
  meta: SessionMetadata;
1441
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1442
+ model?: string;
1436
1443
  /** The active role — persona, instructions, role-level constraints. */
1437
1444
  role: Role;
1438
1445
  /** Unfiltered, unranked preferences attached strictly to the role or session. */
@@ -1467,6 +1474,8 @@ interface SessionSnapshot {
1467
1474
  * - Uploading inline blobs to the provider where required.
1468
1475
  */
1469
1476
  interface Prompt {
1477
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1478
+ model?: string;
1470
1479
  /** Correlates this prompt to its session for logging and evaluation. */
1471
1480
  session: UUID;
1472
1481
  /** System-level instructions, context, and preferences. */
@@ -1540,7 +1549,7 @@ interface AdapterStatus {
1540
1549
  };
1541
1550
  /** Pricing tiers for this model. */
1542
1551
  pricing: Array<{
1543
- unit: 'token' | 'call';
1552
+ unit: 'token' | 'call' | "image";
1544
1553
  /** Exponent: price is per 10^scale units. */
1545
1554
  scale: number;
1546
1555
  /** Price per unit in USD. */
@@ -1561,7 +1570,7 @@ interface AdapterStatus {
1561
1570
  timeout?: number;
1562
1571
  /** The hard limits enforced by the provider. */
1563
1572
  capacity: Array<{
1564
- unit: 'token' | 'call';
1573
+ unit: 'token' | 'call' | string;
1565
1574
  /** Maximum units allowed per period. */
1566
1575
  max: number;
1567
1576
  /** Period length in seconds. */
@@ -1580,20 +1589,33 @@ interface ExecuteResult {
1580
1589
  /** Side-effect commands to dispatch against the workspace. */
1581
1590
  effects: BaseCommand[];
1582
1591
  }
1592
+ /**
1593
+ * A single labelled section of the system prompt.
1594
+ * Mirrors PreparedPrompt.system exactly — the assembler's output is stored
1595
+ * there directly, giving callers full inspection without re-parsing the string.
1596
+ */
1597
+ interface PromptSection {
1598
+ /**
1599
+ * Origin label for this section.
1600
+ * Core sections use fixed labels: 'operating-system' | 'persona' |
1601
+ * 'preferences' | 'context' | 'instructions'.
1602
+ * Extensions carry whatever label the injector provides.
1603
+ */
1604
+ label: string;
1605
+ /** Text content exactly as it will be sent to the model. */
1606
+ content: string;
1607
+ /** Optional structured metadata for richer UI display or tooling. */
1608
+ metadata?: Record<string, any>;
1609
+ }
1583
1610
  /**
1584
1611
  * The complete, final prompt exactly as the model will receive it.
1585
1612
  * Generic, provider-agnostic, fully inspectable, and executable.
1586
1613
  */
1587
1614
  interface PreparedPrompt {
1615
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1616
+ model: string;
1588
1617
  /** The complete system instruction broken into labelled sections for inspection. */
1589
- system: Array<{
1590
- /** Origin label for this section (e.g., "persona", "context:project-brief"). */
1591
- label: string;
1592
- /** Text content exactly as it will be sent to the model. */
1593
- content: string;
1594
- /** Optional structured metadata for richer UI display. */
1595
- metadata?: Record<string, any>;
1596
- }>;
1618
+ instructions: Array<PromptSection>;
1597
1619
  /** Final transcript turns that will be sent after adapter-level truncation. */
1598
1620
  transcript: Turn[];
1599
1621
  /** Final context entries included after adapter-level truncation. */
@@ -1870,7 +1892,7 @@ type Collections = typeof COLLECTIONS[keyof typeof COLLECTIONS];
1870
1892
  * The full set of stores passed to every reducer and middleware call.
1871
1893
  * Applications extend this with their own stores (e.g., `interface AppContext extends WorkspaceContext`).
1872
1894
  */
1873
- interface WorkspaceContext {
1895
+ type WorkspaceContext<ProjectMetadata extends Record<string, any> = Record<string, any>, IndexExtentions extends Record<string, Record<string, any>> = Record<string, Record<string, any>>, StoreExtensions = any> = {
1874
1896
  /** Store for managing system personas and roles. */
1875
1897
  roles: RoleStore;
1876
1898
  /** Store for managing global and session-level user preferences. */
@@ -1888,10 +1910,10 @@ interface WorkspaceContext {
1888
1910
  /** Optional registry for managing available tools. */
1889
1911
  tools?: ToolRegistry;
1890
1912
  /** The current state of the workspace. */
1891
- workspace: Workspace;
1913
+ workspace: Workspace<ProjectMetadata, IndexExtentions>;
1892
1914
  /** The underlying database used by the workspace */
1893
1915
  db: WorkspaceDatabase;
1894
- }
1916
+ } & StoreExtensions;
1895
1917
  /**
1896
1918
  * Ranks and filters context entries by relevance to the current conversation.
1897
1919
  * The default implementation uses token overlap and recency weighting, but
@@ -1954,9 +1976,10 @@ interface LLMAdapter<TRequestParams extends Record<string, any> = {}> {
1954
1976
  /**
1955
1977
  * Returns the current state of the adapter. Callable at any time without a prompt.
1956
1978
  *
1979
+ * @param model - The model whose params we want to query.
1957
1980
  * @returns The adapter's status, including context windows and rate limits.
1958
1981
  */
1959
- status(): Promise<AdapterStatus>;
1982
+ status(model?: string): Promise<AdapterStatus>;
1960
1983
  /**
1961
1984
  * Processes a Prompt into a PreparedPrompt — the complete, final representation of what the model will receive.
1962
1985
  *
@@ -1967,6 +1990,42 @@ interface LLMAdapter<TRequestParams extends Record<string, any> = {}> {
1967
1990
  prompt: Prompt;
1968
1991
  } & TRequestParams): Promise<PreparedPrompt>;
1969
1992
  }
1993
+ interface LLMAdapterStatic<TRequestParams extends Record<string, any> = {}> {
1994
+ /** Lists all model profiles that can be used with this adapter. */
1995
+ models(): ModelProfile[];
1996
+ new (...args: any[]): LLMAdapter<TRequestParams>;
1997
+ }
1998
+ interface ModelProfile {
1999
+ /** Provider identifier, e.g. "google". */
2000
+ provider: string;
2001
+ /** Canonical model string as accepted by the API, e.g. "gemini-2.0-flash". */
2002
+ name: string;
2003
+ /** Context window and output limits. */
2004
+ window: AdapterStatus["window"];
2005
+ /** Capability flags. */
2006
+ feature: AdapterStatus["feature"];
2007
+ /** Pricing tiers. */
2008
+ pricing: AdapterStatus["pricing"];
2009
+ /**
2010
+ * Hard rate limit capacity as enforced by the provider.
2011
+ * Does not include runtime state (load, timeout).
2012
+ */
2013
+ capacity: AdapterStatus["rate"]["capacity"];
2014
+ }
2015
+ interface ModelRegistry {
2016
+ /**
2017
+ * Returns the profile for a model, or undefined if the model is unknown.
2018
+ * Callers should treat an undefined return as a configuration error.
2019
+ */
2020
+ get(model: string): ModelProfile | undefined;
2021
+ /** Lists all registered profiles, optionally filtered by provider. */
2022
+ list(provider?: string): ModelProfile[];
2023
+ /**
2024
+ * Registers or replaces a model profile. Useful for preview models,
2025
+ * fine-tunes, or updated specs that postdate the bundled defaults.
2026
+ */
2027
+ register(profile: ModelProfile): void;
2028
+ }
1970
2029
  /**
1971
2030
  * Analyzes assistant turn output for workspace side effects.
1972
2031
  * Implementations scan blocks and emit Commands that the Session dispatches.
@@ -1976,12 +2035,12 @@ interface TurnProcessor {
1976
2035
  * Scans an assistant turn for actionable blocks.
1977
2036
  *
1978
2037
  * @param turn - The turn containing blocks to process.
1979
- * @param sessionId - The UUID of the session the turn belongs to.
2038
+ * @param session - The UUID of the session the turn belongs to.
1980
2039
  * @returns Commands to dispatch against the workspace.
1981
2040
  */
1982
2041
  process(turn: {
1983
2042
  blocks: BaseContentBlock<string>[];
1984
- }, sessionId?: UUID): BaseCommand[];
2043
+ }, session: UUID): BaseCommand[];
1985
2044
  }
1986
2045
  /**
1987
2046
  * Compresses old transcript turns to reclaim token budget.
@@ -2080,18 +2139,7 @@ declare class WorkspaceManager {
2080
2139
  * @returns unsubscribe
2081
2140
  */
2082
2141
  subscribe<K extends keyof WorkspaceEvents>(event: K, listener: (payload: WorkspaceEvents[K]) => void): () => void;
2083
- ctx(): {
2084
- context: ContextStore;
2085
- roles: RoleStore;
2086
- preferences: PreferenceStore;
2087
- sessions: SessionStore;
2088
- topics: TopicStore;
2089
- blobs: BlobStore;
2090
- turns: TurnStore;
2091
- tools?: ToolRegistry | undefined;
2092
- db: WorkspaceDatabase;
2093
- workspace: Workspace<Record<string, any>>;
2094
- };
2142
+ ctx(): WorkspaceContext;
2095
2143
  }
2096
2144
 
2097
2145
  declare class WorkspaceApi {
@@ -2251,6 +2299,12 @@ declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
2251
2299
  * implementation for Browsers and Edge environments to avoid stack overflows.
2252
2300
  */
2253
2301
  declare function bufferToBase64(buffer: Uint8Array): string;
2302
+ /**
2303
+ * Short, deterministic hash of a string (4 chars in base36).
2304
+ * Suitable for AI-friendly reference tokens.
2305
+ */
2306
+ declare function shortHash(s: string, length?: number): string;
2307
+ declare function getExtension<K extends string, V>(index: Index, key: K): Record<string, V>;
2254
2308
 
2255
2309
  interface CreateWorkspaceParams {
2256
2310
  db: Database;
@@ -2264,6 +2318,7 @@ interface CreateWorkspaceParams {
2264
2318
  extensionSchemas?: SchemaDefinition[];
2265
2319
  extensionReducers?: Record<string, WorkspaceReducer<any>>;
2266
2320
  extensionMiddleware?: WorkspaceMiddleware[];
2321
+ extensionStores?: (ctx: Omit<WorkspaceContext, "workspace">) => Record<string, any>;
2267
2322
  }
2268
2323
  /**
2269
2324
  * Boot factory for the Workspace library.
@@ -2272,7 +2327,7 @@ interface CreateWorkspaceParams {
2272
2327
  declare function createWorkspace(params: CreateWorkspaceParams): Promise<{
2273
2328
  manager: WorkspaceManager;
2274
2329
  sessions: SessionManager;
2275
- ctx: Omit<WorkspaceContext, "workspace">;
2330
+ ctx: Omit<any, "workspace">;
2276
2331
  }>;
2277
2332
 
2278
- export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTopic, type AddTurn, type AuthRequest, type BackendError, type BaseCommand, type BaseContentBlock, type BlobCommand, type BlobError, type BlobMediaType, type BlobRecord, type BlobRef, type BlobResolver, type BranchInfo, type BranchTurn, COLLECTIONS, type Collections, type Command, type ContentBlock, type Context, type ContextContent, type ContextRetriever, type ContextSummary, type CreateSession, type CreateWorkspace, type CreateWorkspaceParams, type DeepPartial, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTopic, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, EMPTY_SYSTEM_ROLE, type EditTurn, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type InvalidCommandError, type LLMAdapter, LRUCache, type MergeTopics, type ModelConstraint, type ModelConstraintMap, type ModelName, type NotFoundError, type OverrideSessionPreferences, type PermissionDeniedError, type PermissionGuard, type Preference, type PreferenceSummary, type Project, type PromptBuilder, type PromptBuilderOptions, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type ResolvedSession, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionMetadata, type SessionSnapshot, type Settings, type Summarizer, type SummaryBlock, type SwitchSessionRole, type SystemActor, type TextBlock, type ThinkingBlock, type Timestamp, type ToolCall, type ToolCallCommand, type ToolRegistry, type ToolResultBlock, type ToolSummary, type ToolUseBlock, type Topic, type TopicIndex, type Turn, TurnBuilder, type TurnKey, type TurnNode, type TurnProcessor, type TurnRef, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type UpdateSession, type UpdateTopic, type UpdateTurn, type Workspace, type WorkspaceBundle, type WorkspaceContext, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, type WorkspaceMiddleware, type WorkspaceReducer, bufferToBase64, computeSHA256, createWorkspace, createWorkspaceDatabase, del, error, merge, ok, omitNullUndefined, success };
2333
+ export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTopic, type AddTurn, type AuthRequest, type BackendError, type BaseCommand, type BaseContentBlock, type BlobCommand, type BlobError, type BlobMediaType, type BlobRecord, type BlobRef, type BlobResolver, type BranchInfo, type BranchTurn, COLLECTIONS, type Collections, type Command, type ContentBlock, type Context, type ContextContent, type ContextRetriever, type ContextSummary, type CreateSession, type CreateWorkspace, type CreateWorkspaceParams, type DeepPartial, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTopic, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, EMPTY_SYSTEM_ROLE, type EditTurn, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexExtensions, type InvalidCommandError, type LLMAdapter, type LLMAdapterStatic, LRUCache, type MergeTopics, type ModelConstraint, type ModelConstraintMap, type ModelName, type ModelProfile, type ModelRegistry, type NotFoundError, type OverrideSessionPreferences, type PermissionDeniedError, type PermissionGuard, type Preference, type PreferenceSummary, type Project, type PromptBuilder, type PromptBuilderOptions, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type ResolvedSession, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionMetadata, type SessionSnapshot, type Settings, type Summarizer, type SummaryBlock, type SwitchSessionRole, type SystemActor, type TextBlock, type ThinkingBlock, type Timestamp, type ToolCall, type ToolCallCommand, type ToolRegistry, type ToolResultBlock, type ToolSummary, type ToolUseBlock, type Topic, type TopicIndex, type Turn, TurnBuilder, type TurnKey, type TurnNode, type TurnProcessor, type TurnRef, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type UpdateSession, type UpdateTopic, type UpdateTurn, type Workspace, type WorkspaceBundle, type WorkspaceContext, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, type WorkspaceMiddleware, type WorkspaceReducer, bufferToBase64, computeSHA256, createWorkspace, createWorkspaceDatabase, del, error, getExtension, merge, ok, omitNullUndefined, shortHash, success };
package/index.d.ts CHANGED
@@ -944,6 +944,9 @@ interface SessionMetadata {
944
944
  created?: Timestamp;
945
945
  /** UTC timestamp of the last activity within the session. */
946
946
  updated?: Timestamp;
947
+ /** The current model being use by the session */
948
+ model?: string;
949
+ [key: string]: any;
947
950
  };
948
951
  /** The current chronological leaf-node of the conversation DAG. */
949
952
  head?: {
@@ -1018,8 +1021,9 @@ interface TopicIndex {
1018
1021
  entries?: number;
1019
1022
  };
1020
1023
  }
1021
- /** The complete in-memory read-model of the Workspace state. */
1022
- interface Index {
1024
+ type IndexExtensions = Record<string, Record<string, any>>;
1025
+ interface Index<T extends IndexExtensions = IndexExtensions> {
1026
+ /** The complete in-memory read-model of the Workspace state. */
1023
1027
  /** Lookup dictionary of Roles by their string name. */
1024
1028
  roles: Record<string, RoleSummary>;
1025
1029
  /** Lookup dictionary of Preferences by their UUID. */
@@ -1034,9 +1038,10 @@ interface Index {
1034
1038
  blobs: Record<SHA256, BlobRecord>;
1035
1039
  /** Lookup dictionary of registered Tool capabilities by their string name. */
1036
1040
  tools: Record<string, ToolSummary>;
1041
+ extensions: T;
1037
1042
  }
1038
1043
  /** The root container for a user's workspace. */
1039
- interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>> {
1044
+ interface Workspace<ProjectMetadata extends Record<string, any> = Record<string, any>, Extentions extends Record<string, Record<string, any>> = IndexExtensions> {
1040
1045
  /** Unique identifier for the entire workspace environment. */
1041
1046
  id: UUID;
1042
1047
  /** Global user and systemic settings. */
@@ -1044,7 +1049,7 @@ interface Workspace<ProjectMetadata extends Record<string, any> = Record<string,
1044
1049
  /** High-level project metadata. */
1045
1050
  project: Project<ProjectMetadata>;
1046
1051
  /** The in-memory read-projection of all underlying stores. */
1047
- index: Index;
1052
+ index: Index<Extentions>;
1048
1053
  }
1049
1054
  /**
1050
1055
  * Format used for exporting/importing a complete workspace state,
@@ -1433,6 +1438,8 @@ interface SessionSnapshot {
1433
1438
  id: UUID;
1434
1439
  /** Top-level session definition fields. */
1435
1440
  meta: SessionMetadata;
1441
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1442
+ model?: string;
1436
1443
  /** The active role — persona, instructions, role-level constraints. */
1437
1444
  role: Role;
1438
1445
  /** Unfiltered, unranked preferences attached strictly to the role or session. */
@@ -1467,6 +1474,8 @@ interface SessionSnapshot {
1467
1474
  * - Uploading inline blobs to the provider where required.
1468
1475
  */
1469
1476
  interface Prompt {
1477
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1478
+ model?: string;
1470
1479
  /** Correlates this prompt to its session for logging and evaluation. */
1471
1480
  session: UUID;
1472
1481
  /** System-level instructions, context, and preferences. */
@@ -1540,7 +1549,7 @@ interface AdapterStatus {
1540
1549
  };
1541
1550
  /** Pricing tiers for this model. */
1542
1551
  pricing: Array<{
1543
- unit: 'token' | 'call';
1552
+ unit: 'token' | 'call' | "image";
1544
1553
  /** Exponent: price is per 10^scale units. */
1545
1554
  scale: number;
1546
1555
  /** Price per unit in USD. */
@@ -1561,7 +1570,7 @@ interface AdapterStatus {
1561
1570
  timeout?: number;
1562
1571
  /** The hard limits enforced by the provider. */
1563
1572
  capacity: Array<{
1564
- unit: 'token' | 'call';
1573
+ unit: 'token' | 'call' | string;
1565
1574
  /** Maximum units allowed per period. */
1566
1575
  max: number;
1567
1576
  /** Period length in seconds. */
@@ -1580,20 +1589,33 @@ interface ExecuteResult {
1580
1589
  /** Side-effect commands to dispatch against the workspace. */
1581
1590
  effects: BaseCommand[];
1582
1591
  }
1592
+ /**
1593
+ * A single labelled section of the system prompt.
1594
+ * Mirrors PreparedPrompt.system exactly — the assembler's output is stored
1595
+ * there directly, giving callers full inspection without re-parsing the string.
1596
+ */
1597
+ interface PromptSection {
1598
+ /**
1599
+ * Origin label for this section.
1600
+ * Core sections use fixed labels: 'operating-system' | 'persona' |
1601
+ * 'preferences' | 'context' | 'instructions'.
1602
+ * Extensions carry whatever label the injector provides.
1603
+ */
1604
+ label: string;
1605
+ /** Text content exactly as it will be sent to the model. */
1606
+ content: string;
1607
+ /** Optional structured metadata for richer UI display or tooling. */
1608
+ metadata?: Record<string, any>;
1609
+ }
1583
1610
  /**
1584
1611
  * The complete, final prompt exactly as the model will receive it.
1585
1612
  * Generic, provider-agnostic, fully inspectable, and executable.
1586
1613
  */
1587
1614
  interface PreparedPrompt {
1615
+ /** Model identifier (e.g., "claude-sonnet-4-6", "gemini-2.0-flash"). */
1616
+ model: string;
1588
1617
  /** The complete system instruction broken into labelled sections for inspection. */
1589
- system: Array<{
1590
- /** Origin label for this section (e.g., "persona", "context:project-brief"). */
1591
- label: string;
1592
- /** Text content exactly as it will be sent to the model. */
1593
- content: string;
1594
- /** Optional structured metadata for richer UI display. */
1595
- metadata?: Record<string, any>;
1596
- }>;
1618
+ instructions: Array<PromptSection>;
1597
1619
  /** Final transcript turns that will be sent after adapter-level truncation. */
1598
1620
  transcript: Turn[];
1599
1621
  /** Final context entries included after adapter-level truncation. */
@@ -1870,7 +1892,7 @@ type Collections = typeof COLLECTIONS[keyof typeof COLLECTIONS];
1870
1892
  * The full set of stores passed to every reducer and middleware call.
1871
1893
  * Applications extend this with their own stores (e.g., `interface AppContext extends WorkspaceContext`).
1872
1894
  */
1873
- interface WorkspaceContext {
1895
+ type WorkspaceContext<ProjectMetadata extends Record<string, any> = Record<string, any>, IndexExtentions extends Record<string, Record<string, any>> = Record<string, Record<string, any>>, StoreExtensions = any> = {
1874
1896
  /** Store for managing system personas and roles. */
1875
1897
  roles: RoleStore;
1876
1898
  /** Store for managing global and session-level user preferences. */
@@ -1888,10 +1910,10 @@ interface WorkspaceContext {
1888
1910
  /** Optional registry for managing available tools. */
1889
1911
  tools?: ToolRegistry;
1890
1912
  /** The current state of the workspace. */
1891
- workspace: Workspace;
1913
+ workspace: Workspace<ProjectMetadata, IndexExtentions>;
1892
1914
  /** The underlying database used by the workspace */
1893
1915
  db: WorkspaceDatabase;
1894
- }
1916
+ } & StoreExtensions;
1895
1917
  /**
1896
1918
  * Ranks and filters context entries by relevance to the current conversation.
1897
1919
  * The default implementation uses token overlap and recency weighting, but
@@ -1954,9 +1976,10 @@ interface LLMAdapter<TRequestParams extends Record<string, any> = {}> {
1954
1976
  /**
1955
1977
  * Returns the current state of the adapter. Callable at any time without a prompt.
1956
1978
  *
1979
+ * @param model - The model whose params we want to query.
1957
1980
  * @returns The adapter's status, including context windows and rate limits.
1958
1981
  */
1959
- status(): Promise<AdapterStatus>;
1982
+ status(model?: string): Promise<AdapterStatus>;
1960
1983
  /**
1961
1984
  * Processes a Prompt into a PreparedPrompt — the complete, final representation of what the model will receive.
1962
1985
  *
@@ -1967,6 +1990,42 @@ interface LLMAdapter<TRequestParams extends Record<string, any> = {}> {
1967
1990
  prompt: Prompt;
1968
1991
  } & TRequestParams): Promise<PreparedPrompt>;
1969
1992
  }
1993
+ interface LLMAdapterStatic<TRequestParams extends Record<string, any> = {}> {
1994
+ /** Lists all model profiles that can be used with this adapter. */
1995
+ models(): ModelProfile[];
1996
+ new (...args: any[]): LLMAdapter<TRequestParams>;
1997
+ }
1998
+ interface ModelProfile {
1999
+ /** Provider identifier, e.g. "google". */
2000
+ provider: string;
2001
+ /** Canonical model string as accepted by the API, e.g. "gemini-2.0-flash". */
2002
+ name: string;
2003
+ /** Context window and output limits. */
2004
+ window: AdapterStatus["window"];
2005
+ /** Capability flags. */
2006
+ feature: AdapterStatus["feature"];
2007
+ /** Pricing tiers. */
2008
+ pricing: AdapterStatus["pricing"];
2009
+ /**
2010
+ * Hard rate limit capacity as enforced by the provider.
2011
+ * Does not include runtime state (load, timeout).
2012
+ */
2013
+ capacity: AdapterStatus["rate"]["capacity"];
2014
+ }
2015
+ interface ModelRegistry {
2016
+ /**
2017
+ * Returns the profile for a model, or undefined if the model is unknown.
2018
+ * Callers should treat an undefined return as a configuration error.
2019
+ */
2020
+ get(model: string): ModelProfile | undefined;
2021
+ /** Lists all registered profiles, optionally filtered by provider. */
2022
+ list(provider?: string): ModelProfile[];
2023
+ /**
2024
+ * Registers or replaces a model profile. Useful for preview models,
2025
+ * fine-tunes, or updated specs that postdate the bundled defaults.
2026
+ */
2027
+ register(profile: ModelProfile): void;
2028
+ }
1970
2029
  /**
1971
2030
  * Analyzes assistant turn output for workspace side effects.
1972
2031
  * Implementations scan blocks and emit Commands that the Session dispatches.
@@ -1976,12 +2035,12 @@ interface TurnProcessor {
1976
2035
  * Scans an assistant turn for actionable blocks.
1977
2036
  *
1978
2037
  * @param turn - The turn containing blocks to process.
1979
- * @param sessionId - The UUID of the session the turn belongs to.
2038
+ * @param session - The UUID of the session the turn belongs to.
1980
2039
  * @returns Commands to dispatch against the workspace.
1981
2040
  */
1982
2041
  process(turn: {
1983
2042
  blocks: BaseContentBlock<string>[];
1984
- }, sessionId?: UUID): BaseCommand[];
2043
+ }, session: UUID): BaseCommand[];
1985
2044
  }
1986
2045
  /**
1987
2046
  * Compresses old transcript turns to reclaim token budget.
@@ -2080,18 +2139,7 @@ declare class WorkspaceManager {
2080
2139
  * @returns unsubscribe
2081
2140
  */
2082
2141
  subscribe<K extends keyof WorkspaceEvents>(event: K, listener: (payload: WorkspaceEvents[K]) => void): () => void;
2083
- ctx(): {
2084
- context: ContextStore;
2085
- roles: RoleStore;
2086
- preferences: PreferenceStore;
2087
- sessions: SessionStore;
2088
- topics: TopicStore;
2089
- blobs: BlobStore;
2090
- turns: TurnStore;
2091
- tools?: ToolRegistry | undefined;
2092
- db: WorkspaceDatabase;
2093
- workspace: Workspace<Record<string, any>>;
2094
- };
2142
+ ctx(): WorkspaceContext;
2095
2143
  }
2096
2144
 
2097
2145
  declare class WorkspaceApi {
@@ -2251,6 +2299,12 @@ declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
2251
2299
  * implementation for Browsers and Edge environments to avoid stack overflows.
2252
2300
  */
2253
2301
  declare function bufferToBase64(buffer: Uint8Array): string;
2302
+ /**
2303
+ * Short, deterministic hash of a string (4 chars in base36).
2304
+ * Suitable for AI-friendly reference tokens.
2305
+ */
2306
+ declare function shortHash(s: string, length?: number): string;
2307
+ declare function getExtension<K extends string, V>(index: Index, key: K): Record<string, V>;
2254
2308
 
2255
2309
  interface CreateWorkspaceParams {
2256
2310
  db: Database;
@@ -2264,6 +2318,7 @@ interface CreateWorkspaceParams {
2264
2318
  extensionSchemas?: SchemaDefinition[];
2265
2319
  extensionReducers?: Record<string, WorkspaceReducer<any>>;
2266
2320
  extensionMiddleware?: WorkspaceMiddleware[];
2321
+ extensionStores?: (ctx: Omit<WorkspaceContext, "workspace">) => Record<string, any>;
2267
2322
  }
2268
2323
  /**
2269
2324
  * Boot factory for the Workspace library.
@@ -2272,7 +2327,7 @@ interface CreateWorkspaceParams {
2272
2327
  declare function createWorkspace(params: CreateWorkspaceParams): Promise<{
2273
2328
  manager: WorkspaceManager;
2274
2329
  sessions: SessionManager;
2275
- ctx: Omit<WorkspaceContext, "workspace">;
2330
+ ctx: Omit<any, "workspace">;
2276
2331
  }>;
2277
2332
 
2278
- export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTopic, type AddTurn, type AuthRequest, type BackendError, type BaseCommand, type BaseContentBlock, type BlobCommand, type BlobError, type BlobMediaType, type BlobRecord, type BlobRef, type BlobResolver, type BranchInfo, type BranchTurn, COLLECTIONS, type Collections, type Command, type ContentBlock, type Context, type ContextContent, type ContextRetriever, type ContextSummary, type CreateSession, type CreateWorkspace, type CreateWorkspaceParams, type DeepPartial, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTopic, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, EMPTY_SYSTEM_ROLE, type EditTurn, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type InvalidCommandError, type LLMAdapter, LRUCache, type MergeTopics, type ModelConstraint, type ModelConstraintMap, type ModelName, type NotFoundError, type OverrideSessionPreferences, type PermissionDeniedError, type PermissionGuard, type Preference, type PreferenceSummary, type Project, type PromptBuilder, type PromptBuilderOptions, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type ResolvedSession, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionMetadata, type SessionSnapshot, type Settings, type Summarizer, type SummaryBlock, type SwitchSessionRole, type SystemActor, type TextBlock, type ThinkingBlock, type Timestamp, type ToolCall, type ToolCallCommand, type ToolRegistry, type ToolResultBlock, type ToolSummary, type ToolUseBlock, type Topic, type TopicIndex, type Turn, TurnBuilder, type TurnKey, type TurnNode, type TurnProcessor, type TurnRef, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type UpdateSession, type UpdateTopic, type UpdateTurn, type Workspace, type WorkspaceBundle, type WorkspaceContext, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, type WorkspaceMiddleware, type WorkspaceReducer, bufferToBase64, computeSHA256, createWorkspace, createWorkspaceDatabase, del, error, merge, ok, omitNullUndefined, success };
2333
+ export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTopic, type AddTurn, type AuthRequest, type BackendError, type BaseCommand, type BaseContentBlock, type BlobCommand, type BlobError, type BlobMediaType, type BlobRecord, type BlobRef, type BlobResolver, type BranchInfo, type BranchTurn, COLLECTIONS, type Collections, type Command, type ContentBlock, type Context, type ContextContent, type ContextRetriever, type ContextSummary, type CreateSession, type CreateWorkspace, type CreateWorkspaceParams, type DeepPartial, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTopic, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type DuplicateKeyError, EMPTY_SYSTEM_ROLE, type EditTurn, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexExtensions, type InvalidCommandError, type LLMAdapter, type LLMAdapterStatic, LRUCache, type MergeTopics, type ModelConstraint, type ModelConstraintMap, type ModelName, type ModelProfile, type ModelRegistry, type NotFoundError, type OverrideSessionPreferences, type PermissionDeniedError, type PermissionGuard, type Preference, type PreferenceSummary, type Project, type PromptBuilder, type PromptBuilderOptions, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type ResolvedSession, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionMetadata, type SessionSnapshot, type Settings, type Summarizer, type SummaryBlock, type SwitchSessionRole, type SystemActor, type TextBlock, type ThinkingBlock, type Timestamp, type ToolCall, type ToolCallCommand, type ToolRegistry, type ToolResultBlock, type ToolSummary, type ToolUseBlock, type Topic, type TopicIndex, type Turn, TurnBuilder, type TurnKey, type TurnNode, type TurnProcessor, type TurnRef, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type UpdateSession, type UpdateTopic, type UpdateTurn, type Workspace, type WorkspaceBundle, type WorkspaceContext, type WorkspaceDatabase, type WorkspaceError, type WorkspaceEvents, WorkspaceManager, type WorkspaceMiddleware, type WorkspaceReducer, bufferToBase64, computeSHA256, createWorkspace, createWorkspaceDatabase, del, error, getExtension, merge, ok, omitNullUndefined, shortHash, success };
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("uuid"),t=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let s;this._pendingFn=void 0;try{s={status:"ok",value:await e()}}catch(e){s={status:"error",error:e}}for(const e of t)e(s);return s}},s=class e extends Error{constructor(t,s){super(t,{cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},r=class extends s{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},i=class extends s{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},n=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,n)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(new r("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},o=class{mutex=new n({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,n)=>{i=setTimeout((()=>n(new r(s))),t)}))])}},a=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new n({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new i};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,r=null;try{if(this._done)throw new i;r=await e(),this._lastValue=r,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:r,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}};function c(e){const s={},r=s.errorHandler??(e=>console.error("EventBus Error:",e)),i=null!=s.batch?.size,n=s.batch?.size,o=s.batch?.delay??16;if(i&&(n<=0||!Number.isFinite(n)))throw new Error(`EventBus: batch.size must be a positive finite number, got ${n}.`);if(i&&(o<0||!Number.isFinite(o)))throw new Error(`EventBus: batch.delay must be a non-negative finite number, got ${o}.`);const a=s.broadcast?.channel,c=null!=a&&a.length>0,d=new Map;let u=[];const l=i?new t({delay:o}):null;let h=0,p=0;const f=new Map,m=()=>{if(!c)return null;if("undefined"==typeof BroadcastChannel)return console.warn("EventBus: BroadcastChannel is not supported in this environment. Cross-tab notifications are disabled."),null;const e=new BroadcastChannel(a);return e.onmessage=e=>{const{name:t,payload:s}=e.data;g(t,s)},e};let y=m();const w=(e,t)=>{h++,p+=t,f.set(e,(f.get(e)??0)+1)},g=(e,t)=>{const s=d.get(e);if(s&&0!==s.size)for(const i of Array.from(s))try{i(t)}catch(s){const i=s instanceof Error?s:Object.assign(new Error(String(s)),{cause:s}),n=Object.assign(i,{eventName:e,payload:t});r(n)}},_=(e,t)=>{d.has(e)||d.set(e,new Set);const s=d.get(e);return s.add(t),()=>{s.delete(t),0===s.size&&d.delete(e)}},b=()=>{const e=u;u=[];for(const{name:t,payload:s}of e){const e=performance.now();g(t,s),w(t,performance.now()-e)}};return{subscribe:(e,t)=>_(e,t),once:(e,t)=>{let s;return s=_(e,(e=>{s(),t(e)})),s},emit:({name:e,payload:t})=>{if(i)return u.push({name:e,payload:t}),u.length>=n?(l.cancel(),void b()):(l.fire((()=>b())),void y?.postMessage({name:e,payload:t}));const s=performance.now();g(e,t),w(e,performance.now()-s),y?.postMessage({name:e,payload:t})},metrics:()=>({totalEvents:h,activeSubscriptions:Array.from(d.values()).reduce(((e,t)=>e+t.size),0),eventCounts:new Map(f),averageEmitDuration:h>0?p/h:0}),clear:()=>{l?.cancel(),u=[],d.clear(),h=0,p=0,f.clear(),y?.close(),y=m()}}}var d=[{name:"role",version:"1.0.0",description:"AI persona with a system prompt and associated preference defaults.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!0},description:{name:"description",type:"string",required:!1},persona:{name:"persona",type:"string",required:!0},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},topics:{name:"topics",type:"array",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_name",fields:["name"],type:"unique"},{name:"by_label",fields:["label"],type:"normal"}],constraints:[],migrations:[]},{name:"preference",version:"1.0.0",description:"A user behavioural instruction, scoped to zero or more topics.",fields:{id:{name:"id",type:"string",required:!0},content:{name:"content",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},timestamp:{name:"timestamp",type:"string",required:!0}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"context",version:"1.0.0",description:"Injected background knowledge, scoped to topics. Content is a discriminated union.",fields:{key:{name:"key",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},content:{name:"content",type:"record",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},metadata:{name:"metadata",type:"record",required:!1}},indexes:[{name:"by_key",fields:["key"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"session",version:"1.0.0",description:"Session metadata. The head field tracks the current tip of the turn DAG.",fields:{id:{name:"id",type:"string",required:!0},label:{name:"label",type:"string",required:!0},role:{name:"role",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},metadata:{name:"metadata",type:"record",required:!1},head:{name:"head",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_role",fields:["role"],type:"normal"}],constraints:[],migrations:[]},{name:"turn",version:"1.0.0",description:["A single message in a session transcript, stored as a flat document.","The DAG is reconstructed in memory by TurnTree.buildNodeGraph() at session open time."].join(" "),fields:{id:{name:"id",type:"string",required:!0},session:{name:"session",type:"string",required:!0},version:{name:"version",type:"number",required:!0},actor:{name:"actor",type:"enum",required:!0,values:["user","assistant","tool"]},blocks:{name:"blocks",type:"array",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},role:{name:"role",type:"string",required:!1},parent:{name:"parent",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_session",fields:["session"],type:"normal"},{name:"by_session_parent",fields:["session","parent"],type:"composite"},{name:"by_session_id_ver",fields:["session","id","version"],type:"composite",unique:!0}],constraints:[],migrations:[]},{name:"topic",version:"1.0.0",description:"A categorization for context and preferences, used for retrieval.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!1},description:{name:"description",type:"string",required:!1},metadata:{name:"metadata",type:"record",required:!1},created:{name:"created",type:"string",required:!0},updated:{name:"updated",type:"string",required:!0}},indexes:[{name:"by_name",fields:["name"],type:"unique"}],constraints:[],migrations:[]}];function u(e){const t=new o({retry:!0,throws:!0}),s=new o({retry:!0,throws:!0});return{open:async(s=[])=>(await t.do((async()=>{const t=[...d,...s];await e.setupCollections(t)}))).value,collection:async t=>e.collection(t),close:async()=>(await s.do((()=>{e.close()}))).value,database:()=>e}}var l={ROLE:"role",PREFERENCE:"preference",CONTEXT:"context",SESSION:"session",TURN:"turn",BLOB:"blob",TOPIC:"topic"},h=Symbol.for("delete"),p=e=>Array.isArray(e)?[...e]:{...e};function f(e){return{ok:!0,value:e}}function m(e){return f(e)}function y(e){return{ok:!1,error:e}}var w=function(e){const t=e?.deleteMarker||h;function s(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==t)).map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e:s(e)));if("object"==typeof e){const r={};for(const[i,n]of Object.entries(e))if(n!==t)if("object"==typeof n&&null!==n){const e=s(n);void 0!==e&&(r[i]=e)}else r[i]=n;return r}return e===t?void 0:e}return function(e,r){if("object"!=typeof e||null===e)return"object"==typeof r&&null!==r?s(r):r===t?{}:r;if("object"!=typeof r||null===r)return e;const i=p(e),n=[{target:i,source:r}];for(;n.length>0;){const{target:e,source:s}=n.pop();for(const r of Object.keys(s)){const i=s[r];if(i!==t)if(Array.isArray(i))e[r]=i;else if("object"==typeof i&&null!==i){const t=r in e&&"object"==typeof e[r]&&null!==e[r]?e[r]:{};e[r]=p(t),n.push({target:e[r],source:i})}else e[r]=i;else delete e[r]}}return i}}({deleteMarker:h});async function g(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map((e=>e.toString(16).padStart(2,"0"))).join("")}var _=class{registry=new Map;middlewares=[];serializer=new a;bus;_getWorkspace;updateWorkspace;guard;_ctx;constructor(e){this._ctx=e.ctx,this._getWorkspace=e.getWorkspace,this.updateWorkspace=e.updateWorkspace,this.guard=e.guard,this.bus=e.bus}register(e,t){return this.registry.set(e,t),this}use(e){return this.middlewares.push(e),this}workspace(){return this._getWorkspace()}async dispatch(e){const t=await this.serializer.do((async()=>{if(this.guard){const t=await this.guard.authenticate({type:"command",payload:e});if(!t.ok)return y(t.error)}const t=this.registry.get(e.type);if(!t)return y({code:"INVALID_COMMAND",reason:`No reducer registered for command type: ${e.type}`});const s=this._getWorkspace(),r=await t({workspace:s,...this._ctx},e.payload);if(!r.ok)return r;let i=r.value;for(const t of this.middlewares){const r=await t({workspace:s,command:e,patch:i,...this._ctx});i=w(i,r)}return await this.updateWorkspace(i),this.bus.emit({name:"workspace:changed",payload:i}),m(i)}));if(t.error)throw t.error;return t.value}subscribe(e,t){return this.bus.subscribe(e,t)}ctx(){return{workspace:this._getWorkspace(),...this._ctx}}},b=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getMany(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?t.push(e):s.push(r)}if(s.length>0){const e=await this.collection.filter({operator:"or",conditions:s.map((e=>({field:"name",operator:"eq",value:e})))});for(const s of e){const e=s.state();this.cache.set(e.name,e),t.push(e)}}return t}referencedBy(e,t){for(const s in t.roles)if(t.roles[s].topics?.includes(e))return!0;for(const s in t.sessions)if(t.sessions[s].topics?.includes(e))return!0;for(const s in t.context)if(t.context[s].topics?.includes(e))return!0;for(const s in t.preferences)if(t.preferences[s].topics?.includes(e))return!0;return!1}};function v(e,t,s,r,i,n){const o={};for(const a of t){let t=e[a];if(!t){if("add"!==i||!n)continue;t={topic:a,contextKeys:[],preferences:[],metadata:{created:(new Date).toISOString(),updated:(new Date).toISOString(),entries:0}},n.add({name:a,created:t.metadata.created,updated:t.metadata.updated})}const c=t[r],d=c.includes(s);if("add"!==i||d){if("remove"===i&&d){const e=Math.max(0,(t.metadata.entries||0)-1);o[a]={...t,[r]:c.filter((e=>e!==s)),metadata:{...t.metadata,updated:(new Date).toISOString(),entries:e}}}}else o[a]={...t,[r]:[...c,s],metadata:{...t.metadata,updated:(new Date).toISOString(),entries:(t.metadata.entries||0)+1}}}return{index:{topics:o}}}function x(e,t,s,r){return v(e,t,s,"contextKeys","add",r)}function k(e,t,s){return v(e,t,s,"contextKeys","remove")}function O(e,t,s,r){return v(e,t,s,"preferences","add",r)}function T(e,t,s){return v(e,t,s,"preferences","remove")}var N=async e=>{if(!e.patch)return;const{workspace:t,patch:s}=e,r=t.index.topics;let i={};const n=e=>{const t=e?.index?.topics;t&&(i=w(i,t))};if(s.index?.context)for(const[i,o]of Object.entries(s.index.context)){const s=t.index.context[i];if(void 0===o&&s)n(k(r,s.topics,s.key));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(k(r,c,s.key)),a.length&&n(x(r,a,s.key,e.topics))}}else n(x(r,o.topics??[],o.key,e.topics))}if(s.index?.preferences)for(const[i,o]of Object.entries(s.index.preferences)){const s=t.index.preferences[i];if(void 0===o&&s)n(T(r,s.topics,s.id));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(T(r,c,s.id)),a.length&&n(O(r,a,s.id,e.topics))}}else n(O(r,o.topics??[],o.id,e.topics))}return Object.keys(i).length?{index:{topics:i}}:{}};var S={"role:add":async function(e,t){const{workspace:s,roles:r}=e,i=t;return s.index.roles[i.name]?y({code:"DUPLICATE_KEY",resource:"Role",key:i.name}):(await r.add(i),m({index:{roles:{[i.name]:{name:i.name,label:i.label,description:i.description,preferences:i.preferences.length}}}}))},"role:update":async function(e,t){const{workspace:s,roles:r}=e,{name:i,...n}=t;if(!s.index.roles[i])return y({code:"NOT_FOUND",resource:"Role",id:i});const o=await r.update(i,n);return o?m({index:{roles:{[i]:{name:o.name,label:o.label,description:o.description,preferences:o.preferences.length}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update role ${i} in store.`})},"role:delete":async function(e,t){const{workspace:s,roles:r}=e,{name:i}=t;return s.index.roles[i]?await r.delete(i)?m({index:{roles:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete role ${i} from store.`}):y({code:"NOT_FOUND",resource:"Role",id:i})},"preference:add":async function(e,t){const{workspace:s,preferences:r}=e,i=t;return s.index.preferences[i.id]?y({code:"DUPLICATE_KEY",resource:"Preference",key:i.id}):(await r.add(i),m({index:{preferences:{[i.id]:{id:i.id,topics:i.topics,timestamp:i.timestamp,snippet:i.content.substring(0,100)}}}}))},"preference:update":async function(e,t){const{workspace:s,preferences:r}=e,{id:i,...n}=t;if(!s.index.preferences[i])return y({code:"NOT_FOUND",resource:"Preference",id:i});const o=await r.update(i,n);return o?m({index:{preferences:{[i]:{id:o.id,topics:o.topics,timestamp:o.timestamp,snippet:o.content.substring(0,100)}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update preference ${i} in store.`})},"preference:delete":async function(e,t){const{workspace:s,preferences:r}=e,{id:i}=t;return s.index.preferences[i]?await r.delete(i)?m({index:{preferences:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete preference ${i} from store.`}):y({code:"NOT_FOUND",resource:"Preference",id:i})},"context:add":async function(e,t){const{workspace:s,context:r}=e,i=t;return s.index.context[i.key]?y({code:"DUPLICATE_KEY",resource:"Context",key:i.key}):(await r.add(i),m({index:{context:{[i.key]:{key:i.key,topics:i.topics,timestamp:i.timestamp,mime:"blob"===i.content.kind?i.content.mediaType:void 0,size:"blob"===i.content.kind?i.content.sizeBytes:void 0,metadata:i.metadata}}}}))},"context:update":async function(e,t){const{workspace:s,context:r}=e,{key:i,...n}=t;if(!s.index.context[i])return y({code:"NOT_FOUND",resource:"Context",id:i});const o=await r.update(i,n);return o?m({index:{context:{[i]:{key:o.key,topics:o.topics,timestamp:o.timestamp,mime:"blob"===o.content.kind?o.content.mediaType:void 0,size:"blob"===o.content.kind?o.content.sizeBytes:void 0,metadata:o.metadata}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update context ${i} in store.`})},"context:delete":async function(e,t){const{workspace:s,context:r}=e,{key:i}=t;return s.index.context[i]?await r.delete(i)?m({index:{context:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete context ${i} from store.`}):y({code:"NOT_FOUND",resource:"Context",id:i})},"topic:add":async function(e,t){const{workspace:s,topics:r}=e,i=t;return s.index.topics[i.name]?y({code:"DUPLICATE_KEY",resource:"Topic",key:i.name}):(await r.add(i),m({index:{topics:{[i.name]:{topic:i.name,contextKeys:[],preferences:[],metadata:{created:i.created,updated:i.updated,entries:0}}}}}))},"topic:update":async function(e,t){const{workspace:s,topics:r}=e,{name:i,...n}=t;if(!s.index.topics[i])return y({code:"NOT_FOUND",resource:"Topic",id:i});const o=await r.update(i,n);return o?m({index:{topics:{[i]:{metadata:{updated:o.updated}}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update topic ${i} in store.`})},"topic:delete":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{name:o,cascade:a}=t;if(!s.index.topics[o])return y({code:"NOT_FOUND",resource:"Topic",id:o});if(r.referencedBy(o,s.index)&&!a)return y({code:"INVALID_COMMAND",reason:`Topic '${o}' is referenced by other entities. Use 'cascade: true' to force deletion.`});if(a){for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);t&&await i.update(e,{topics:t.topics.filter((e=>e!==o))})}}for(const e in s.index.sessions){const t=s.index.sessions[e];t.topics?.includes(o)&&await n.update(e,{topics:t.topics.filter((e=>e!==o))})}}return await r.delete(o)?m({index:{topics:{[o]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete topic ${o} from store.`})},"topic:merge":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{source:o,target:a}=t;if(!s.index.topics[o]||!s.index.topics[a])return y({code:"NOT_FOUND",resource:"Topic",id:s.index.topics[o]?a:o});for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);if(t){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await i.update(e,{topics:s})}}}for(const e in s.index.sessions){const t=s.index.sessions[e];if(t.topics?.includes(o)){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await n.update(e,{topics:s})}}return await r.delete(o),m({index:{topics:{[o]:h}}})},"session:create":async function(e,t){const{workspace:s,sessions:r}=e,i=t;return s.index.sessions[i.id]?y({code:"DUPLICATE_KEY",resource:"Session",key:i.id}):(await r.add(i),m({index:{sessions:{[i.id]:{id:i.id,label:i.label,role:i.role,topics:i.topics,preferences:i.preferences,metadata:i.metadata}}}}))},"session:update":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,...n}=t;if(!s.index.sessions[i])return y({code:"NOT_FOUND",resource:"Session",id:i});const o=await r.update(i,n);return o?m({index:{sessions:{[i]:{label:o.label,role:o.role,topics:o.topics,preferences:o.preferences,metadata:o.metadata,head:o.head}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update session ${i} in store.`})},"session:fork":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,newSessionId:n,label:o}=t,a=s.index.sessions[i];if(!a)return y({code:"NOT_FOUND",resource:"Session",id:i});const c={...a,id:n,label:o||`Fork of ${a.label}`,role:t.role?t.role:a.role,topics:t.topics?t.topics:a.topics};return await r.add(c),m({index:{sessions:{[n]:{id:n,label:c.label,role:c.role,topics:c.topics,preferences:c.preferences,metadata:c.metadata,head:c.head}}}})},"session:delete":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i}=t;return s.index.sessions[i]?(await r.delete(i),m({index:{sessions:{[i]:h}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:role:switch":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,roleName:n}=t;return s.index.sessions[i]?(await r.update(i,{role:n}),m({index:{sessions:{[i]:{role:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:topics:add":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,topics:n}=t,o=s.index.sessions[i];if(!o)return y({code:"NOT_FOUND",resource:"Session",id:i});const a=Array.from(new Set([...o.topics,...n]));return await r.update(i,{topics:a}),m({index:{sessions:{[i]:{topics:a}}}})},"session:preferences:override":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,preferences:n}=t;return s.index.sessions[i]?(await r.update(i,{preferences:n}),m({index:{sessions:{[i]:{preferences:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"turn:add":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:update":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.update(o,o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:edit":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newBlocks:a,newVersion:c,roleSnapshot:d}=t,u=s.index.sessions[n];if(!u)return y({code:"NOT_FOUND",resource:"Session",id:n});const l=u.head;let h={};if(l&&l.id===o){const e=await i.get({id:l.id,version:l.version,session:n});e&&(h={...e})}const p={...h,id:o,version:c,blocks:a,role:d??h.role,timestamp:(new Date).toISOString(),parent:h.parent,actor:h.actor||"assistant",session:n};if(await i.add(p),u.head?.id===o){const e={id:o,version:c};return await r.update(n,{head:e}),m({index:{sessions:{[n]:{head:e}}}})}return m({})},"turn:branch":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:delete":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newHead:a}=t;return s.index.sessions[n]?(await i.delete({session:n,id:o,version:t.version}),a?(await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})):m({})):y({code:"NOT_FOUND",resource:"Session",id:n})},"blob:register":async function(e,t){const{blobs:s}=e,r=await s.register(t.data,t.mediaType,t.filename);if(!r.ok)return r;const i=await s.getRecord(r.value.sha256);return i?m({index:{blobs:{[i.sha256]:i}}}):y({code:"BACKEND_ERROR",reason:`Failed to retrieve registered blob record for ${r.value.sha256}`})},"blob:retain":async function(e,t){const{blobs:s}=e,r=await s.retain(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i}}})},"blob:release":async function(e,t){const{blobs:s}=e,r=await s.release(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i||h}}})},"blob:purge":async function(e,t){const{blobs:s}=e,r=await s.purge(t.sha256);return r.ok?m({index:{blobs:{[t.sha256]:h}}}):r},"blob:record_remote_id":async function(e,t){const{blobs:s}=e,{sha256:r,providerId:i,fileId:n,timestamp:o}=t,a=await s.recordRemoteId(r,i,n,o);if(!a.ok)return a;const c=await s.getRecord(r);return m({index:{blobs:{[r]:c}}})},"tool:call":async function(e,t){return m({})}},D="__system__",I=class{constructor(t,s,r){this._actor=t,this._turn=r?JSON.parse(JSON.stringify(r)):{id:e.v7(),session:s,version:0,actor:this._actor,blocks:[],timestamp:(new Date).toISOString(),role:void 0}}_turn;addText(t){const s={id:e.v7(),type:"text",text:t};return this._turn.blocks.push(s),this}addImage(t,s){const r={id:e.v7(),type:"image",ref:t,altText:s};return this._turn.blocks.push(r),this}addDocument(t,s){const r={id:e.v7(),type:"document",ref:t,title:s};return this._turn.blocks.push(r),this}addToolUse(t,s){const r={id:e.v7(),type:"tool:use",name:t,input:s};return this._turn.blocks.push(r),this}addToolResult(t,s,r){const i={id:e.v7(),type:"tool:result",useId:t,content:s,isError:r};return this._turn.blocks.push(i),this}addSummary(t){const s={id:e.v7(),type:"summary",text:t};return this._turn.blocks.push(s),this}addRoleTransition(t,s){const r={id:e.v7(),type:"role:transition",previousRole:t,newRole:s};return this._turn.blocks.push(r),this}addThinking(t){const s={id:e.v7(),type:"thinking",thinking:t};return this._turn.blocks.push(s),this}addBlock(e){return this._turn.blocks.push(e),this}deleteBlock(e){return this._turn.blocks=this._turn.blocks.filter((t=>t.id!==e)),this}editTextBlock(e,t){const s=this._turn.blocks.findIndex((t=>t.id===e));if(-1===s)throw new Error(`Block with ID ${e} not found.`);const r=this._turn.blocks[s];if("text"!==r.type)throw new Error(`Block with ID ${e} is not a TextBlock.`);return this._turn.blocks[s]={...r,text:t},this}withId(e){return this._turn.id=e,this}withVersion(e){return this._turn.version=e,this}withTimestamp(e){return this._turn.timestamp=e,this}withParent(e){return this._turn.parent=e,this}withRoleSnapshot(e){return this._turn.role=e,this}build(){return JSON.parse(JSON.stringify(this._turn))}},R=class{constructor(e,t){this.turnStore=e,this.sessionStore=t}async loadAllTurns(e){return this.turnStore.listBySession(e)}async loadHead(e){const t=await this.sessionStore.get(e);return t?.head??null}},E=class e{constructor(e,t){this.nodes=e,this._head=t}static async build(t,s){const[r,i]=await Promise.all([s.loadAllTurns(t),s.loadHead(t)]),n=function(e,t){const s=function(e,t){if(!t)return new Set;const s=new Map;for(const t of e)s.set(`${t.id}:${t.version}`,t);const r=new Set;let i=t;for(;i;){const e=`${i.id}:${i.version}`;if(r.has(e))break;r.add(e);const t=s.get(e);if(!t)break;i=t.parent}return r}(e,t),r={},i={};for(const t of e){r[t.id]||(r[t.id]={id:t.id,versions:{},activeVersion:t.version,actor:t.actor,blocks:t.blocks,timestamp:t.timestamp,roleSnapshot:t.role,parent:t.parent,children:{}},i[t.id]=new Set);const e=r[t.id];e.versions[t.version]=t;const n=s.has(`${t.id}:${t.version}`),o=s.has(`${t.id}:${e.activeVersion}`);if(n&&(!o||t.version>=e.activeVersion)&&(e.activeVersion=t.version,e.blocks=t.blocks,e.timestamp=t.timestamp,e.roleSnapshot=t.role,e.parent=t.parent),t.parent){const e=`${t.parent.id}:${t.parent.version}`;if(i[t.parent.id]||(i[t.parent.id]=new Set),!i[t.parent.id].has(e+":"+t.id)){i[t.parent.id].add(e+":"+t.id),r[t.parent.id]||(r[t.parent.id]={id:t.parent.id,versions:{},activeVersion:t.parent.version,actor:"user",blocks:[],timestamp:"",roleSnapshot:void 0,children:{}});const s=r[t.parent.id];s.children[t.parent.version]||(s.children[t.parent.version]=[]),s.children[t.parent.version].push(t.id)}}}return r}(r,i);return new e(n,i)}head(){return this._head}chain(){if(!this._head)return[];const e=[];let t=this._head.id;for(;t;){const s=this.nodes[t];if(!s)break;e.push(s),t=s.parent?.id??null}return e.reverse()}getTurnSiblings(e){const t=this.nodes[e];if(!t)return[];if(!t.parent)return Object.values(this.nodes).filter((e=>!e.parent));const s=this.nodes[t.parent.id];if(!s)return[t];const r=s.children[t.parent.version];return r?r.map((e=>this.nodes[e])).filter((e=>!!e)):[t]}branchInfo(e){const t=this.nodes[e];if(!t)return{versions:[],currentIndex:-1,total:0,hasPrev:!1,hasNext:!1};const s=Object.keys(t.versions).map(Number).sort(((e,t)=>e-t)),r=s.indexOf(t.activeVersion);return{versions:s,currentIndex:r,total:s.length,hasPrev:r>0,hasNext:r<s.length-1}}graph(){return{...this.nodes}}};var q=class{constructor(e){this.manager=e}get workspace(){return this.manager.workspace()}roles(){return this.manager.ctx().roles.list()}role(e){return this.manager.ctx().roles.get(e)}async createRole(e,t,s,r,i=[]){if(this.workspace.index.roles[e])return y({code:"DUPLICATE_KEY",resource:"role",key:e});const n={name:e,label:t,description:r,persona:s,preferences:i,topics:[]};return this.manager.dispatch({type:"role:add",payload:n,timestamp:(new Date).toISOString()})}async updateRole(e,t){return this.workspace.index.roles[e]?this.manager.dispatch({type:"role:update",payload:{name:e,...t},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"role",id:e})}async deleteRole(e){const t=this.workspace;if(!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});return Object.values(t.index.sessions).some((t=>t.role===e))?y({code:"INVALID_COMMAND",reason:`Cannot delete role "${e}" — it is still referenced by one or more sessions`}):this.manager.dispatch({type:"role:delete",payload:{name:e},timestamp:(new Date).toISOString()})}async addPreference(e,t){const s={id:crypto.randomUUID(),content:e,topics:t,timestamp:(new Date).toISOString()};return this.manager.dispatch({type:"preference:add",payload:s,timestamp:s.timestamp})}preferences(){return this.manager.ctx().preferences.list()}async addContext(e,t,s,r){const i={key:e,topics:s,content:t,timestamp:(new Date).toISOString(),metadata:r};return this.manager.dispatch({type:"context:add",payload:i,timestamp:i.timestamp})}context(){return this.manager.ctx().context.list()}async registerBlob(e,t,s){const r=await this.manager.dispatch({type:"blob:register",payload:{data:e,mediaType:t,filename:s},timestamp:(new Date).toISOString()});if(!r.ok)return y(r.error);const i=r.value,n=i?.index?.blobs;if(!n)return y({code:"BACKEND_ERROR",reason:"Blob registration succeeded but no blobs patch returned"});const o=Object.keys(n)[0];if(!o)return y({code:"BACKEND_ERROR",reason:"No SHA256 in patch"});const a=n[o];if(!a)return y({code:"BACKEND_ERROR",reason:"Blob record missing"});return f({sha256:o,ref:{sha256:o,mediaType:a.mediaType,sizeBytes:a.sizeBytes,filename:a.filename,previewUrl:a.previewUrl}})}},F=class e{constructor(e,t,s,r){this._id=e,this.manager=t,this.processor=s,this.turnRepository=r,this.workspace=new q(t)}workspace;_role=void 0;_preferences=[];tree;static async create(t,s,r){const i=new R(s.ctx().turns,s.ctx().sessions),n=new e(t,s,r,i);return await n._setRole(),await n._setPreference(),await n.refreshTurnTree(),n}async _setRole(){const e=this.meta(),t=await this.manager.ctx().roles.get(e.role);t&&(this._role=t)}async _setPreference(){const e=this.meta();this._preferences=await this.manager.ctx().preferences.load(e.preferences)}id(){return this._id}ws(){return this.manager.workspace()}meta(){return this.ws().index.sessions[this._id]}label(){return this.meta()?.label}role(){return this._role}topics(){return this.meta()?.topics??[]}preferences(){return this._preferences}head(){return this.meta()?.head??null}turns(){return this.tree.chain()}async siblings(e){return this.tree.getTurnSiblings(e)}async branchInfo(e){return this.tree.branchInfo(e)}async getTurn(e){return this.tree.graph()[e]}async rename(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,label:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setTopics(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async addTopics(e){return this.meta()?this.dispatch({type:"session:topics:add",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setPreferences(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t=await this.dispatch({type:"session:preferences:override",payload:{sessionId:this._id,preferences:e},timestamp:(new Date).toISOString()});return t.ok&&await this._setPreference(),t}async fork(e,t,s,r){return this.meta()?this.dispatch({type:"session:fork",payload:{sessionId:this._id,newSessionId:e,label:t,role:s,topics:r},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async dispatch(e){return this.manager.dispatch(e)}async switchRole(e){const t=this.ws();if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(e!==D&&!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});const s=await this.dispatch({type:"session:update",payload:{sessionId:this._id,role:e},timestamp:(new Date).toISOString()});return s.ok&&await this._setRole(),s}async addTurn(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t={...e,session:this._id,version:e.version??0,parent:!e.parent&&this.head()?this.head():void 0},s=await this.dispatch({type:"turn:add",payload:{sessionId:this._id,turn:t},timestamp:t.timestamp});return s.ok&&await this.refreshTurnTree(),s}async recordUserTurn(e){return this.meta()?this.addTurn(e):y({code:"NOT_FOUND",resource:"session",id:this._id})}async recordAssistantTurn(e,t){const s=this.ws();if(!s)return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!s.index.sessions[this._id])return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.processor.process(e,this._id);let i={};const n=[];for(const e of r){const t=await this.manager.dispatch(e);if(t.ok)i=w(i,t.value);else{if("PERMISSION_DENIED"!==t.error.code||e.synthetic)return t;{const t=this.describeCommand(e);n.push({cmd:e,description:t})}}}const o=await this.addTurn(e);if(!o.ok)return o;if(i=w(i,o.value),t&&n.length>0){const e=this.buildDenialTurn(n),t=await this.addTurn(e);t.ok&&(i=w(i,t.value))}return f(i)}buildDenialTurn(e){const t=new I("user",this._id);for(const s of e)t.addText(`[System] User denied: ${s.description}.`);return t.build()}describeCommand(e){return"tool:call"===e.type?`tool execution: ${e.payload.tool}`:`command: ${e.type}`}async editTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph()[e];if(!r)return y({code:"NOT_FOUND",resource:"turn",id:e});const i=r.versions[r.activeVersion],n=r.activeVersion+1,o=await this.dispatch({type:"turn:edit",payload:{sessionId:this._id,turnId:e,newBlocks:t,roleSnapshot:s??i.role,newVersion:n},timestamp:(new Date).toISOString()});return o.ok&&await this.refreshTurnTree(),o}async branch(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(!e.parent)return y({code:"INVALID_COMMAND",reason:"branch requires turn.parent to be set"});const t=await this.dispatch({type:"turn:branch",payload:{sessionId:this._id,turn:{...e,session:this._id}},timestamp:e.timestamp});return t.ok&&await this.refreshTurnTree(),t}async deleteTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph();if(!r[e]?.versions[t])return y({code:"NOT_FOUND",resource:"turn version",id:`${e}:${t}`});const i=await this.dispatch({type:"turn:delete",payload:{sessionId:this._id,turnId:e,version:t,newHead:s},timestamp:(new Date).toISOString()});return i.ok&&await this.refreshTurnTree(),i}async switchVersionLeft(e){return this.switchVersion(e,-1)}async switchVersionRight(e){return this.switchVersion(e,1)}async switchVersion(e,t){if(!this.ws())return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const s=this.tree.graph()[e];if(!s)return y({code:"NOT_FOUND",resource:"turn",id:e});const r=Object.keys(s.versions).map(Number).sort(((e,t)=>e-t)),i=r.indexOf(s.activeVersion);if(-1===i)return y({code:"INVALID_COMMAND",reason:"Active version not found"});const n=i+t;if(n<0||n>=r.length)return y({code:"INVALID_COMMAND",reason:`No ${t<0?"previous":"next"} version available for turn ${e}`});const o=r[n],a=this.findSubtreeTip(this.tree.graph(),e,o),c=await this.dispatch({type:"session:update",payload:{sessionId:this._id,head:a},timestamp:(new Date).toISOString()});return c.ok&&await this.refreshTurnTree(),c}async snapshot(){const e=this,t=e.meta();if(!t)return;const s=e.ws(),r=e._role;if(!r)return;const i=await e.manager.ctx().context.getByTopics(s.index,t.topics),n=Array.from(new Set([...r.preferences,...t.preferences])),o=n.length>0?await e.manager.ctx().preferences.load(n):e._preferences,a=e.tree.chain().map((e=>e.versions[e.activeVersion])).filter((e=>!!e)),c=[...a].reverse().find((e=>"user"===e.actor));return{id:e._id,meta:t,role:r,preferences:o,context:i,transcript:a,topics:t.topics,instructions:s.settings?.prompt,constraints:{role:r.constraints,session:t.constraints,turn:c?.constraints}}}async refreshTurnTree(){this.tree=await E.build(this._id,this.turnRepository)}findSubtreeTip(e,t,s){let r=t,i=s;for(;;){const t=e[r];if(!t)break;const s=t.children[i];if(!s||0===s.length)break;const n=s[0],o=e[n];if(!o)break;r=n,i=o.activeVersion}return{id:r,version:i}}},U=class{constructor(e,t){this.manager=e,this.processor=t}openOnce=new Map;async open(e){let t=this.openOnce.get(e);t||(t=new o,this.openOnce.set(e,t));const s=await t.do((async()=>{if(!this.manager.workspace().index.sessions[e])throw new Error(`Session ${e} not found in workspace index`);return F.create(e,this.manager,this.processor)}));if(s.error)throw s.error;return s.value}close(e){this.openOnce.delete(e)}async delete(e){const t=await this.manager.dispatch({type:"session:delete",payload:{sessionId:e},timestamp:(new Date).toISOString()});if(t.ok)return this.close(e),t.value=void 0,t;throw t.error}async create(t){const s=e.v7(),r=await this.manager.dispatch({type:"session:create",payload:{...t,id:s},timestamp:(new Date).toISOString()});if(r.ok)return this.open(s);throw r.error}list(){return Object.values(this.manager.workspace().index.sessions)}metadata(e){return this.manager.workspace().index.sessions[e]}},A=class{constructor(e,t,s){this.storage=e,this.cache=t,this.bus=s}async register(e,t,s){const r=await g(e),i=await this.getRecord(r);if(i){const e={...i,refCount:i.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(e),this.cache.set(r,e),f(this.reference(e))}const n={sha256:r,mediaType:t,sizeBytes:e.byteLength,filename:s,refCount:1,remoteIds:{},createdAt:(new Date).toISOString(),lastUsedAt:(new Date).toISOString()};return this.storage.registerBlob?await this.storage.registerBlob(n,e):(await this.storage.storeBytes(r,e),await this.storage.saveRecord(n)),this.cache.set(r,n),this.bus.emit({name:"blobs:changed",payload:{sha256:r,record:n}}),f(this.reference(n))}async retain(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s={...t,refCount:t.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(s),this.cache.set(e,s),f(void 0)}async release(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s=Math.max(0,t.refCount-1),r={...t,refCount:s,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(r),this.cache.set(e,r),f(void 0)}async purge(e){return await this.storage.deleteBytes(e),await this.storage.deleteRecord(e),this.cache.delete(e),this.bus.emit({name:"blobs:changed",payload:{sha256:e}}),f(void 0)}async recordRemoteId(e,t,s,r){const i=await this.getRecord(e);if(!i)return y({code:"NOT_FOUND",resource:"blob",id:e});const n={...i,remoteIds:{...i.remoteIds,[t]:{id:s,timestamp:r||(new Date).toISOString()}},lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(n),this.cache.set(e,n),this.bus.emit({name:"blobs:changed",payload:{sha256:e,record:n}}),f(void 0)}async getRecord(e){const t=this.cache.get(e);if(t)return t;const s=await this.storage.loadRecord(e);return s&&this.cache.set(e,s),s}async getAllRecords(){const e=await this.storage.listRecords(),t={};for(const s of e)t[s.sha256]=s,this.cache.set(s.sha256,s);return t}reference(e){return{sha256:e.sha256,mediaType:e.mediaType,sizeBytes:e.sizeBytes,filename:e.filename}}async resolve(e,t){const s=await this.getRecord(e.sha256);if(!s)return f(null);if(t){const e=s.remoteIds[t];if(e)return f({kind:"remote",sha256:s.sha256,mediaType:s.mediaType,fileId:e.id,providerId:t,timestamp:e.timestamp});const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}async resolveMany(e,t){const s=new Map;for(const r of e){const e=await this.resolve(r,t);if(!e.ok)return y(e.error);if(null===e.value)return y({code:"BLOB_ERROR",reason:`Unable to resolve blob ${r.sha256}${t?` with adapter ${t}`:""}`});s.set(r.sha256,e.value)}return f(s)}},C=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.key,e)}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}async update(e,t){const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"key",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getByTopics(e,t){const s=new Set;for(const r of t){const t=e.topics[r];t&&t.contextKeys.forEach((e=>s.add(e)))}if(0===s.size)return[];const r=[],i=[];for(const e of s){const t=this.cache.get(e);t?i.push(t):r.push(e)}if(r.length>0){const e=await this.collection.filter({operator:"or",conditions:r.map((e=>({field:"key",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.key,e),i.push(e)}}return i.sort(((e,t)=>new Date(t.timestamp).getTime()-new Date(e.timestamp).getTime()))}},B=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async load(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?s.push(e):t.push(r)}if(t.length>0){const e=await this.collection.filter({operator:"or",conditions:t.map((e=>({field:"id",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.id,e),s.push(e)}}return s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},M=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},$=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}},P=class{constructor(e,t){this.collection=e,this.cache=t}key({id:e,session:t,version:s}){return`${t}:${s}:${e}`}async find({id:e,session:t,version:s},r=!0){const i=this.key({id:e,session:t,version:s});this.cache.get(i)&&this.cache.get(i);const n=await this.collection.find({operator:"and",conditions:[{field:"id",operator:"eq",value:e},{field:"session",operator:"eq",value:t},{field:"version",operator:"eq",value:s}]});return n?(r&&this.cache.set(i,n),n):null}async get(e){return this.find(e)}async add(e){const t=await this.collection.create(e);this.cache.set(this.key(e),t)}async update(e,t){const s=await this.find(e);return s?(await s.update(t),s.state()):null}async listBySession(e){return(await this.collection.filter({field:"session",operator:"eq",value:e})).map((e=>e.state()))}async delete(e){const t=await this.find(e,!1);if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(this.key(e)),s}},j=class{cache;maxSize;constructor(e){this.cache=new Map,this.maxSize=e}get(e){const t=this.cache.get(e);return void 0!==t&&(this.cache.delete(e),this.cache.set(e,t)),t}set(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){const e=this.cache.keys().next().value;void 0!==e&&this.cache.delete(e)}this.cache.set(e,t)}has(e){return this.cache.has(e)}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}};exports.COLLECTIONS=l,exports.EMPTY_SYSTEM_ROLE=D,exports.LRUCache=j,exports.Session=F,exports.SessionManager=U,exports.TurnBuilder=I,exports.TurnTree=E,exports.WorkspaceManager=_,exports.bufferToBase64=function(e){if("undefined"!=typeof Buffer)return Buffer.from(e).toString("base64");const t=[];for(let s=0;s<e.length;s+=32768){const r=e.subarray(s,s+32768);t.push(String.fromCharCode.apply(null,Array.from(r)))}return btoa(t.join(""))},exports.computeSHA256=g,exports.createWorkspace=async function(e){const{blobStorage:t,eventBus:s=c(),getWorkspace:r,setWorkspace:i,processor:n,guard:o,toolRegistry:a,extensionReducers:d={},extensionMiddleware:h=[]}=e,p=u(e.db);await p.open(e.extensionSchemas);const f={role:await p.collection(l.ROLE),preference:await p.collection(l.PREFERENCE),context:await p.collection(l.CONTEXT),session:await p.collection(l.SESSION),topic:await p.collection(l.TOPIC),turn:await p.collection(l.TURN)},m=new A(t,new j(200),s),y={roles:new M(f.role,new j(100)),preferences:new B(f.preference,new j(500)),context:new C(f.context,new j(500)),topics:new b(f.topic,new j(100)),sessions:new $(f.session,new j(50)),turns:new P(f.turn,new j(50)),blobs:m,tools:a,db:p},w=new _({ctx:y,getWorkspace:r,updateWorkspace:i,guard:o,bus:s});Object.entries(S).forEach((([e,t])=>{w.register(e,t)})),Object.entries(d).forEach((([e,t])=>{w.register(e,t)})),w.use(N),h.forEach((e=>{w.use(e)}));const g=new U(w,n);return{manager:w,sessions:g,ctx:y}},exports.createWorkspaceDatabase=u,exports.del=function(){return h},exports.error=y,exports.merge=w,exports.ok=m,exports.omitNullUndefined=function(e){return Object.fromEntries(Object.entries(e).filter((([e,t])=>null!=t)))},exports.success=f;
1
+ "use strict";var e=require("uuid"),t=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let s;this._pendingFn=void 0;try{s={status:"ok",value:await e()}}catch(e){s={status:"error",error:e}}for(const e of t)e(s);return s}},s=class e extends Error{constructor(t,s){super(t,{cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},r=class extends s{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},i=class extends s{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},n=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,n)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(new r("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},o=class{mutex=new n({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,n)=>{i=setTimeout((()=>n(new r(s))),t)}))])}},a=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new n({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new i};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,r=null;try{if(this._done)throw new i;r=await e(),this._lastValue=r,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:r,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}};function c(e){const s={},r=s.errorHandler??(e=>console.error("EventBus Error:",e)),i=null!=s.batch?.size,n=s.batch?.size,o=s.batch?.delay??16;if(i&&(n<=0||!Number.isFinite(n)))throw new Error(`EventBus: batch.size must be a positive finite number, got ${n}.`);if(i&&(o<0||!Number.isFinite(o)))throw new Error(`EventBus: batch.delay must be a non-negative finite number, got ${o}.`);const a=s.broadcast?.channel,c=null!=a&&a.length>0,d=new Map;let u=[];const l=i?new t({delay:o}):null;let h=0,p=0;const f=new Map,m=()=>{if(!c)return null;if("undefined"==typeof BroadcastChannel)return console.warn("EventBus: BroadcastChannel is not supported in this environment. Cross-tab notifications are disabled."),null;const e=new BroadcastChannel(a);return e.onmessage=e=>{const{name:t,payload:s}=e.data;g(t,s)},e};let y=m();const w=(e,t)=>{h++,p+=t,f.set(e,(f.get(e)??0)+1)},g=(e,t)=>{const s=d.get(e);if(s&&0!==s.size)for(const i of Array.from(s))try{i(t)}catch(s){const i=s instanceof Error?s:Object.assign(new Error(String(s)),{cause:s}),n=Object.assign(i,{eventName:e,payload:t});r(n)}},_=(e,t)=>{d.has(e)||d.set(e,new Set);const s=d.get(e);return s.add(t),()=>{s.delete(t),0===s.size&&d.delete(e)}},b=()=>{const e=u;u=[];for(const{name:t,payload:s}of e){const e=performance.now();g(t,s),w(t,performance.now()-e)}};return{subscribe:(e,t)=>_(e,t),once:(e,t)=>{let s;return s=_(e,(e=>{s(),t(e)})),s},emit:({name:e,payload:t})=>{if(i)return u.push({name:e,payload:t}),u.length>=n?(l.cancel(),void b()):(l.fire((()=>b())),void y?.postMessage({name:e,payload:t}));const s=performance.now();g(e,t),w(e,performance.now()-s),y?.postMessage({name:e,payload:t})},metrics:()=>({totalEvents:h,activeSubscriptions:Array.from(d.values()).reduce(((e,t)=>e+t.size),0),eventCounts:new Map(f),averageEmitDuration:h>0?p/h:0}),clear:()=>{l?.cancel(),u=[],d.clear(),h=0,p=0,f.clear(),y?.close(),y=m()}}}var d=[{name:"role",version:"1.0.0",description:"AI persona with a system prompt and associated preference defaults.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!0},description:{name:"description",type:"string",required:!1},persona:{name:"persona",type:"string",required:!0},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},topics:{name:"topics",type:"array",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_name",fields:["name"],type:"unique"},{name:"by_label",fields:["label"],type:"normal"}],constraints:[],migrations:[]},{name:"preference",version:"1.0.0",description:"A user behavioural instruction, scoped to zero or more topics.",fields:{id:{name:"id",type:"string",required:!0},content:{name:"content",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},timestamp:{name:"timestamp",type:"string",required:!0}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"context",version:"1.0.0",description:"Injected background knowledge, scoped to topics. Content is a discriminated union.",fields:{key:{name:"key",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},content:{name:"content",type:"record",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},metadata:{name:"metadata",type:"record",required:!1}},indexes:[{name:"by_key",fields:["key"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"session",version:"1.0.0",description:"Session metadata. The head field tracks the current tip of the turn DAG.",fields:{id:{name:"id",type:"string",required:!0},label:{name:"label",type:"string",required:!0},role:{name:"role",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},metadata:{name:"metadata",type:"record",required:!1},head:{name:"head",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_role",fields:["role"],type:"normal"}],constraints:[],migrations:[]},{name:"turn",version:"1.0.0",description:["A single message in a session transcript, stored as a flat document.","The DAG is reconstructed in memory by TurnTree.buildNodeGraph() at session open time."].join(" "),fields:{id:{name:"id",type:"string",required:!0},session:{name:"session",type:"string",required:!0},version:{name:"version",type:"number",required:!0},actor:{name:"actor",type:"enum",required:!0,values:["user","assistant","tool"]},blocks:{name:"blocks",type:"array",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},role:{name:"role",type:"string",required:!1},parent:{name:"parent",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_session",fields:["session"],type:"normal"},{name:"by_session_parent",fields:["session","parent"],type:"composite"},{name:"by_session_id_ver",fields:["session","id","version"],type:"composite",unique:!0}],constraints:[],migrations:[]},{name:"topic",version:"1.0.0",description:"A categorization for context and preferences, used for retrieval.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!1},description:{name:"description",type:"string",required:!1},metadata:{name:"metadata",type:"record",required:!1},created:{name:"created",type:"string",required:!0},updated:{name:"updated",type:"string",required:!0}},indexes:[{name:"by_name",fields:["name"],type:"unique"}],constraints:[],migrations:[]}];function u(e){const t=new o({retry:!0,throws:!0}),s=new o({retry:!0,throws:!0});return{open:async(s=[])=>(await t.do((async()=>{const t=[...d,...s];await e.setupCollections(t)}))).value,collection:async t=>e.collection(t),close:async()=>(await s.do((()=>{e.close()}))).value,database:()=>e}}var l={ROLE:"role",PREFERENCE:"preference",CONTEXT:"context",SESSION:"session",TURN:"turn",BLOB:"blob",TOPIC:"topic"},h=Symbol.for("delete"),p=e=>Array.isArray(e)?[...e]:{...e};function f(e){return{ok:!0,value:e}}function m(e){return f(e)}function y(e){return{ok:!1,error:e}}var w=function(e){const t=e?.deleteMarker||h;function s(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==t)).map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e:s(e)));if("object"==typeof e){const r={};for(const[i,n]of Object.entries(e))if(n!==t)if("object"==typeof n&&null!==n){const e=s(n);void 0!==e&&(r[i]=e)}else r[i]=n;return r}return e===t?void 0:e}return function(e,r){if("object"!=typeof e||null===e)return"object"==typeof r&&null!==r?s(r):r===t?{}:r;if("object"!=typeof r||null===r)return e;const i=p(e),n=[{target:i,source:r}];for(;n.length>0;){const{target:e,source:s}=n.pop();for(const r of Object.keys(s)){const i=s[r];if(i!==t)if(Array.isArray(i))e[r]=i;else if("object"==typeof i&&null!==i){const t=r in e&&"object"==typeof e[r]&&null!==e[r]?e[r]:{};e[r]=p(t),n.push({target:e[r],source:i})}else e[r]=i;else delete e[r]}}return i}}({deleteMarker:h});async function g(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map((e=>e.toString(16).padStart(2,"0"))).join("")}var _=class{registry=new Map;middlewares=[];serializer=new a;bus;_getWorkspace;updateWorkspace;guard;_ctx;constructor(e){this._ctx=e.ctx,this._getWorkspace=e.getWorkspace,this.updateWorkspace=e.updateWorkspace,this.guard=e.guard,this.bus=e.bus}register(e,t){return this.registry.set(e,t),this}use(e){return this.middlewares.push(e),this}workspace(){return this._getWorkspace()}async dispatch(e){const t=await this.serializer.do((async()=>{if(this.guard){const t=await this.guard.authenticate({type:"command",payload:e});if(!t.ok)return y(t.error)}const t=this.registry.get(e.type);if(!t)return y({code:"INVALID_COMMAND",reason:`No reducer registered for command type: ${e.type}`});const s=this._getWorkspace(),r=await t({workspace:s,...this._ctx},e.payload);if(!r.ok)return r;let i=r.value;for(const t of this.middlewares){const r=await t({workspace:s,command:e,patch:i,...this._ctx});i=w(i,r)}return await this.updateWorkspace(i),this.bus.emit({name:"workspace:changed",payload:i}),m(i)}));if(t.error)throw t.error;return t.value}subscribe(e,t){return this.bus.subscribe(e,t)}ctx(){return{workspace:this._getWorkspace(),...this._ctx}}},b=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getMany(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?t.push(e):s.push(r)}if(s.length>0){const e=await this.collection.filter({operator:"or",conditions:s.map((e=>({field:"name",operator:"eq",value:e})))});for(const s of e){const e=s.state();this.cache.set(e.name,e),t.push(e)}}return t}referencedBy(e,t){for(const s in t.roles)if(t.roles[s].topics?.includes(e))return!0;for(const s in t.sessions)if(t.sessions[s].topics?.includes(e))return!0;for(const s in t.context)if(t.context[s].topics?.includes(e))return!0;for(const s in t.preferences)if(t.preferences[s].topics?.includes(e))return!0;return!1}};function x(e,t,s,r,i,n){const o={};for(const a of t){let t=e[a];if(!t){if("add"!==i||!n)continue;t={topic:a,contextKeys:[],preferences:[],metadata:{created:(new Date).toISOString(),updated:(new Date).toISOString(),entries:0}},n.add({name:a,created:t.metadata.created,updated:t.metadata.updated})}const c=t[r],d=c.includes(s);if("add"!==i||d){if("remove"===i&&d){const e=Math.max(0,(t.metadata.entries||0)-1);o[a]={...t,[r]:c.filter((e=>e!==s)),metadata:{...t.metadata,updated:(new Date).toISOString(),entries:e}}}}else o[a]={...t,[r]:[...c,s],metadata:{...t.metadata,updated:(new Date).toISOString(),entries:(t.metadata.entries||0)+1}}}return{index:{topics:o}}}function v(e,t,s,r){return x(e,t,s,"contextKeys","add",r)}function k(e,t,s){return x(e,t,s,"contextKeys","remove")}function O(e,t,s,r){return x(e,t,s,"preferences","add",r)}function T(e,t,s){return x(e,t,s,"preferences","remove")}var S=async e=>{if(!e.patch)return;const{workspace:t,patch:s}=e,r=t.index.topics;let i={};const n=e=>{const t=e?.index?.topics;t&&(i=w(i,t))};if(s.index?.context)for(const[i,o]of Object.entries(s.index.context)){const s=t.index.context[i];if(void 0===o&&s)n(k(r,s.topics,s.key));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(k(r,c,s.key)),a.length&&n(v(r,a,s.key,e.topics))}}else n(v(r,o.topics??[],o.key,e.topics))}if(s.index?.preferences)for(const[i,o]of Object.entries(s.index.preferences)){const s=t.index.preferences[i];if(void 0===o&&s)n(T(r,s.topics,s.id));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(T(r,c,s.id)),a.length&&n(O(r,a,s.id,e.topics))}}else n(O(r,o.topics??[],o.id,e.topics))}return Object.keys(i).length?{index:{topics:i}}:{}};var N={"role:add":async function(e,t){const{workspace:s,roles:r}=e,i=t;return s.index.roles[i.name]?y({code:"DUPLICATE_KEY",resource:"Role",key:i.name}):(await r.add(i),m({index:{roles:{[i.name]:{name:i.name,label:i.label,description:i.description,preferences:i.preferences.length}}}}))},"role:update":async function(e,t){const{workspace:s,roles:r}=e,{name:i,...n}=t;if(!s.index.roles[i])return y({code:"NOT_FOUND",resource:"Role",id:i});const o=await r.update(i,n);return o?m({index:{roles:{[i]:{name:o.name,label:o.label,description:o.description,preferences:o.preferences.length}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update role ${i} in store.`})},"role:delete":async function(e,t){const{workspace:s,roles:r}=e,{name:i}=t;return s.index.roles[i]?await r.delete(i)?m({index:{roles:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete role ${i} from store.`}):y({code:"NOT_FOUND",resource:"Role",id:i})},"preference:add":async function(e,t){const{workspace:s,preferences:r}=e,i=t;return s.index.preferences[i.id]?y({code:"DUPLICATE_KEY",resource:"Preference",key:i.id}):(await r.add(i),m({index:{preferences:{[i.id]:{id:i.id,topics:i.topics,timestamp:i.timestamp,snippet:i.content.substring(0,100)}}}}))},"preference:update":async function(e,t){const{workspace:s,preferences:r}=e,{id:i,...n}=t;if(!s.index.preferences[i])return y({code:"NOT_FOUND",resource:"Preference",id:i});const o=await r.update(i,n);return o?m({index:{preferences:{[i]:{id:o.id,topics:o.topics,timestamp:o.timestamp,snippet:o.content.substring(0,100)}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update preference ${i} in store.`})},"preference:delete":async function(e,t){const{workspace:s,preferences:r}=e,{id:i}=t;return s.index.preferences[i]?await r.delete(i)?m({index:{preferences:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete preference ${i} from store.`}):y({code:"NOT_FOUND",resource:"Preference",id:i})},"context:add":async function(e,t){const{workspace:s,context:r}=e,i=t;return s.index.context[i.key]?y({code:"DUPLICATE_KEY",resource:"Context",key:i.key}):(await r.add(i),m({index:{context:{[i.key]:{key:i.key,topics:i.topics,timestamp:i.timestamp,mime:"blob"===i.content.kind?i.content.mediaType:void 0,size:"blob"===i.content.kind?i.content.sizeBytes:void 0,metadata:i.metadata}}}}))},"context:update":async function(e,t){const{workspace:s,context:r}=e,{key:i,...n}=t;if(!s.index.context[i])return y({code:"NOT_FOUND",resource:"Context",id:i});const o=await r.update(i,n);return o?m({index:{context:{[i]:{key:o.key,topics:o.topics,timestamp:o.timestamp,mime:"blob"===o.content.kind?o.content.mediaType:void 0,size:"blob"===o.content.kind?o.content.sizeBytes:void 0,metadata:o.metadata}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update context ${i} in store.`})},"context:delete":async function(e,t){const{workspace:s,context:r}=e,{key:i}=t;return s.index.context[i]?await r.delete(i)?m({index:{context:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete context ${i} from store.`}):y({code:"NOT_FOUND",resource:"Context",id:i})},"topic:add":async function(e,t){const{workspace:s,topics:r}=e,i=t;return s.index.topics[i.name]?y({code:"DUPLICATE_KEY",resource:"Topic",key:i.name}):(await r.add(i),m({index:{topics:{[i.name]:{topic:i.name,contextKeys:[],preferences:[],metadata:{created:i.created,updated:i.updated,entries:0}}}}}))},"topic:update":async function(e,t){const{workspace:s,topics:r}=e,{name:i,...n}=t;if(!s.index.topics[i])return y({code:"NOT_FOUND",resource:"Topic",id:i});const o=await r.update(i,n);return o?m({index:{topics:{[i]:{metadata:{updated:o.updated}}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update topic ${i} in store.`})},"topic:delete":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{name:o,cascade:a}=t;if(!s.index.topics[o])return y({code:"NOT_FOUND",resource:"Topic",id:o});if(r.referencedBy(o,s.index)&&!a)return y({code:"INVALID_COMMAND",reason:`Topic '${o}' is referenced by other entities. Use 'cascade: true' to force deletion.`});if(a){for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);t&&await i.update(e,{topics:t.topics.filter((e=>e!==o))})}}for(const e in s.index.sessions){const t=s.index.sessions[e];t.topics?.includes(o)&&await n.update(e,{topics:t.topics.filter((e=>e!==o))})}}return await r.delete(o)?m({index:{topics:{[o]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete topic ${o} from store.`})},"topic:merge":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{source:o,target:a}=t;if(!s.index.topics[o]||!s.index.topics[a])return y({code:"NOT_FOUND",resource:"Topic",id:s.index.topics[o]?a:o});for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);if(t){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await i.update(e,{topics:s})}}}for(const e in s.index.sessions){const t=s.index.sessions[e];if(t.topics?.includes(o)){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await n.update(e,{topics:s})}}return await r.delete(o),m({index:{topics:{[o]:h}}})},"session:create":async function(e,t){const{workspace:s,sessions:r}=e,i=t;return s.index.sessions[i.id]?y({code:"DUPLICATE_KEY",resource:"Session",key:i.id}):(await r.add(i),m({index:{sessions:{[i.id]:{id:i.id,label:i.label,role:i.role,topics:i.topics,preferences:i.preferences,metadata:i.metadata}}}}))},"session:update":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,...n}=t;if(!s.index.sessions[i])return y({code:"NOT_FOUND",resource:"Session",id:i});const o=await r.update(i,n);return o?m({index:{sessions:{[i]:{label:o.label,role:o.role,topics:o.topics,preferences:o.preferences,metadata:o.metadata,head:o.head}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update session ${i} in store.`})},"session:fork":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,newSessionId:n,label:o}=t,a=s.index.sessions[i];if(!a)return y({code:"NOT_FOUND",resource:"Session",id:i});const c={...a,id:n,label:o||`Fork of ${a.label}`,role:t.role?t.role:a.role,topics:t.topics?t.topics:a.topics};return await r.add(c),m({index:{sessions:{[n]:{id:n,label:c.label,role:c.role,topics:c.topics,preferences:c.preferences,metadata:c.metadata,head:c.head}}}})},"session:delete":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i}=t;return s.index.sessions[i]?(await r.delete(i),m({index:{sessions:{[i]:h}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:role:switch":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,roleName:n}=t;return s.index.sessions[i]?(await r.update(i,{role:n}),m({index:{sessions:{[i]:{role:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:topics:add":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,topics:n}=t,o=s.index.sessions[i];if(!o)return y({code:"NOT_FOUND",resource:"Session",id:i});const a=Array.from(new Set([...o.topics,...n]));return await r.update(i,{topics:a}),m({index:{sessions:{[i]:{topics:a}}}})},"session:preferences:override":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,preferences:n}=t;return s.index.sessions[i]?(await r.update(i,{preferences:n}),m({index:{sessions:{[i]:{preferences:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"turn:add":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:update":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.update(o,o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:edit":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newBlocks:a,newVersion:c,roleSnapshot:d}=t,u=s.index.sessions[n];if(!u)return y({code:"NOT_FOUND",resource:"Session",id:n});const l=u.head;let h={};if(l&&l.id===o){const e=await i.get({id:l.id,version:l.version,session:n});e&&(h={...e})}const p={...h,id:o,version:c,blocks:a,role:d??h.role,timestamp:(new Date).toISOString(),parent:h.parent,actor:h.actor||"assistant",session:n};if(await i.add(p),u.head?.id===o){const e={id:o,version:c};return await r.update(n,{head:e}),m({index:{sessions:{[n]:{head:e}}}})}return m({})},"turn:branch":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:delete":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newHead:a}=t;return s.index.sessions[n]?(await i.delete({session:n,id:o,version:t.version}),a?(await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})):m({})):y({code:"NOT_FOUND",resource:"Session",id:n})},"blob:register":async function(e,t){const{blobs:s}=e,r=await s.register(t.data,t.mediaType,t.filename);if(!r.ok)return r;const i=await s.getRecord(r.value.sha256);return i?m({index:{blobs:{[i.sha256]:i}}}):y({code:"BACKEND_ERROR",reason:`Failed to retrieve registered blob record for ${r.value.sha256}`})},"blob:retain":async function(e,t){const{blobs:s}=e,r=await s.retain(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i}}})},"blob:release":async function(e,t){const{blobs:s}=e,r=await s.release(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i||h}}})},"blob:purge":async function(e,t){const{blobs:s}=e,r=await s.purge(t.sha256);return r.ok?m({index:{blobs:{[t.sha256]:h}}}):r},"blob:record_remote_id":async function(e,t){const{blobs:s}=e,{sha256:r,providerId:i,fileId:n,timestamp:o}=t,a=await s.recordRemoteId(r,i,n,o);if(!a.ok)return a;const c=await s.getRecord(r);return m({index:{blobs:{[r]:c}}})},"tool:call":async function(e,t){return m({})}},D="__system__",I=class{constructor(t,s,r){this._actor=t,this._turn=r?JSON.parse(JSON.stringify(r)):{id:e.v7(),session:s,version:0,actor:this._actor,blocks:[],timestamp:(new Date).toISOString(),role:void 0}}_turn;addText(t){const s={id:e.v7(),type:"text",text:t};return this._turn.blocks.push(s),this}addImage(t,s){const r={id:e.v7(),type:"image",ref:t,altText:s};return this._turn.blocks.push(r),this}addDocument(t,s){const r={id:e.v7(),type:"document",ref:t,title:s};return this._turn.blocks.push(r),this}addToolUse(t,s){const r={id:e.v7(),type:"tool:use",name:t,input:s};return this._turn.blocks.push(r),this}addToolResult(t,s,r){const i={id:e.v7(),type:"tool:result",useId:t,content:s,isError:r};return this._turn.blocks.push(i),this}addSummary(t){const s={id:e.v7(),type:"summary",text:t};return this._turn.blocks.push(s),this}addRoleTransition(t,s){const r={id:e.v7(),type:"role:transition",previousRole:t,newRole:s};return this._turn.blocks.push(r),this}addThinking(t){const s={id:e.v7(),type:"thinking",thinking:t};return this._turn.blocks.push(s),this}addBlock(e){return this._turn.blocks.push(e),this}deleteBlock(e){return this._turn.blocks=this._turn.blocks.filter((t=>t.id!==e)),this}editTextBlock(e,t){const s=this._turn.blocks.findIndex((t=>t.id===e));if(-1===s)throw new Error(`Block with ID ${e} not found.`);const r=this._turn.blocks[s];if("text"!==r.type)throw new Error(`Block with ID ${e} is not a TextBlock.`);return this._turn.blocks[s]={...r,text:t},this}withId(e){return this._turn.id=e,this}withVersion(e){return this._turn.version=e,this}withTimestamp(e){return this._turn.timestamp=e,this}withParent(e){return this._turn.parent=e,this}withRoleSnapshot(e){return this._turn.role=e,this}build(){return JSON.parse(JSON.stringify(this._turn))}},R=class{constructor(e,t){this.turnStore=e,this.sessionStore=t}async loadAllTurns(e){return this.turnStore.listBySession(e)}async loadHead(e){const t=await this.sessionStore.get(e);return t?.head??null}},E=class e{constructor(e,t){this.nodes=e,this._head=t}static async build(t,s){const[r,i]=await Promise.all([s.loadAllTurns(t),s.loadHead(t)]),n=function(e,t){const s=function(e,t){if(!t)return new Set;const s=new Map;for(const t of e)s.set(`${t.id}:${t.version}`,t);const r=new Set;let i=t;for(;i;){const e=`${i.id}:${i.version}`;if(r.has(e))break;r.add(e);const t=s.get(e);if(!t)break;i=t.parent}return r}(e,t),r={},i={};for(const t of e){r[t.id]||(r[t.id]={id:t.id,versions:{},activeVersion:t.version,actor:t.actor,blocks:t.blocks,timestamp:t.timestamp,roleSnapshot:t.role,parent:t.parent,children:{}},i[t.id]=new Set);const e=r[t.id];e.versions[t.version]=t;const n=s.has(`${t.id}:${t.version}`),o=s.has(`${t.id}:${e.activeVersion}`);if(n&&(!o||t.version>=e.activeVersion)&&(e.activeVersion=t.version,e.blocks=t.blocks,e.timestamp=t.timestamp,e.roleSnapshot=t.role,e.parent=t.parent),t.parent){const e=`${t.parent.id}:${t.parent.version}`;if(i[t.parent.id]||(i[t.parent.id]=new Set),!i[t.parent.id].has(e+":"+t.id)){i[t.parent.id].add(e+":"+t.id),r[t.parent.id]||(r[t.parent.id]={id:t.parent.id,versions:{},activeVersion:t.parent.version,actor:"user",blocks:[],timestamp:"",roleSnapshot:void 0,children:{}});const s=r[t.parent.id];s.children[t.parent.version]||(s.children[t.parent.version]=[]),s.children[t.parent.version].push(t.id)}}}return r}(r,i);return new e(n,i)}head(){return this._head}chain(){if(!this._head)return[];const e=[];let t=this._head.id;for(;t;){const s=this.nodes[t];if(!s)break;e.push(s),t=s.parent?.id??null}return e.reverse()}getTurnSiblings(e){const t=this.nodes[e];if(!t)return[];if(!t.parent)return Object.values(this.nodes).filter((e=>!e.parent));const s=this.nodes[t.parent.id];if(!s)return[t];const r=s.children[t.parent.version];return r?r.map((e=>this.nodes[e])).filter((e=>!!e)):[t]}branchInfo(e){const t=this.nodes[e];if(!t)return{versions:[],currentIndex:-1,total:0,hasPrev:!1,hasNext:!1};const s=Object.keys(t.versions).map(Number).sort(((e,t)=>e-t)),r=s.indexOf(t.activeVersion);return{versions:s,currentIndex:r,total:s.length,hasPrev:r>0,hasNext:r<s.length-1}}graph(){return{...this.nodes}}};var q=class{constructor(e){this.manager=e}get workspace(){return this.manager.workspace()}roles(){return this.manager.ctx().roles.list()}role(e){return this.manager.ctx().roles.get(e)}async createRole(e,t,s,r,i=[]){if(this.workspace.index.roles[e])return y({code:"DUPLICATE_KEY",resource:"role",key:e});const n={name:e,label:t,description:r,persona:s,preferences:i,topics:[]};return this.manager.dispatch({type:"role:add",payload:n,timestamp:(new Date).toISOString()})}async updateRole(e,t){return this.workspace.index.roles[e]?this.manager.dispatch({type:"role:update",payload:{name:e,...t},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"role",id:e})}async deleteRole(e){const t=this.workspace;if(!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});return Object.values(t.index.sessions).some((t=>t.role===e))?y({code:"INVALID_COMMAND",reason:`Cannot delete role "${e}" — it is still referenced by one or more sessions`}):this.manager.dispatch({type:"role:delete",payload:{name:e},timestamp:(new Date).toISOString()})}async addPreference(e,t){const s={id:crypto.randomUUID(),content:e,topics:t,timestamp:(new Date).toISOString()};return this.manager.dispatch({type:"preference:add",payload:s,timestamp:s.timestamp})}preferences(){return this.manager.ctx().preferences.list()}async addContext(e,t,s,r){const i={key:e,topics:s,content:t,timestamp:(new Date).toISOString(),metadata:r};return this.manager.dispatch({type:"context:add",payload:i,timestamp:i.timestamp})}context(){return this.manager.ctx().context.list()}async registerBlob(e,t,s){const r=await this.manager.dispatch({type:"blob:register",payload:{data:e,mediaType:t,filename:s},timestamp:(new Date).toISOString()});if(!r.ok)return y(r.error);const i=r.value,n=i?.index?.blobs;if(!n)return y({code:"BACKEND_ERROR",reason:"Blob registration succeeded but no blobs patch returned"});const o=Object.keys(n)[0];if(!o)return y({code:"BACKEND_ERROR",reason:"No SHA256 in patch"});const a=n[o];if(!a)return y({code:"BACKEND_ERROR",reason:"Blob record missing"});return f({sha256:o,ref:{sha256:o,mediaType:a.mediaType,sizeBytes:a.sizeBytes,filename:a.filename,previewUrl:a.previewUrl}})}},F=class e{constructor(e,t,s,r){this._id=e,this.manager=t,this.processor=s,this.turnRepository=r,this.workspace=new q(t)}workspace;_role=void 0;_preferences=[];tree;static async create(t,s,r){s.ctx().workspace;const i=new R(s.ctx().turns,s.ctx().sessions),n=new e(t,s,r,i);return await n._setRole(),await n._setPreference(),await n.refreshTurnTree(),n}async _setRole(){const e=this.meta(),t=await this.manager.ctx().roles.get(e.role);t&&(this._role=t)}async _setPreference(){const e=this.meta();this._preferences=await this.manager.ctx().preferences.load(e.preferences)}id(){return this._id}ws(){return this.manager.workspace()}meta(){return this.ws().index.sessions[this._id]}label(){return this.meta()?.label}role(){return this._role}topics(){return this.meta()?.topics??[]}preferences(){return this._preferences}head(){return this.meta()?.head??null}turns(){return this.tree.chain()}async siblings(e){return this.tree.getTurnSiblings(e)}async branchInfo(e){return this.tree.branchInfo(e)}async getTurn(e){return this.tree.graph()[e]}async rename(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,label:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setTopics(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async addTopics(e){return this.meta()?this.dispatch({type:"session:topics:add",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setPreferences(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t=await this.dispatch({type:"session:preferences:override",payload:{sessionId:this._id,preferences:e},timestamp:(new Date).toISOString()});return t.ok&&await this._setPreference(),t}async fork(e,t,s,r){return this.meta()?this.dispatch({type:"session:fork",payload:{sessionId:this._id,newSessionId:e,label:t,role:s,topics:r},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async dispatch(e){return this.manager.dispatch(e)}async switchRole(e){const t=this.ws();if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(e!==D&&!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});const s=await this.dispatch({type:"session:update",payload:{sessionId:this._id,role:e},timestamp:(new Date).toISOString()});return s.ok&&await this._setRole(),s}async addTurn(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t={...e,session:this._id,version:e.version??0,parent:!e.parent&&this.head()?this.head():void 0},s=await this.dispatch({type:"turn:add",payload:{sessionId:this._id,turn:t},timestamp:t.timestamp});return s.ok&&await this.refreshTurnTree(),s}async recordUserTurn(e){return this.meta()?this.addTurn(e):y({code:"NOT_FOUND",resource:"session",id:this._id})}async recordAssistantTurn(e,t){const s=this.ws();if(!s)return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!s.index.sessions[this._id])return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.processor.process(e,this._id);let i={};const n=[];for(const e of r){const t=await this.manager.dispatch(e);if(t.ok)i=w(i,t.value);else{if("PERMISSION_DENIED"!==t.error.code||e.synthetic)return t;{const t=this.describeCommand(e);n.push({cmd:e,description:t})}}}const o=await this.addTurn(e);if(!o.ok)return o;if(i=w(i,o.value),t&&n.length>0){const e=this.buildDenialTurn(n),t=await this.addTurn(e);t.ok&&(i=w(i,t.value))}return f(i)}buildDenialTurn(e){const t=new I("user",this._id);for(const s of e)t.addText(`[System] User denied: ${s.description}.`);return t.build()}describeCommand(e){return"tool:call"===e.type?`tool execution: ${e.payload.tool}`:`command: ${e.type}`}async editTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph()[e];if(!r)return y({code:"NOT_FOUND",resource:"turn",id:e});const i=r.versions[r.activeVersion],n=r.activeVersion+1,o=await this.dispatch({type:"turn:edit",payload:{sessionId:this._id,turnId:e,newBlocks:t,roleSnapshot:s??i.role,newVersion:n},timestamp:(new Date).toISOString()});return o.ok&&(await this.dispatch({type:"session:update",payload:{sessionId:this._id,head:{id:e,version:n}},timestamp:(new Date).toISOString()}),await this.refreshTurnTree()),o}async branch(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(!e.parent)return y({code:"INVALID_COMMAND",reason:"branch requires turn.parent to be set"});const t=await this.dispatch({type:"turn:branch",payload:{sessionId:this._id,turn:{...e,session:this._id}},timestamp:e.timestamp});return t.ok&&await this.refreshTurnTree(),t}async deleteTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph();if(!r[e]?.versions[t])return y({code:"NOT_FOUND",resource:"turn version",id:`${e}:${t}`});const i=await this.dispatch({type:"turn:delete",payload:{sessionId:this._id,turnId:e,version:t,newHead:s},timestamp:(new Date).toISOString()});return i.ok&&await this.refreshTurnTree(),i}async switchVersionLeft(e){return this.switchVersion(e,-1)}async switchVersionRight(e){return this.switchVersion(e,1)}async switchVersion(e,t){if(!this.ws())return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const s=this.tree.graph()[e];if(!s)return y({code:"NOT_FOUND",resource:"turn",id:e});const r=Object.keys(s.versions).map(Number).sort(((e,t)=>e-t)),i=r.indexOf(s.activeVersion);if(-1===i)return y({code:"INVALID_COMMAND",reason:"Active version not found"});const n=i+t;if(n<0||n>=r.length)return y({code:"INVALID_COMMAND",reason:`No ${t<0?"previous":"next"} version available for turn ${e}`});const o=r[n],a=this.findSubtreeTip(this.tree.graph(),e,o),c=await this.dispatch({type:"session:update",payload:{sessionId:this._id,head:a},timestamp:(new Date).toISOString()});return c.ok&&await this.refreshTurnTree(),c}async snapshot(){const e=this,t=e.meta();if(!t)return;const s=e.ws(),r=e._role;if(!r)return;const i=await e.manager.ctx().context.getByTopics(s.index,t.topics),n=Array.from(new Set([...r.preferences,...t.preferences])),o=n.length>0?await e.manager.ctx().preferences.load(n):e._preferences,a=e.tree.chain().map((e=>e.versions[e.activeVersion])).filter((e=>!!e)),c=[...a].reverse().find((e=>"user"===e.actor));return{id:e._id,meta:t,role:r,preferences:o,context:i,model:t.metadata?.model,transcript:a,topics:t.topics,instructions:s.settings?.prompt,constraints:{role:r.constraints,session:t.constraints,turn:c?.constraints}}}async refreshTurnTree(){this.tree=await E.build(this._id,this.turnRepository)}findSubtreeTip(e,t,s){let r=t,i=s;for(;;){const t=e[r];if(!t)break;const s=t.children[i];if(!s||0===s.length)break;const n=s[0],o=e[n];if(!o)break;r=n,i=o.activeVersion}return{id:r,version:i}}},U=class{constructor(e,t){this.manager=e,this.processor=t}openOnce=new Map;async open(e){let t=this.openOnce.get(e);t||(t=new o,this.openOnce.set(e,t));const s=await t.do((async()=>{if(!this.manager.workspace().index.sessions[e])throw new Error(`Session ${e} not found in workspace index`);return F.create(e,this.manager,this.processor)}));if(s.error)throw s.error;return s.value}close(e){this.openOnce.delete(e)}async delete(e){const t=await this.manager.dispatch({type:"session:delete",payload:{sessionId:e},timestamp:(new Date).toISOString()});if(t.ok)return this.close(e),t.value=void 0,t;throw t.error}async create(t){const s=e.v7(),r=await this.manager.dispatch({type:"session:create",payload:{...t,id:s},timestamp:(new Date).toISOString()});if(r.ok)return this.open(s);throw r.error}list(){return Object.values(this.manager.workspace().index.sessions)}metadata(e){return this.manager.workspace().index.sessions[e]}},A=class{constructor(e,t,s){this.storage=e,this.cache=t,this.bus=s}async register(e,t,s){const r=await g(e),i=await this.getRecord(r);if(i){const e={...i,refCount:i.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(e),this.cache.set(r,e),f(this.reference(e))}const n={sha256:r,mediaType:t,sizeBytes:e.byteLength,filename:s,refCount:1,remoteIds:{},createdAt:(new Date).toISOString(),lastUsedAt:(new Date).toISOString()};return this.storage.registerBlob?await this.storage.registerBlob(n,e):(await this.storage.storeBytes(r,e),await this.storage.saveRecord(n)),this.cache.set(r,n),this.bus.emit({name:"blobs:changed",payload:{sha256:r,record:n}}),f(this.reference(n))}async retain(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s={...t,refCount:t.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(s),this.cache.set(e,s),f(void 0)}async release(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s=Math.max(0,t.refCount-1),r={...t,refCount:s,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(r),this.cache.set(e,r),f(void 0)}async purge(e){return await this.storage.deleteBytes(e),await this.storage.deleteRecord(e),this.cache.delete(e),this.bus.emit({name:"blobs:changed",payload:{sha256:e}}),f(void 0)}async recordRemoteId(e,t,s,r){const i=await this.getRecord(e);if(!i)return y({code:"NOT_FOUND",resource:"blob",id:e});const n={...i,remoteIds:{...i.remoteIds,[t]:{id:s,timestamp:r||(new Date).toISOString()}},lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(n),this.cache.set(e,n),this.bus.emit({name:"blobs:changed",payload:{sha256:e,record:n}}),f(void 0)}async getRecord(e){const t=this.cache.get(e);if(t)return t;const s=await this.storage.loadRecord(e);return s&&this.cache.set(e,s),s}async getAllRecords(){const e=await this.storage.listRecords(),t={};for(const s of e)t[s.sha256]=s,this.cache.set(s.sha256,s);return t}reference(e){return{sha256:e.sha256,mediaType:e.mediaType,sizeBytes:e.sizeBytes,filename:e.filename}}async resolve(e,t){const s=await this.getRecord(e.sha256);if(!s)return f(null);if(t){const e=s.remoteIds[t];if(e)return f({kind:"remote",sha256:s.sha256,mediaType:s.mediaType,fileId:e.id,providerId:t,timestamp:e.timestamp});const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}async resolveMany(e,t){const s=new Map;for(const r of e){const e=await this.resolve(r,t);if(!e.ok)return y(e.error);if(null===e.value)return y({code:"BLOB_ERROR",reason:`Unable to resolve blob ${r.sha256}${t?` with adapter ${t}`:""}`});s.set(r.sha256,e.value)}return f(s)}},C=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.key,e)}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}async update(e,t){const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"key",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getByTopics(e,t){const s=new Set;for(const r of t){const t=e.topics[r];t&&t.contextKeys.forEach((e=>s.add(e)))}if(0===s.size)return[];const r=[],i=[];for(const e of s){const t=this.cache.get(e);t?i.push(t):r.push(e)}if(r.length>0){const e=await this.collection.filter({operator:"or",conditions:r.map((e=>({field:"key",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.key,e),i.push(e)}}return i.sort(((e,t)=>new Date(t.timestamp).getTime()-new Date(e.timestamp).getTime()))}},B=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async load(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?s.push(e):t.push(r)}if(t.length>0){const e=await this.collection.filter({operator:"or",conditions:t.map((e=>({field:"id",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.id,e),s.push(e)}}return s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},M=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},$=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}},j=class{constructor(e,t){this.collection=e,this.cache=t}key({id:e,session:t,version:s}){return`${t}:${s}:${e}`}async find({id:e,session:t,version:s},r=!0){const i=this.key({id:e,session:t,version:s});this.cache.get(i)&&this.cache.get(i);const n=await this.collection.find({operator:"and",conditions:[{field:"id",operator:"eq",value:e},{field:"session",operator:"eq",value:t},{field:"version",operator:"eq",value:s}]});return n?(r&&this.cache.set(i,n),n):null}async get(e){return this.find(e)}async add(e){const t=await this.collection.create(e);this.cache.set(this.key(e),t)}async update(e,t){const s=await this.find(e);return s?(await s.update(t),s.state()):null}async listBySession(e){return(await this.collection.filter({field:"session",operator:"eq",value:e})).map((e=>e.state()))}async delete(e){const t=await this.find(e,!1);if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(this.key(e)),s}},P=class{cache;maxSize;constructor(e){this.cache=new Map,this.maxSize=e}get(e){const t=this.cache.get(e);return void 0!==t&&(this.cache.delete(e),this.cache.set(e,t)),t}set(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){const e=this.cache.keys().next().value;void 0!==e&&this.cache.delete(e)}this.cache.set(e,t)}has(e){return this.cache.has(e)}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}};exports.COLLECTIONS=l,exports.EMPTY_SYSTEM_ROLE=D,exports.LRUCache=P,exports.Session=F,exports.SessionManager=U,exports.TurnBuilder=I,exports.TurnTree=E,exports.WorkspaceManager=_,exports.bufferToBase64=function(e){if("undefined"!=typeof Buffer)return Buffer.from(e).toString("base64");const t=[];for(let s=0;s<e.length;s+=32768){const r=e.subarray(s,s+32768);t.push(String.fromCharCode.apply(null,Array.from(r)))}return btoa(t.join(""))},exports.computeSHA256=g,exports.createWorkspace=async function(e){const{blobStorage:t,eventBus:s=c(),getWorkspace:r,setWorkspace:i,processor:n,guard:o,toolRegistry:a,extensionReducers:d={},extensionMiddleware:h=[],extensionStores:p}=e,f=u(e.db);await f.open(e.extensionSchemas);const m={role:await f.collection(l.ROLE),preference:await f.collection(l.PREFERENCE),context:await f.collection(l.CONTEXT),session:await f.collection(l.SESSION),topic:await f.collection(l.TOPIC),turn:await f.collection(l.TURN)},y=new A(t,new P(200),s),w={roles:new M(m.role,new P(100)),preferences:new B(m.preference,new P(500)),context:new C(m.context,new P(500)),topics:new b(m.topic,new P(100)),sessions:new $(m.session,new P(50)),turns:new j(m.turn,new P(50)),blobs:y,tools:a,db:f};if(p){const e=p(w);Object.assign(w,e)}const g=new _({ctx:w,getWorkspace:r,updateWorkspace:i,guard:o,bus:s});Object.entries(N).forEach((([e,t])=>{g.register(e,t)})),Object.entries(d).forEach((([e,t])=>{g.register(e,t)})),g.use(S),h.forEach((e=>{g.use(e)}));const x=new U(g,n);return{manager:g,sessions:x,ctx:w}},exports.createWorkspaceDatabase=u,exports.del=function(){return h},exports.error=y,exports.getExtension=function(e,t){return e.extensions[t]},exports.merge=w,exports.ok=m,exports.omitNullUndefined=function(e){return Object.fromEntries(Object.entries(e).filter((([e,t])=>null!=t)))},exports.shortHash=function(e,t=4){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return Math.abs(s).toString(36).padEnd(t,"0").slice(0,t)},exports.success=f;
package/index.mjs CHANGED
@@ -1 +1 @@
1
- import{v7 as e}from"uuid";var t=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let s;this._pendingFn=void 0;try{s={status:"ok",value:await e()}}catch(e){s={status:"error",error:e}}for(const e of t)e(s);return s}},s=class e extends Error{constructor(t,s){super(t,{cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},r=class extends s{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},i=class extends s{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},n=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,n)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(new r("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},o=class{mutex=new n({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,n)=>{i=setTimeout((()=>n(new r(s))),t)}))])}},a=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new n({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new i};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,r=null;try{if(this._done)throw new i;r=await e(),this._lastValue=r,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:r,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}};function c(e){const s={},r=s.errorHandler??(e=>console.error("EventBus Error:",e)),i=null!=s.batch?.size,n=s.batch?.size,o=s.batch?.delay??16;if(i&&(n<=0||!Number.isFinite(n)))throw new Error(`EventBus: batch.size must be a positive finite number, got ${n}.`);if(i&&(o<0||!Number.isFinite(o)))throw new Error(`EventBus: batch.delay must be a non-negative finite number, got ${o}.`);const a=s.broadcast?.channel,c=null!=a&&a.length>0,d=new Map;let u=[];const l=i?new t({delay:o}):null;let h=0,p=0;const f=new Map,m=()=>{if(!c)return null;if("undefined"==typeof BroadcastChannel)return console.warn("EventBus: BroadcastChannel is not supported in this environment. Cross-tab notifications are disabled."),null;const e=new BroadcastChannel(a);return e.onmessage=e=>{const{name:t,payload:s}=e.data;g(t,s)},e};let y=m();const w=(e,t)=>{h++,p+=t,f.set(e,(f.get(e)??0)+1)},g=(e,t)=>{const s=d.get(e);if(s&&0!==s.size)for(const i of Array.from(s))try{i(t)}catch(s){const i=s instanceof Error?s:Object.assign(new Error(String(s)),{cause:s}),n=Object.assign(i,{eventName:e,payload:t});r(n)}},_=(e,t)=>{d.has(e)||d.set(e,new Set);const s=d.get(e);return s.add(t),()=>{s.delete(t),0===s.size&&d.delete(e)}},b=()=>{const e=u;u=[];for(const{name:t,payload:s}of e){const e=performance.now();g(t,s),w(t,performance.now()-e)}};return{subscribe:(e,t)=>_(e,t),once:(e,t)=>{let s;return s=_(e,(e=>{s(),t(e)})),s},emit:({name:e,payload:t})=>{if(i)return u.push({name:e,payload:t}),u.length>=n?(l.cancel(),void b()):(l.fire((()=>b())),void y?.postMessage({name:e,payload:t}));const s=performance.now();g(e,t),w(e,performance.now()-s),y?.postMessage({name:e,payload:t})},metrics:()=>({totalEvents:h,activeSubscriptions:Array.from(d.values()).reduce(((e,t)=>e+t.size),0),eventCounts:new Map(f),averageEmitDuration:h>0?p/h:0}),clear:()=>{l?.cancel(),u=[],d.clear(),h=0,p=0,f.clear(),y?.close(),y=m()}}}var d=[{name:"role",version:"1.0.0",description:"AI persona with a system prompt and associated preference defaults.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!0},description:{name:"description",type:"string",required:!1},persona:{name:"persona",type:"string",required:!0},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},topics:{name:"topics",type:"array",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_name",fields:["name"],type:"unique"},{name:"by_label",fields:["label"],type:"normal"}],constraints:[],migrations:[]},{name:"preference",version:"1.0.0",description:"A user behavioural instruction, scoped to zero or more topics.",fields:{id:{name:"id",type:"string",required:!0},content:{name:"content",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},timestamp:{name:"timestamp",type:"string",required:!0}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"context",version:"1.0.0",description:"Injected background knowledge, scoped to topics. Content is a discriminated union.",fields:{key:{name:"key",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},content:{name:"content",type:"record",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},metadata:{name:"metadata",type:"record",required:!1}},indexes:[{name:"by_key",fields:["key"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"session",version:"1.0.0",description:"Session metadata. The head field tracks the current tip of the turn DAG.",fields:{id:{name:"id",type:"string",required:!0},label:{name:"label",type:"string",required:!0},role:{name:"role",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},metadata:{name:"metadata",type:"record",required:!1},head:{name:"head",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_role",fields:["role"],type:"normal"}],constraints:[],migrations:[]},{name:"turn",version:"1.0.0",description:["A single message in a session transcript, stored as a flat document.","The DAG is reconstructed in memory by TurnTree.buildNodeGraph() at session open time."].join(" "),fields:{id:{name:"id",type:"string",required:!0},session:{name:"session",type:"string",required:!0},version:{name:"version",type:"number",required:!0},actor:{name:"actor",type:"enum",required:!0,values:["user","assistant","tool"]},blocks:{name:"blocks",type:"array",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},role:{name:"role",type:"string",required:!1},parent:{name:"parent",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_session",fields:["session"],type:"normal"},{name:"by_session_parent",fields:["session","parent"],type:"composite"},{name:"by_session_id_ver",fields:["session","id","version"],type:"composite",unique:!0}],constraints:[],migrations:[]},{name:"topic",version:"1.0.0",description:"A categorization for context and preferences, used for retrieval.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!1},description:{name:"description",type:"string",required:!1},metadata:{name:"metadata",type:"record",required:!1},created:{name:"created",type:"string",required:!0},updated:{name:"updated",type:"string",required:!0}},indexes:[{name:"by_name",fields:["name"],type:"unique"}],constraints:[],migrations:[]}];function u(e){const t=new o({retry:!0,throws:!0}),s=new o({retry:!0,throws:!0});return{open:async(s=[])=>(await t.do((async()=>{const t=[...d,...s];await e.setupCollections(t)}))).value,collection:async t=>e.collection(t),close:async()=>(await s.do((()=>{e.close()}))).value,database:()=>e}}var l={ROLE:"role",PREFERENCE:"preference",CONTEXT:"context",SESSION:"session",TURN:"turn",BLOB:"blob",TOPIC:"topic"},h=Symbol.for("delete"),p=e=>Array.isArray(e)?[...e]:{...e};function f(e){return{ok:!0,value:e}}function m(e){return f(e)}function y(e){return{ok:!1,error:e}}function w(e){return Object.fromEntries(Object.entries(e).filter((([e,t])=>null!=t)))}function g(){return h}var _=function(e){const t=e?.deleteMarker||h;function s(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==t)).map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e:s(e)));if("object"==typeof e){const r={};for(const[i,n]of Object.entries(e))if(n!==t)if("object"==typeof n&&null!==n){const e=s(n);void 0!==e&&(r[i]=e)}else r[i]=n;return r}return e===t?void 0:e}return function(e,r){if("object"!=typeof e||null===e)return"object"==typeof r&&null!==r?s(r):r===t?{}:r;if("object"!=typeof r||null===r)return e;const i=p(e),n=[{target:i,source:r}];for(;n.length>0;){const{target:e,source:s}=n.pop();for(const r of Object.keys(s)){const i=s[r];if(i!==t)if(Array.isArray(i))e[r]=i;else if("object"==typeof i&&null!==i){const t=r in e&&"object"==typeof e[r]&&null!==e[r]?e[r]:{};e[r]=p(t),n.push({target:e[r],source:i})}else e[r]=i;else delete e[r]}}return i}}({deleteMarker:h});async function b(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map((e=>e.toString(16).padStart(2,"0"))).join("")}function v(e){if("undefined"!=typeof Buffer)return Buffer.from(e).toString("base64");const t=[];for(let s=0;s<e.length;s+=32768){const r=e.subarray(s,s+32768);t.push(String.fromCharCode.apply(null,Array.from(r)))}return btoa(t.join(""))}var k=class{registry=new Map;middlewares=[];serializer=new a;bus;_getWorkspace;updateWorkspace;guard;_ctx;constructor(e){this._ctx=e.ctx,this._getWorkspace=e.getWorkspace,this.updateWorkspace=e.updateWorkspace,this.guard=e.guard,this.bus=e.bus}register(e,t){return this.registry.set(e,t),this}use(e){return this.middlewares.push(e),this}workspace(){return this._getWorkspace()}async dispatch(e){const t=await this.serializer.do((async()=>{if(this.guard){const t=await this.guard.authenticate({type:"command",payload:e});if(!t.ok)return y(t.error)}const t=this.registry.get(e.type);if(!t)return y({code:"INVALID_COMMAND",reason:`No reducer registered for command type: ${e.type}`});const s=this._getWorkspace(),r=await t({workspace:s,...this._ctx},e.payload);if(!r.ok)return r;let i=r.value;for(const t of this.middlewares){const r=await t({workspace:s,command:e,patch:i,...this._ctx});i=_(i,r)}return await this.updateWorkspace(i),this.bus.emit({name:"workspace:changed",payload:i}),m(i)}));if(t.error)throw t.error;return t.value}subscribe(e,t){return this.bus.subscribe(e,t)}ctx(){return{workspace:this._getWorkspace(),...this._ctx}}},x=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getMany(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?t.push(e):s.push(r)}if(s.length>0){const e=await this.collection.filter({operator:"or",conditions:s.map((e=>({field:"name",operator:"eq",value:e})))});for(const s of e){const e=s.state();this.cache.set(e.name,e),t.push(e)}}return t}referencedBy(e,t){for(const s in t.roles)if(t.roles[s].topics?.includes(e))return!0;for(const s in t.sessions)if(t.sessions[s].topics?.includes(e))return!0;for(const s in t.context)if(t.context[s].topics?.includes(e))return!0;for(const s in t.preferences)if(t.preferences[s].topics?.includes(e))return!0;return!1}};function O(e,t,s,r,i,n){const o={};for(const a of t){let t=e[a];if(!t){if("add"!==i||!n)continue;t={topic:a,contextKeys:[],preferences:[],metadata:{created:(new Date).toISOString(),updated:(new Date).toISOString(),entries:0}},n.add({name:a,created:t.metadata.created,updated:t.metadata.updated})}const c=t[r],d=c.includes(s);if("add"!==i||d){if("remove"===i&&d){const e=Math.max(0,(t.metadata.entries||0)-1);o[a]={...t,[r]:c.filter((e=>e!==s)),metadata:{...t.metadata,updated:(new Date).toISOString(),entries:e}}}}else o[a]={...t,[r]:[...c,s],metadata:{...t.metadata,updated:(new Date).toISOString(),entries:(t.metadata.entries||0)+1}}}return{index:{topics:o}}}function T(e,t,s,r){return O(e,t,s,"contextKeys","add",r)}function N(e,t,s){return O(e,t,s,"contextKeys","remove")}function S(e,t,s,r){return O(e,t,s,"preferences","add",r)}function D(e,t,s){return O(e,t,s,"preferences","remove")}var I=async e=>{if(!e.patch)return;const{workspace:t,patch:s}=e,r=t.index.topics;let i={};const n=e=>{const t=e?.index?.topics;t&&(i=_(i,t))};if(s.index?.context)for(const[i,o]of Object.entries(s.index.context)){const s=t.index.context[i];if(void 0===o&&s)n(N(r,s.topics,s.key));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(N(r,c,s.key)),a.length&&n(T(r,a,s.key,e.topics))}}else n(T(r,o.topics??[],o.key,e.topics))}if(s.index?.preferences)for(const[i,o]of Object.entries(s.index.preferences)){const s=t.index.preferences[i];if(void 0===o&&s)n(D(r,s.topics,s.id));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(D(r,c,s.id)),a.length&&n(S(r,a,s.id,e.topics))}}else n(S(r,o.topics??[],o.id,e.topics))}return Object.keys(i).length?{index:{topics:i}}:{}};var R={"role:add":async function(e,t){const{workspace:s,roles:r}=e,i=t;return s.index.roles[i.name]?y({code:"DUPLICATE_KEY",resource:"Role",key:i.name}):(await r.add(i),m({index:{roles:{[i.name]:{name:i.name,label:i.label,description:i.description,preferences:i.preferences.length}}}}))},"role:update":async function(e,t){const{workspace:s,roles:r}=e,{name:i,...n}=t;if(!s.index.roles[i])return y({code:"NOT_FOUND",resource:"Role",id:i});const o=await r.update(i,n);return o?m({index:{roles:{[i]:{name:o.name,label:o.label,description:o.description,preferences:o.preferences.length}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update role ${i} in store.`})},"role:delete":async function(e,t){const{workspace:s,roles:r}=e,{name:i}=t;return s.index.roles[i]?await r.delete(i)?m({index:{roles:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete role ${i} from store.`}):y({code:"NOT_FOUND",resource:"Role",id:i})},"preference:add":async function(e,t){const{workspace:s,preferences:r}=e,i=t;return s.index.preferences[i.id]?y({code:"DUPLICATE_KEY",resource:"Preference",key:i.id}):(await r.add(i),m({index:{preferences:{[i.id]:{id:i.id,topics:i.topics,timestamp:i.timestamp,snippet:i.content.substring(0,100)}}}}))},"preference:update":async function(e,t){const{workspace:s,preferences:r}=e,{id:i,...n}=t;if(!s.index.preferences[i])return y({code:"NOT_FOUND",resource:"Preference",id:i});const o=await r.update(i,n);return o?m({index:{preferences:{[i]:{id:o.id,topics:o.topics,timestamp:o.timestamp,snippet:o.content.substring(0,100)}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update preference ${i} in store.`})},"preference:delete":async function(e,t){const{workspace:s,preferences:r}=e,{id:i}=t;return s.index.preferences[i]?await r.delete(i)?m({index:{preferences:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete preference ${i} from store.`}):y({code:"NOT_FOUND",resource:"Preference",id:i})},"context:add":async function(e,t){const{workspace:s,context:r}=e,i=t;return s.index.context[i.key]?y({code:"DUPLICATE_KEY",resource:"Context",key:i.key}):(await r.add(i),m({index:{context:{[i.key]:{key:i.key,topics:i.topics,timestamp:i.timestamp,mime:"blob"===i.content.kind?i.content.mediaType:void 0,size:"blob"===i.content.kind?i.content.sizeBytes:void 0,metadata:i.metadata}}}}))},"context:update":async function(e,t){const{workspace:s,context:r}=e,{key:i,...n}=t;if(!s.index.context[i])return y({code:"NOT_FOUND",resource:"Context",id:i});const o=await r.update(i,n);return o?m({index:{context:{[i]:{key:o.key,topics:o.topics,timestamp:o.timestamp,mime:"blob"===o.content.kind?o.content.mediaType:void 0,size:"blob"===o.content.kind?o.content.sizeBytes:void 0,metadata:o.metadata}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update context ${i} in store.`})},"context:delete":async function(e,t){const{workspace:s,context:r}=e,{key:i}=t;return s.index.context[i]?await r.delete(i)?m({index:{context:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete context ${i} from store.`}):y({code:"NOT_FOUND",resource:"Context",id:i})},"topic:add":async function(e,t){const{workspace:s,topics:r}=e,i=t;return s.index.topics[i.name]?y({code:"DUPLICATE_KEY",resource:"Topic",key:i.name}):(await r.add(i),m({index:{topics:{[i.name]:{topic:i.name,contextKeys:[],preferences:[],metadata:{created:i.created,updated:i.updated,entries:0}}}}}))},"topic:update":async function(e,t){const{workspace:s,topics:r}=e,{name:i,...n}=t;if(!s.index.topics[i])return y({code:"NOT_FOUND",resource:"Topic",id:i});const o=await r.update(i,n);return o?m({index:{topics:{[i]:{metadata:{updated:o.updated}}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update topic ${i} in store.`})},"topic:delete":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{name:o,cascade:a}=t;if(!s.index.topics[o])return y({code:"NOT_FOUND",resource:"Topic",id:o});if(r.referencedBy(o,s.index)&&!a)return y({code:"INVALID_COMMAND",reason:`Topic '${o}' is referenced by other entities. Use 'cascade: true' to force deletion.`});if(a){for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);t&&await i.update(e,{topics:t.topics.filter((e=>e!==o))})}}for(const e in s.index.sessions){const t=s.index.sessions[e];t.topics?.includes(o)&&await n.update(e,{topics:t.topics.filter((e=>e!==o))})}}return await r.delete(o)?m({index:{topics:{[o]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete topic ${o} from store.`})},"topic:merge":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{source:o,target:a}=t;if(!s.index.topics[o]||!s.index.topics[a])return y({code:"NOT_FOUND",resource:"Topic",id:s.index.topics[o]?a:o});for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);if(t){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await i.update(e,{topics:s})}}}for(const e in s.index.sessions){const t=s.index.sessions[e];if(t.topics?.includes(o)){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await n.update(e,{topics:s})}}return await r.delete(o),m({index:{topics:{[o]:h}}})},"session:create":async function(e,t){const{workspace:s,sessions:r}=e,i=t;return s.index.sessions[i.id]?y({code:"DUPLICATE_KEY",resource:"Session",key:i.id}):(await r.add(i),m({index:{sessions:{[i.id]:{id:i.id,label:i.label,role:i.role,topics:i.topics,preferences:i.preferences,metadata:i.metadata}}}}))},"session:update":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,...n}=t;if(!s.index.sessions[i])return y({code:"NOT_FOUND",resource:"Session",id:i});const o=await r.update(i,n);return o?m({index:{sessions:{[i]:{label:o.label,role:o.role,topics:o.topics,preferences:o.preferences,metadata:o.metadata,head:o.head}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update session ${i} in store.`})},"session:fork":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,newSessionId:n,label:o}=t,a=s.index.sessions[i];if(!a)return y({code:"NOT_FOUND",resource:"Session",id:i});const c={...a,id:n,label:o||`Fork of ${a.label}`,role:t.role?t.role:a.role,topics:t.topics?t.topics:a.topics};return await r.add(c),m({index:{sessions:{[n]:{id:n,label:c.label,role:c.role,topics:c.topics,preferences:c.preferences,metadata:c.metadata,head:c.head}}}})},"session:delete":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i}=t;return s.index.sessions[i]?(await r.delete(i),m({index:{sessions:{[i]:h}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:role:switch":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,roleName:n}=t;return s.index.sessions[i]?(await r.update(i,{role:n}),m({index:{sessions:{[i]:{role:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:topics:add":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,topics:n}=t,o=s.index.sessions[i];if(!o)return y({code:"NOT_FOUND",resource:"Session",id:i});const a=Array.from(new Set([...o.topics,...n]));return await r.update(i,{topics:a}),m({index:{sessions:{[i]:{topics:a}}}})},"session:preferences:override":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,preferences:n}=t;return s.index.sessions[i]?(await r.update(i,{preferences:n}),m({index:{sessions:{[i]:{preferences:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"turn:add":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:update":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.update(o,o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:edit":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newBlocks:a,newVersion:c,roleSnapshot:d}=t,u=s.index.sessions[n];if(!u)return y({code:"NOT_FOUND",resource:"Session",id:n});const l=u.head;let h={};if(l&&l.id===o){const e=await i.get({id:l.id,version:l.version,session:n});e&&(h={...e})}const p={...h,id:o,version:c,blocks:a,role:d??h.role,timestamp:(new Date).toISOString(),parent:h.parent,actor:h.actor||"assistant",session:n};if(await i.add(p),u.head?.id===o){const e={id:o,version:c};return await r.update(n,{head:e}),m({index:{sessions:{[n]:{head:e}}}})}return m({})},"turn:branch":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:delete":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newHead:a}=t;return s.index.sessions[n]?(await i.delete({session:n,id:o,version:t.version}),a?(await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})):m({})):y({code:"NOT_FOUND",resource:"Session",id:n})},"blob:register":async function(e,t){const{blobs:s}=e,r=await s.register(t.data,t.mediaType,t.filename);if(!r.ok)return r;const i=await s.getRecord(r.value.sha256);return i?m({index:{blobs:{[i.sha256]:i}}}):y({code:"BACKEND_ERROR",reason:`Failed to retrieve registered blob record for ${r.value.sha256}`})},"blob:retain":async function(e,t){const{blobs:s}=e,r=await s.retain(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i}}})},"blob:release":async function(e,t){const{blobs:s}=e,r=await s.release(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i||h}}})},"blob:purge":async function(e,t){const{blobs:s}=e,r=await s.purge(t.sha256);return r.ok?m({index:{blobs:{[t.sha256]:h}}}):r},"blob:record_remote_id":async function(e,t){const{blobs:s}=e,{sha256:r,providerId:i,fileId:n,timestamp:o}=t,a=await s.recordRemoteId(r,i,n,o);if(!a.ok)return a;const c=await s.getRecord(r);return m({index:{blobs:{[r]:c}}})},"tool:call":async function(e,t){return m({})}},E="__system__",F=class{constructor(t,s,r){this._actor=t,this._turn=r?JSON.parse(JSON.stringify(r)):{id:e(),session:s,version:0,actor:this._actor,blocks:[],timestamp:(new Date).toISOString(),role:void 0}}_turn;addText(t){const s={id:e(),type:"text",text:t};return this._turn.blocks.push(s),this}addImage(t,s){const r={id:e(),type:"image",ref:t,altText:s};return this._turn.blocks.push(r),this}addDocument(t,s){const r={id:e(),type:"document",ref:t,title:s};return this._turn.blocks.push(r),this}addToolUse(t,s){const r={id:e(),type:"tool:use",name:t,input:s};return this._turn.blocks.push(r),this}addToolResult(t,s,r){const i={id:e(),type:"tool:result",useId:t,content:s,isError:r};return this._turn.blocks.push(i),this}addSummary(t){const s={id:e(),type:"summary",text:t};return this._turn.blocks.push(s),this}addRoleTransition(t,s){const r={id:e(),type:"role:transition",previousRole:t,newRole:s};return this._turn.blocks.push(r),this}addThinking(t){const s={id:e(),type:"thinking",thinking:t};return this._turn.blocks.push(s),this}addBlock(e){return this._turn.blocks.push(e),this}deleteBlock(e){return this._turn.blocks=this._turn.blocks.filter((t=>t.id!==e)),this}editTextBlock(e,t){const s=this._turn.blocks.findIndex((t=>t.id===e));if(-1===s)throw new Error(`Block with ID ${e} not found.`);const r=this._turn.blocks[s];if("text"!==r.type)throw new Error(`Block with ID ${e} is not a TextBlock.`);return this._turn.blocks[s]={...r,text:t},this}withId(e){return this._turn.id=e,this}withVersion(e){return this._turn.version=e,this}withTimestamp(e){return this._turn.timestamp=e,this}withParent(e){return this._turn.parent=e,this}withRoleSnapshot(e){return this._turn.role=e,this}build(){return JSON.parse(JSON.stringify(this._turn))}},q=class{constructor(e,t){this.turnStore=e,this.sessionStore=t}async loadAllTurns(e){return this.turnStore.listBySession(e)}async loadHead(e){const t=await this.sessionStore.get(e);return t?.head??null}},U=class e{constructor(e,t){this.nodes=e,this._head=t}static async build(t,s){const[r,i]=await Promise.all([s.loadAllTurns(t),s.loadHead(t)]),n=function(e,t){const s=function(e,t){if(!t)return new Set;const s=new Map;for(const t of e)s.set(`${t.id}:${t.version}`,t);const r=new Set;let i=t;for(;i;){const e=`${i.id}:${i.version}`;if(r.has(e))break;r.add(e);const t=s.get(e);if(!t)break;i=t.parent}return r}(e,t),r={},i={};for(const t of e){r[t.id]||(r[t.id]={id:t.id,versions:{},activeVersion:t.version,actor:t.actor,blocks:t.blocks,timestamp:t.timestamp,roleSnapshot:t.role,parent:t.parent,children:{}},i[t.id]=new Set);const e=r[t.id];e.versions[t.version]=t;const n=s.has(`${t.id}:${t.version}`),o=s.has(`${t.id}:${e.activeVersion}`);if(n&&(!o||t.version>=e.activeVersion)&&(e.activeVersion=t.version,e.blocks=t.blocks,e.timestamp=t.timestamp,e.roleSnapshot=t.role,e.parent=t.parent),t.parent){const e=`${t.parent.id}:${t.parent.version}`;if(i[t.parent.id]||(i[t.parent.id]=new Set),!i[t.parent.id].has(e+":"+t.id)){i[t.parent.id].add(e+":"+t.id),r[t.parent.id]||(r[t.parent.id]={id:t.parent.id,versions:{},activeVersion:t.parent.version,actor:"user",blocks:[],timestamp:"",roleSnapshot:void 0,children:{}});const s=r[t.parent.id];s.children[t.parent.version]||(s.children[t.parent.version]=[]),s.children[t.parent.version].push(t.id)}}}return r}(r,i);return new e(n,i)}head(){return this._head}chain(){if(!this._head)return[];const e=[];let t=this._head.id;for(;t;){const s=this.nodes[t];if(!s)break;e.push(s),t=s.parent?.id??null}return e.reverse()}getTurnSiblings(e){const t=this.nodes[e];if(!t)return[];if(!t.parent)return Object.values(this.nodes).filter((e=>!e.parent));const s=this.nodes[t.parent.id];if(!s)return[t];const r=s.children[t.parent.version];return r?r.map((e=>this.nodes[e])).filter((e=>!!e)):[t]}branchInfo(e){const t=this.nodes[e];if(!t)return{versions:[],currentIndex:-1,total:0,hasPrev:!1,hasNext:!1};const s=Object.keys(t.versions).map(Number).sort(((e,t)=>e-t)),r=s.indexOf(t.activeVersion);return{versions:s,currentIndex:r,total:s.length,hasPrev:r>0,hasNext:r<s.length-1}}graph(){return{...this.nodes}}};var A=class{constructor(e){this.manager=e}get workspace(){return this.manager.workspace()}roles(){return this.manager.ctx().roles.list()}role(e){return this.manager.ctx().roles.get(e)}async createRole(e,t,s,r,i=[]){if(this.workspace.index.roles[e])return y({code:"DUPLICATE_KEY",resource:"role",key:e});const n={name:e,label:t,description:r,persona:s,preferences:i,topics:[]};return this.manager.dispatch({type:"role:add",payload:n,timestamp:(new Date).toISOString()})}async updateRole(e,t){return this.workspace.index.roles[e]?this.manager.dispatch({type:"role:update",payload:{name:e,...t},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"role",id:e})}async deleteRole(e){const t=this.workspace;if(!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});return Object.values(t.index.sessions).some((t=>t.role===e))?y({code:"INVALID_COMMAND",reason:`Cannot delete role "${e}" — it is still referenced by one or more sessions`}):this.manager.dispatch({type:"role:delete",payload:{name:e},timestamp:(new Date).toISOString()})}async addPreference(e,t){const s={id:crypto.randomUUID(),content:e,topics:t,timestamp:(new Date).toISOString()};return this.manager.dispatch({type:"preference:add",payload:s,timestamp:s.timestamp})}preferences(){return this.manager.ctx().preferences.list()}async addContext(e,t,s,r){const i={key:e,topics:s,content:t,timestamp:(new Date).toISOString(),metadata:r};return this.manager.dispatch({type:"context:add",payload:i,timestamp:i.timestamp})}context(){return this.manager.ctx().context.list()}async registerBlob(e,t,s){const r=await this.manager.dispatch({type:"blob:register",payload:{data:e,mediaType:t,filename:s},timestamp:(new Date).toISOString()});if(!r.ok)return y(r.error);const i=r.value,n=i?.index?.blobs;if(!n)return y({code:"BACKEND_ERROR",reason:"Blob registration succeeded but no blobs patch returned"});const o=Object.keys(n)[0];if(!o)return y({code:"BACKEND_ERROR",reason:"No SHA256 in patch"});const a=n[o];if(!a)return y({code:"BACKEND_ERROR",reason:"Blob record missing"});return f({sha256:o,ref:{sha256:o,mediaType:a.mediaType,sizeBytes:a.sizeBytes,filename:a.filename,previewUrl:a.previewUrl}})}},B=class e{constructor(e,t,s,r){this._id=e,this.manager=t,this.processor=s,this.turnRepository=r,this.workspace=new A(t)}workspace;_role=void 0;_preferences=[];tree;static async create(t,s,r){const i=new q(s.ctx().turns,s.ctx().sessions),n=new e(t,s,r,i);return await n._setRole(),await n._setPreference(),await n.refreshTurnTree(),n}async _setRole(){const e=this.meta(),t=await this.manager.ctx().roles.get(e.role);t&&(this._role=t)}async _setPreference(){const e=this.meta();this._preferences=await this.manager.ctx().preferences.load(e.preferences)}id(){return this._id}ws(){return this.manager.workspace()}meta(){return this.ws().index.sessions[this._id]}label(){return this.meta()?.label}role(){return this._role}topics(){return this.meta()?.topics??[]}preferences(){return this._preferences}head(){return this.meta()?.head??null}turns(){return this.tree.chain()}async siblings(e){return this.tree.getTurnSiblings(e)}async branchInfo(e){return this.tree.branchInfo(e)}async getTurn(e){return this.tree.graph()[e]}async rename(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,label:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setTopics(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async addTopics(e){return this.meta()?this.dispatch({type:"session:topics:add",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setPreferences(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t=await this.dispatch({type:"session:preferences:override",payload:{sessionId:this._id,preferences:e},timestamp:(new Date).toISOString()});return t.ok&&await this._setPreference(),t}async fork(e,t,s,r){return this.meta()?this.dispatch({type:"session:fork",payload:{sessionId:this._id,newSessionId:e,label:t,role:s,topics:r},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async dispatch(e){return this.manager.dispatch(e)}async switchRole(e){const t=this.ws();if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(e!==E&&!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});const s=await this.dispatch({type:"session:update",payload:{sessionId:this._id,role:e},timestamp:(new Date).toISOString()});return s.ok&&await this._setRole(),s}async addTurn(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t={...e,session:this._id,version:e.version??0,parent:!e.parent&&this.head()?this.head():void 0},s=await this.dispatch({type:"turn:add",payload:{sessionId:this._id,turn:t},timestamp:t.timestamp});return s.ok&&await this.refreshTurnTree(),s}async recordUserTurn(e){return this.meta()?this.addTurn(e):y({code:"NOT_FOUND",resource:"session",id:this._id})}async recordAssistantTurn(e,t){const s=this.ws();if(!s)return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!s.index.sessions[this._id])return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.processor.process(e,this._id);let i={};const n=[];for(const e of r){const t=await this.manager.dispatch(e);if(t.ok)i=_(i,t.value);else{if("PERMISSION_DENIED"!==t.error.code||e.synthetic)return t;{const t=this.describeCommand(e);n.push({cmd:e,description:t})}}}const o=await this.addTurn(e);if(!o.ok)return o;if(i=_(i,o.value),t&&n.length>0){const e=this.buildDenialTurn(n),t=await this.addTurn(e);t.ok&&(i=_(i,t.value))}return f(i)}buildDenialTurn(e){const t=new F("user",this._id);for(const s of e)t.addText(`[System] User denied: ${s.description}.`);return t.build()}describeCommand(e){return"tool:call"===e.type?`tool execution: ${e.payload.tool}`:`command: ${e.type}`}async editTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph()[e];if(!r)return y({code:"NOT_FOUND",resource:"turn",id:e});const i=r.versions[r.activeVersion],n=r.activeVersion+1,o=await this.dispatch({type:"turn:edit",payload:{sessionId:this._id,turnId:e,newBlocks:t,roleSnapshot:s??i.role,newVersion:n},timestamp:(new Date).toISOString()});return o.ok&&await this.refreshTurnTree(),o}async branch(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(!e.parent)return y({code:"INVALID_COMMAND",reason:"branch requires turn.parent to be set"});const t=await this.dispatch({type:"turn:branch",payload:{sessionId:this._id,turn:{...e,session:this._id}},timestamp:e.timestamp});return t.ok&&await this.refreshTurnTree(),t}async deleteTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph();if(!r[e]?.versions[t])return y({code:"NOT_FOUND",resource:"turn version",id:`${e}:${t}`});const i=await this.dispatch({type:"turn:delete",payload:{sessionId:this._id,turnId:e,version:t,newHead:s},timestamp:(new Date).toISOString()});return i.ok&&await this.refreshTurnTree(),i}async switchVersionLeft(e){return this.switchVersion(e,-1)}async switchVersionRight(e){return this.switchVersion(e,1)}async switchVersion(e,t){if(!this.ws())return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const s=this.tree.graph()[e];if(!s)return y({code:"NOT_FOUND",resource:"turn",id:e});const r=Object.keys(s.versions).map(Number).sort(((e,t)=>e-t)),i=r.indexOf(s.activeVersion);if(-1===i)return y({code:"INVALID_COMMAND",reason:"Active version not found"});const n=i+t;if(n<0||n>=r.length)return y({code:"INVALID_COMMAND",reason:`No ${t<0?"previous":"next"} version available for turn ${e}`});const o=r[n],a=this.findSubtreeTip(this.tree.graph(),e,o),c=await this.dispatch({type:"session:update",payload:{sessionId:this._id,head:a},timestamp:(new Date).toISOString()});return c.ok&&await this.refreshTurnTree(),c}async snapshot(){const e=this,t=e.meta();if(!t)return;const s=e.ws(),r=e._role;if(!r)return;const i=await e.manager.ctx().context.getByTopics(s.index,t.topics),n=Array.from(new Set([...r.preferences,...t.preferences])),o=n.length>0?await e.manager.ctx().preferences.load(n):e._preferences,a=e.tree.chain().map((e=>e.versions[e.activeVersion])).filter((e=>!!e)),c=[...a].reverse().find((e=>"user"===e.actor));return{id:e._id,meta:t,role:r,preferences:o,context:i,transcript:a,topics:t.topics,instructions:s.settings?.prompt,constraints:{role:r.constraints,session:t.constraints,turn:c?.constraints}}}async refreshTurnTree(){this.tree=await U.build(this._id,this.turnRepository)}findSubtreeTip(e,t,s){let r=t,i=s;for(;;){const t=e[r];if(!t)break;const s=t.children[i];if(!s||0===s.length)break;const n=s[0],o=e[n];if(!o)break;r=n,i=o.activeVersion}return{id:r,version:i}}},C=class{constructor(e,t){this.manager=e,this.processor=t}openOnce=new Map;async open(e){let t=this.openOnce.get(e);t||(t=new o,this.openOnce.set(e,t));const s=await t.do((async()=>{if(!this.manager.workspace().index.sessions[e])throw new Error(`Session ${e} not found in workspace index`);return B.create(e,this.manager,this.processor)}));if(s.error)throw s.error;return s.value}close(e){this.openOnce.delete(e)}async delete(e){const t=await this.manager.dispatch({type:"session:delete",payload:{sessionId:e},timestamp:(new Date).toISOString()});if(t.ok)return this.close(e),t.value=void 0,t;throw t.error}async create(t){const s=e(),r=await this.manager.dispatch({type:"session:create",payload:{...t,id:s},timestamp:(new Date).toISOString()});if(r.ok)return this.open(s);throw r.error}list(){return Object.values(this.manager.workspace().index.sessions)}metadata(e){return this.manager.workspace().index.sessions[e]}},$=class{constructor(e,t,s){this.storage=e,this.cache=t,this.bus=s}async register(e,t,s){const r=await b(e),i=await this.getRecord(r);if(i){const e={...i,refCount:i.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(e),this.cache.set(r,e),f(this.reference(e))}const n={sha256:r,mediaType:t,sizeBytes:e.byteLength,filename:s,refCount:1,remoteIds:{},createdAt:(new Date).toISOString(),lastUsedAt:(new Date).toISOString()};return this.storage.registerBlob?await this.storage.registerBlob(n,e):(await this.storage.storeBytes(r,e),await this.storage.saveRecord(n)),this.cache.set(r,n),this.bus.emit({name:"blobs:changed",payload:{sha256:r,record:n}}),f(this.reference(n))}async retain(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s={...t,refCount:t.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(s),this.cache.set(e,s),f(void 0)}async release(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s=Math.max(0,t.refCount-1),r={...t,refCount:s,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(r),this.cache.set(e,r),f(void 0)}async purge(e){return await this.storage.deleteBytes(e),await this.storage.deleteRecord(e),this.cache.delete(e),this.bus.emit({name:"blobs:changed",payload:{sha256:e}}),f(void 0)}async recordRemoteId(e,t,s,r){const i=await this.getRecord(e);if(!i)return y({code:"NOT_FOUND",resource:"blob",id:e});const n={...i,remoteIds:{...i.remoteIds,[t]:{id:s,timestamp:r||(new Date).toISOString()}},lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(n),this.cache.set(e,n),this.bus.emit({name:"blobs:changed",payload:{sha256:e,record:n}}),f(void 0)}async getRecord(e){const t=this.cache.get(e);if(t)return t;const s=await this.storage.loadRecord(e);return s&&this.cache.set(e,s),s}async getAllRecords(){const e=await this.storage.listRecords(),t={};for(const s of e)t[s.sha256]=s,this.cache.set(s.sha256,s);return t}reference(e){return{sha256:e.sha256,mediaType:e.mediaType,sizeBytes:e.sizeBytes,filename:e.filename}}async resolve(e,t){const s=await this.getRecord(e.sha256);if(!s)return f(null);if(t){const e=s.remoteIds[t];if(e)return f({kind:"remote",sha256:s.sha256,mediaType:s.mediaType,fileId:e.id,providerId:t,timestamp:e.timestamp});const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}async resolveMany(e,t){const s=new Map;for(const r of e){const e=await this.resolve(r,t);if(!e.ok)return y(e.error);if(null===e.value)return y({code:"BLOB_ERROR",reason:`Unable to resolve blob ${r.sha256}${t?` with adapter ${t}`:""}`});s.set(r.sha256,e.value)}return f(s)}},M=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.key,e)}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}async update(e,t){const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"key",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getByTopics(e,t){const s=new Set;for(const r of t){const t=e.topics[r];t&&t.contextKeys.forEach((e=>s.add(e)))}if(0===s.size)return[];const r=[],i=[];for(const e of s){const t=this.cache.get(e);t?i.push(t):r.push(e)}if(r.length>0){const e=await this.collection.filter({operator:"or",conditions:r.map((e=>({field:"key",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.key,e),i.push(e)}}return i.sort(((e,t)=>new Date(t.timestamp).getTime()-new Date(e.timestamp).getTime()))}},j=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async load(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?s.push(e):t.push(r)}if(t.length>0){const e=await this.collection.filter({operator:"or",conditions:t.map((e=>({field:"id",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.id,e),s.push(e)}}return s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},P=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},V=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}},z=class{constructor(e,t){this.collection=e,this.cache=t}key({id:e,session:t,version:s}){return`${t}:${s}:${e}`}async find({id:e,session:t,version:s},r=!0){const i=this.key({id:e,session:t,version:s});this.cache.get(i)&&this.cache.get(i);const n=await this.collection.find({operator:"and",conditions:[{field:"id",operator:"eq",value:e},{field:"session",operator:"eq",value:t},{field:"version",operator:"eq",value:s}]});return n?(r&&this.cache.set(i,n),n):null}async get(e){return this.find(e)}async add(e){const t=await this.collection.create(e);this.cache.set(this.key(e),t)}async update(e,t){const s=await this.find(e);return s?(await s.update(t),s.state()):null}async listBySession(e){return(await this.collection.filter({field:"session",operator:"eq",value:e})).map((e=>e.state()))}async delete(e){const t=await this.find(e,!1);if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(this.key(e)),s}},K=class{cache;maxSize;constructor(e){this.cache=new Map,this.maxSize=e}get(e){const t=this.cache.get(e);return void 0!==t&&(this.cache.delete(e),this.cache.set(e,t)),t}set(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){const e=this.cache.keys().next().value;void 0!==e&&this.cache.delete(e)}this.cache.set(e,t)}has(e){return this.cache.has(e)}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}};async function L(e){const{blobStorage:t,eventBus:s=c(),getWorkspace:r,setWorkspace:i,processor:n,guard:o,toolRegistry:a,extensionReducers:d={},extensionMiddleware:h=[]}=e,p=u(e.db);await p.open(e.extensionSchemas);const f={role:await p.collection(l.ROLE),preference:await p.collection(l.PREFERENCE),context:await p.collection(l.CONTEXT),session:await p.collection(l.SESSION),topic:await p.collection(l.TOPIC),turn:await p.collection(l.TURN)},m=new $(t,new K(200),s),y={roles:new P(f.role,new K(100)),preferences:new j(f.preference,new K(500)),context:new M(f.context,new K(500)),topics:new x(f.topic,new K(100)),sessions:new V(f.session,new K(50)),turns:new z(f.turn,new K(50)),blobs:m,tools:a,db:p},w=new k({ctx:y,getWorkspace:r,updateWorkspace:i,guard:o,bus:s});Object.entries(R).forEach((([e,t])=>{w.register(e,t)})),Object.entries(d).forEach((([e,t])=>{w.register(e,t)})),w.use(I),h.forEach((e=>{w.use(e)}));const g=new C(w,n);return{manager:w,sessions:g,ctx:y}}export{l as COLLECTIONS,E as EMPTY_SYSTEM_ROLE,K as LRUCache,B as Session,C as SessionManager,F as TurnBuilder,U as TurnTree,k as WorkspaceManager,v as bufferToBase64,b as computeSHA256,L as createWorkspace,u as createWorkspaceDatabase,g as del,y as error,_ as merge,m as ok,w as omitNullUndefined,f as success};
1
+ import{v7 as e}from"uuid";var t=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let s;this._pendingFn=void 0;try{s={status:"ok",value:await e()}}catch(e){s={status:"error",error:e}}for(const e of t)e(s);return s}},s=class e extends Error{constructor(t,s){super(t,{cause:s}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},r=class extends s{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},i=class extends s{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},n=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const s=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await s;let i;await Promise.race([s.then((()=>clearTimeout(i))),new Promise(((s,n)=>{i=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(new r("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},o=class{mutex=new n({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,s="Operation timed out"){if(null==t)return e;let i;return Promise.race([e.then((e=>(clearTimeout(i),e))),new Promise(((e,n)=>{i=setTimeout((()=>n(new r(s))),t)}))])}},a=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new n({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new i};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let s,r=null;try{if(this._done)throw new i;r=await e(),this._lastValue=r,this._lastError=void 0,this._hasRun=!0}catch(e){s=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:r,error:s}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}};function c(e){const s={},r=s.errorHandler??(e=>console.error("EventBus Error:",e)),i=null!=s.batch?.size,n=s.batch?.size,o=s.batch?.delay??16;if(i&&(n<=0||!Number.isFinite(n)))throw new Error(`EventBus: batch.size must be a positive finite number, got ${n}.`);if(i&&(o<0||!Number.isFinite(o)))throw new Error(`EventBus: batch.delay must be a non-negative finite number, got ${o}.`);const a=s.broadcast?.channel,c=null!=a&&a.length>0,d=new Map;let u=[];const l=i?new t({delay:o}):null;let h=0,p=0;const f=new Map,m=()=>{if(!c)return null;if("undefined"==typeof BroadcastChannel)return console.warn("EventBus: BroadcastChannel is not supported in this environment. Cross-tab notifications are disabled."),null;const e=new BroadcastChannel(a);return e.onmessage=e=>{const{name:t,payload:s}=e.data;g(t,s)},e};let y=m();const w=(e,t)=>{h++,p+=t,f.set(e,(f.get(e)??0)+1)},g=(e,t)=>{const s=d.get(e);if(s&&0!==s.size)for(const i of Array.from(s))try{i(t)}catch(s){const i=s instanceof Error?s:Object.assign(new Error(String(s)),{cause:s}),n=Object.assign(i,{eventName:e,payload:t});r(n)}},_=(e,t)=>{d.has(e)||d.set(e,new Set);const s=d.get(e);return s.add(t),()=>{s.delete(t),0===s.size&&d.delete(e)}},b=()=>{const e=u;u=[];for(const{name:t,payload:s}of e){const e=performance.now();g(t,s),w(t,performance.now()-e)}};return{subscribe:(e,t)=>_(e,t),once:(e,t)=>{let s;return s=_(e,(e=>{s(),t(e)})),s},emit:({name:e,payload:t})=>{if(i)return u.push({name:e,payload:t}),u.length>=n?(l.cancel(),void b()):(l.fire((()=>b())),void y?.postMessage({name:e,payload:t}));const s=performance.now();g(e,t),w(e,performance.now()-s),y?.postMessage({name:e,payload:t})},metrics:()=>({totalEvents:h,activeSubscriptions:Array.from(d.values()).reduce(((e,t)=>e+t.size),0),eventCounts:new Map(f),averageEmitDuration:h>0?p/h:0}),clear:()=>{l?.cancel(),u=[],d.clear(),h=0,p=0,f.clear(),y?.close(),y=m()}}}var d=[{name:"role",version:"1.0.0",description:"AI persona with a system prompt and associated preference defaults.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!0},description:{name:"description",type:"string",required:!1},persona:{name:"persona",type:"string",required:!0},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},topics:{name:"topics",type:"array",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_name",fields:["name"],type:"unique"},{name:"by_label",fields:["label"],type:"normal"}],constraints:[],migrations:[]},{name:"preference",version:"1.0.0",description:"A user behavioural instruction, scoped to zero or more topics.",fields:{id:{name:"id",type:"string",required:!0},content:{name:"content",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},timestamp:{name:"timestamp",type:"string",required:!0}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"context",version:"1.0.0",description:"Injected background knowledge, scoped to topics. Content is a discriminated union.",fields:{key:{name:"key",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},content:{name:"content",type:"record",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},metadata:{name:"metadata",type:"record",required:!1}},indexes:[{name:"by_key",fields:["key"],type:"unique"},{name:"by_topics",fields:["topics"],type:"normal"},{name:"by_timestamp",fields:["timestamp"],type:"btree"}],constraints:[],migrations:[]},{name:"session",version:"1.0.0",description:"Session metadata. The head field tracks the current tip of the turn DAG.",fields:{id:{name:"id",type:"string",required:!0},label:{name:"label",type:"string",required:!0},role:{name:"role",type:"string",required:!0},topics:{name:"topics",type:"array",required:!1,itemsType:"string"},preferences:{name:"preferences",type:"array",required:!1,itemsType:"string"},metadata:{name:"metadata",type:"record",required:!1},head:{name:"head",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_id",fields:["id"],type:"unique"},{name:"by_role",fields:["role"],type:"normal"}],constraints:[],migrations:[]},{name:"turn",version:"1.0.0",description:["A single message in a session transcript, stored as a flat document.","The DAG is reconstructed in memory by TurnTree.buildNodeGraph() at session open time."].join(" "),fields:{id:{name:"id",type:"string",required:!0},session:{name:"session",type:"string",required:!0},version:{name:"version",type:"number",required:!0},actor:{name:"actor",type:"enum",required:!0,values:["user","assistant","tool"]},blocks:{name:"blocks",type:"array",required:!0},timestamp:{name:"timestamp",type:"string",required:!0},role:{name:"role",type:"string",required:!1},parent:{name:"parent",type:"record",required:!1},constraints:{name:"constraints",type:"record",required:!1}},indexes:[{name:"by_session",fields:["session"],type:"normal"},{name:"by_session_parent",fields:["session","parent"],type:"composite"},{name:"by_session_id_ver",fields:["session","id","version"],type:"composite",unique:!0}],constraints:[],migrations:[]},{name:"topic",version:"1.0.0",description:"A categorization for context and preferences, used for retrieval.",fields:{name:{name:"name",type:"string",required:!0},label:{name:"label",type:"string",required:!1},description:{name:"description",type:"string",required:!1},metadata:{name:"metadata",type:"record",required:!1},created:{name:"created",type:"string",required:!0},updated:{name:"updated",type:"string",required:!0}},indexes:[{name:"by_name",fields:["name"],type:"unique"}],constraints:[],migrations:[]}];function u(e){const t=new o({retry:!0,throws:!0}),s=new o({retry:!0,throws:!0});return{open:async(s=[])=>(await t.do((async()=>{const t=[...d,...s];await e.setupCollections(t)}))).value,collection:async t=>e.collection(t),close:async()=>(await s.do((()=>{e.close()}))).value,database:()=>e}}var l={ROLE:"role",PREFERENCE:"preference",CONTEXT:"context",SESSION:"session",TURN:"turn",BLOB:"blob",TOPIC:"topic"},h=Symbol.for("delete"),p=e=>Array.isArray(e)?[...e]:{...e};function f(e){return{ok:!0,value:e}}function m(e){return f(e)}function y(e){return{ok:!1,error:e}}function w(e){return Object.fromEntries(Object.entries(e).filter((([e,t])=>null!=t)))}function g(){return h}var _=function(e){const t=e?.deleteMarker||h;function s(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==t)).map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e:s(e)));if("object"==typeof e){const r={};for(const[i,n]of Object.entries(e))if(n!==t)if("object"==typeof n&&null!==n){const e=s(n);void 0!==e&&(r[i]=e)}else r[i]=n;return r}return e===t?void 0:e}return function(e,r){if("object"!=typeof e||null===e)return"object"==typeof r&&null!==r?s(r):r===t?{}:r;if("object"!=typeof r||null===r)return e;const i=p(e),n=[{target:i,source:r}];for(;n.length>0;){const{target:e,source:s}=n.pop();for(const r of Object.keys(s)){const i=s[r];if(i!==t)if(Array.isArray(i))e[r]=i;else if("object"==typeof i&&null!==i){const t=r in e&&"object"==typeof e[r]&&null!==e[r]?e[r]:{};e[r]=p(t),n.push({target:e[r],source:i})}else e[r]=i;else delete e[r]}}return i}}({deleteMarker:h});async function b(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map((e=>e.toString(16).padStart(2,"0"))).join("")}function v(e){if("undefined"!=typeof Buffer)return Buffer.from(e).toString("base64");const t=[];for(let s=0;s<e.length;s+=32768){const r=e.subarray(s,s+32768);t.push(String.fromCharCode.apply(null,Array.from(r)))}return btoa(t.join(""))}function k(e,t=4){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return Math.abs(s).toString(36).padEnd(t,"0").slice(0,t)}function x(e,t){return e.extensions[t]}var O=class{registry=new Map;middlewares=[];serializer=new a;bus;_getWorkspace;updateWorkspace;guard;_ctx;constructor(e){this._ctx=e.ctx,this._getWorkspace=e.getWorkspace,this.updateWorkspace=e.updateWorkspace,this.guard=e.guard,this.bus=e.bus}register(e,t){return this.registry.set(e,t),this}use(e){return this.middlewares.push(e),this}workspace(){return this._getWorkspace()}async dispatch(e){const t=await this.serializer.do((async()=>{if(this.guard){const t=await this.guard.authenticate({type:"command",payload:e});if(!t.ok)return y(t.error)}const t=this.registry.get(e.type);if(!t)return y({code:"INVALID_COMMAND",reason:`No reducer registered for command type: ${e.type}`});const s=this._getWorkspace(),r=await t({workspace:s,...this._ctx},e.payload);if(!r.ok)return r;let i=r.value;for(const t of this.middlewares){const r=await t({workspace:s,command:e,patch:i,...this._ctx});i=_(i,r)}return await this.updateWorkspace(i),this.bus.emit({name:"workspace:changed",payload:i}),m(i)}));if(t.error)throw t.error;return t.value}subscribe(e,t){return this.bus.subscribe(e,t)}ctx(){return{workspace:this._getWorkspace(),...this._ctx}}},T=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getMany(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?t.push(e):s.push(r)}if(s.length>0){const e=await this.collection.filter({operator:"or",conditions:s.map((e=>({field:"name",operator:"eq",value:e})))});for(const s of e){const e=s.state();this.cache.set(e.name,e),t.push(e)}}return t}referencedBy(e,t){for(const s in t.roles)if(t.roles[s].topics?.includes(e))return!0;for(const s in t.sessions)if(t.sessions[s].topics?.includes(e))return!0;for(const s in t.context)if(t.context[s].topics?.includes(e))return!0;for(const s in t.preferences)if(t.preferences[s].topics?.includes(e))return!0;return!1}};function N(e,t,s,r,i,n){const o={};for(const a of t){let t=e[a];if(!t){if("add"!==i||!n)continue;t={topic:a,contextKeys:[],preferences:[],metadata:{created:(new Date).toISOString(),updated:(new Date).toISOString(),entries:0}},n.add({name:a,created:t.metadata.created,updated:t.metadata.updated})}const c=t[r],d=c.includes(s);if("add"!==i||d){if("remove"===i&&d){const e=Math.max(0,(t.metadata.entries||0)-1);o[a]={...t,[r]:c.filter((e=>e!==s)),metadata:{...t.metadata,updated:(new Date).toISOString(),entries:e}}}}else o[a]={...t,[r]:[...c,s],metadata:{...t.metadata,updated:(new Date).toISOString(),entries:(t.metadata.entries||0)+1}}}return{index:{topics:o}}}function S(e,t,s,r){return N(e,t,s,"contextKeys","add",r)}function D(e,t,s){return N(e,t,s,"contextKeys","remove")}function I(e,t,s,r){return N(e,t,s,"preferences","add",r)}function R(e,t,s){return N(e,t,s,"preferences","remove")}var E=async e=>{if(!e.patch)return;const{workspace:t,patch:s}=e,r=t.index.topics;let i={};const n=e=>{const t=e?.index?.topics;t&&(i=_(i,t))};if(s.index?.context)for(const[i,o]of Object.entries(s.index.context)){const s=t.index.context[i];if(void 0===o&&s)n(D(r,s.topics,s.key));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(D(r,c,s.key)),a.length&&n(S(r,a,s.key,e.topics))}}else n(S(r,o.topics??[],o.key,e.topics))}if(s.index?.preferences)for(const[i,o]of Object.entries(s.index.preferences)){const s=t.index.preferences[i];if(void 0===o&&s)n(R(r,s.topics,s.id));else if(s||!o){if(s&&o){const t=s.topics??[],i=o.topics??t,a=i.filter((e=>!t.includes(e))),c=t.filter((e=>!i.includes(e)));c.length&&n(R(r,c,s.id)),a.length&&n(I(r,a,s.id,e.topics))}}else n(I(r,o.topics??[],o.id,e.topics))}return Object.keys(i).length?{index:{topics:i}}:{}};var F={"role:add":async function(e,t){const{workspace:s,roles:r}=e,i=t;return s.index.roles[i.name]?y({code:"DUPLICATE_KEY",resource:"Role",key:i.name}):(await r.add(i),m({index:{roles:{[i.name]:{name:i.name,label:i.label,description:i.description,preferences:i.preferences.length}}}}))},"role:update":async function(e,t){const{workspace:s,roles:r}=e,{name:i,...n}=t;if(!s.index.roles[i])return y({code:"NOT_FOUND",resource:"Role",id:i});const o=await r.update(i,n);return o?m({index:{roles:{[i]:{name:o.name,label:o.label,description:o.description,preferences:o.preferences.length}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update role ${i} in store.`})},"role:delete":async function(e,t){const{workspace:s,roles:r}=e,{name:i}=t;return s.index.roles[i]?await r.delete(i)?m({index:{roles:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete role ${i} from store.`}):y({code:"NOT_FOUND",resource:"Role",id:i})},"preference:add":async function(e,t){const{workspace:s,preferences:r}=e,i=t;return s.index.preferences[i.id]?y({code:"DUPLICATE_KEY",resource:"Preference",key:i.id}):(await r.add(i),m({index:{preferences:{[i.id]:{id:i.id,topics:i.topics,timestamp:i.timestamp,snippet:i.content.substring(0,100)}}}}))},"preference:update":async function(e,t){const{workspace:s,preferences:r}=e,{id:i,...n}=t;if(!s.index.preferences[i])return y({code:"NOT_FOUND",resource:"Preference",id:i});const o=await r.update(i,n);return o?m({index:{preferences:{[i]:{id:o.id,topics:o.topics,timestamp:o.timestamp,snippet:o.content.substring(0,100)}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update preference ${i} in store.`})},"preference:delete":async function(e,t){const{workspace:s,preferences:r}=e,{id:i}=t;return s.index.preferences[i]?await r.delete(i)?m({index:{preferences:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete preference ${i} from store.`}):y({code:"NOT_FOUND",resource:"Preference",id:i})},"context:add":async function(e,t){const{workspace:s,context:r}=e,i=t;return s.index.context[i.key]?y({code:"DUPLICATE_KEY",resource:"Context",key:i.key}):(await r.add(i),m({index:{context:{[i.key]:{key:i.key,topics:i.topics,timestamp:i.timestamp,mime:"blob"===i.content.kind?i.content.mediaType:void 0,size:"blob"===i.content.kind?i.content.sizeBytes:void 0,metadata:i.metadata}}}}))},"context:update":async function(e,t){const{workspace:s,context:r}=e,{key:i,...n}=t;if(!s.index.context[i])return y({code:"NOT_FOUND",resource:"Context",id:i});const o=await r.update(i,n);return o?m({index:{context:{[i]:{key:o.key,topics:o.topics,timestamp:o.timestamp,mime:"blob"===o.content.kind?o.content.mediaType:void 0,size:"blob"===o.content.kind?o.content.sizeBytes:void 0,metadata:o.metadata}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update context ${i} in store.`})},"context:delete":async function(e,t){const{workspace:s,context:r}=e,{key:i}=t;return s.index.context[i]?await r.delete(i)?m({index:{context:{[i]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete context ${i} from store.`}):y({code:"NOT_FOUND",resource:"Context",id:i})},"topic:add":async function(e,t){const{workspace:s,topics:r}=e,i=t;return s.index.topics[i.name]?y({code:"DUPLICATE_KEY",resource:"Topic",key:i.name}):(await r.add(i),m({index:{topics:{[i.name]:{topic:i.name,contextKeys:[],preferences:[],metadata:{created:i.created,updated:i.updated,entries:0}}}}}))},"topic:update":async function(e,t){const{workspace:s,topics:r}=e,{name:i,...n}=t;if(!s.index.topics[i])return y({code:"NOT_FOUND",resource:"Topic",id:i});const o=await r.update(i,n);return o?m({index:{topics:{[i]:{metadata:{updated:o.updated}}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update topic ${i} in store.`})},"topic:delete":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{name:o,cascade:a}=t;if(!s.index.topics[o])return y({code:"NOT_FOUND",resource:"Topic",id:o});if(r.referencedBy(o,s.index)&&!a)return y({code:"INVALID_COMMAND",reason:`Topic '${o}' is referenced by other entities. Use 'cascade: true' to force deletion.`});if(a){for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);t&&await i.update(e,{topics:t.topics.filter((e=>e!==o))})}}for(const e in s.index.sessions){const t=s.index.sessions[e];t.topics?.includes(o)&&await n.update(e,{topics:t.topics.filter((e=>e!==o))})}}return await r.delete(o)?m({index:{topics:{[o]:h}}}):y({code:"BACKEND_ERROR",reason:`Failed to delete topic ${o} from store.`})},"topic:merge":async function(e,t){const{workspace:s,topics:r,roles:i,sessions:n}=e,{source:o,target:a}=t;if(!s.index.topics[o]||!s.index.topics[a])return y({code:"NOT_FOUND",resource:"Topic",id:s.index.topics[o]?a:o});for(const e in s.index.roles){const t=s.index.roles[e];if(t.topics?.includes(o)){const t=await i.get(e);if(t){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await i.update(e,{topics:s})}}}for(const e in s.index.sessions){const t=s.index.sessions[e];if(t.topics?.includes(o)){const s=t.topics.filter((e=>e!==o));s.includes(a)||s.push(a),await n.update(e,{topics:s})}}return await r.delete(o),m({index:{topics:{[o]:h}}})},"session:create":async function(e,t){const{workspace:s,sessions:r}=e,i=t;return s.index.sessions[i.id]?y({code:"DUPLICATE_KEY",resource:"Session",key:i.id}):(await r.add(i),m({index:{sessions:{[i.id]:{id:i.id,label:i.label,role:i.role,topics:i.topics,preferences:i.preferences,metadata:i.metadata}}}}))},"session:update":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,...n}=t;if(!s.index.sessions[i])return y({code:"NOT_FOUND",resource:"Session",id:i});const o=await r.update(i,n);return o?m({index:{sessions:{[i]:{label:o.label,role:o.role,topics:o.topics,preferences:o.preferences,metadata:o.metadata,head:o.head}}}}):y({code:"BACKEND_ERROR",reason:`Failed to update session ${i} in store.`})},"session:fork":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,newSessionId:n,label:o}=t,a=s.index.sessions[i];if(!a)return y({code:"NOT_FOUND",resource:"Session",id:i});const c={...a,id:n,label:o||`Fork of ${a.label}`,role:t.role?t.role:a.role,topics:t.topics?t.topics:a.topics};return await r.add(c),m({index:{sessions:{[n]:{id:n,label:c.label,role:c.role,topics:c.topics,preferences:c.preferences,metadata:c.metadata,head:c.head}}}})},"session:delete":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i}=t;return s.index.sessions[i]?(await r.delete(i),m({index:{sessions:{[i]:h}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:role:switch":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,roleName:n}=t;return s.index.sessions[i]?(await r.update(i,{role:n}),m({index:{sessions:{[i]:{role:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"session:topics:add":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,topics:n}=t,o=s.index.sessions[i];if(!o)return y({code:"NOT_FOUND",resource:"Session",id:i});const a=Array.from(new Set([...o.topics,...n]));return await r.update(i,{topics:a}),m({index:{sessions:{[i]:{topics:a}}}})},"session:preferences:override":async function(e,t){const{workspace:s,sessions:r}=e,{sessionId:i,preferences:n}=t;return s.index.sessions[i]?(await r.update(i,{preferences:n}),m({index:{sessions:{[i]:{preferences:n}}}})):y({code:"NOT_FOUND",resource:"Session",id:i})},"turn:add":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:update":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.update(o,o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:edit":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newBlocks:a,newVersion:c,roleSnapshot:d}=t,u=s.index.sessions[n];if(!u)return y({code:"NOT_FOUND",resource:"Session",id:n});const l=u.head;let h={};if(l&&l.id===o){const e=await i.get({id:l.id,version:l.version,session:n});e&&(h={...e})}const p={...h,id:o,version:c,blocks:a,role:d??h.role,timestamp:(new Date).toISOString(),parent:h.parent,actor:h.actor||"assistant",session:n};if(await i.add(p),u.head?.id===o){const e={id:o,version:c};return await r.update(n,{head:e}),m({index:{sessions:{[n]:{head:e}}}})}return m({})},"turn:branch":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turn:o}=t;if(!s.index.sessions[n])return y({code:"NOT_FOUND",resource:"Session",id:n});await i.add(o);const a={id:o.id,version:o.version};return await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})},"turn:delete":async function(e,t){const{workspace:s,sessions:r,turns:i}=e,{sessionId:n,turnId:o,newHead:a}=t;return s.index.sessions[n]?(await i.delete({session:n,id:o,version:t.version}),a?(await r.update(n,{head:a}),m({index:{sessions:{[n]:{head:a}}}})):m({})):y({code:"NOT_FOUND",resource:"Session",id:n})},"blob:register":async function(e,t){const{blobs:s}=e,r=await s.register(t.data,t.mediaType,t.filename);if(!r.ok)return r;const i=await s.getRecord(r.value.sha256);return i?m({index:{blobs:{[i.sha256]:i}}}):y({code:"BACKEND_ERROR",reason:`Failed to retrieve registered blob record for ${r.value.sha256}`})},"blob:retain":async function(e,t){const{blobs:s}=e,r=await s.retain(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i}}})},"blob:release":async function(e,t){const{blobs:s}=e,r=await s.release(t.sha256);if(!r.ok)return r;const i=await s.getRecord(t.sha256);return m({index:{blobs:{[t.sha256]:i||h}}})},"blob:purge":async function(e,t){const{blobs:s}=e,r=await s.purge(t.sha256);return r.ok?m({index:{blobs:{[t.sha256]:h}}}):r},"blob:record_remote_id":async function(e,t){const{blobs:s}=e,{sha256:r,providerId:i,fileId:n,timestamp:o}=t,a=await s.recordRemoteId(r,i,n,o);if(!a.ok)return a;const c=await s.getRecord(r);return m({index:{blobs:{[r]:c}}})},"tool:call":async function(e,t){return m({})}},q="__system__",A=class{constructor(t,s,r){this._actor=t,this._turn=r?JSON.parse(JSON.stringify(r)):{id:e(),session:s,version:0,actor:this._actor,blocks:[],timestamp:(new Date).toISOString(),role:void 0}}_turn;addText(t){const s={id:e(),type:"text",text:t};return this._turn.blocks.push(s),this}addImage(t,s){const r={id:e(),type:"image",ref:t,altText:s};return this._turn.blocks.push(r),this}addDocument(t,s){const r={id:e(),type:"document",ref:t,title:s};return this._turn.blocks.push(r),this}addToolUse(t,s){const r={id:e(),type:"tool:use",name:t,input:s};return this._turn.blocks.push(r),this}addToolResult(t,s,r){const i={id:e(),type:"tool:result",useId:t,content:s,isError:r};return this._turn.blocks.push(i),this}addSummary(t){const s={id:e(),type:"summary",text:t};return this._turn.blocks.push(s),this}addRoleTransition(t,s){const r={id:e(),type:"role:transition",previousRole:t,newRole:s};return this._turn.blocks.push(r),this}addThinking(t){const s={id:e(),type:"thinking",thinking:t};return this._turn.blocks.push(s),this}addBlock(e){return this._turn.blocks.push(e),this}deleteBlock(e){return this._turn.blocks=this._turn.blocks.filter((t=>t.id!==e)),this}editTextBlock(e,t){const s=this._turn.blocks.findIndex((t=>t.id===e));if(-1===s)throw new Error(`Block with ID ${e} not found.`);const r=this._turn.blocks[s];if("text"!==r.type)throw new Error(`Block with ID ${e} is not a TextBlock.`);return this._turn.blocks[s]={...r,text:t},this}withId(e){return this._turn.id=e,this}withVersion(e){return this._turn.version=e,this}withTimestamp(e){return this._turn.timestamp=e,this}withParent(e){return this._turn.parent=e,this}withRoleSnapshot(e){return this._turn.role=e,this}build(){return JSON.parse(JSON.stringify(this._turn))}},U=class{constructor(e,t){this.turnStore=e,this.sessionStore=t}async loadAllTurns(e){return this.turnStore.listBySession(e)}async loadHead(e){const t=await this.sessionStore.get(e);return t?.head??null}},C=class e{constructor(e,t){this.nodes=e,this._head=t}static async build(t,s){const[r,i]=await Promise.all([s.loadAllTurns(t),s.loadHead(t)]),n=function(e,t){const s=function(e,t){if(!t)return new Set;const s=new Map;for(const t of e)s.set(`${t.id}:${t.version}`,t);const r=new Set;let i=t;for(;i;){const e=`${i.id}:${i.version}`;if(r.has(e))break;r.add(e);const t=s.get(e);if(!t)break;i=t.parent}return r}(e,t),r={},i={};for(const t of e){r[t.id]||(r[t.id]={id:t.id,versions:{},activeVersion:t.version,actor:t.actor,blocks:t.blocks,timestamp:t.timestamp,roleSnapshot:t.role,parent:t.parent,children:{}},i[t.id]=new Set);const e=r[t.id];e.versions[t.version]=t;const n=s.has(`${t.id}:${t.version}`),o=s.has(`${t.id}:${e.activeVersion}`);if(n&&(!o||t.version>=e.activeVersion)&&(e.activeVersion=t.version,e.blocks=t.blocks,e.timestamp=t.timestamp,e.roleSnapshot=t.role,e.parent=t.parent),t.parent){const e=`${t.parent.id}:${t.parent.version}`;if(i[t.parent.id]||(i[t.parent.id]=new Set),!i[t.parent.id].has(e+":"+t.id)){i[t.parent.id].add(e+":"+t.id),r[t.parent.id]||(r[t.parent.id]={id:t.parent.id,versions:{},activeVersion:t.parent.version,actor:"user",blocks:[],timestamp:"",roleSnapshot:void 0,children:{}});const s=r[t.parent.id];s.children[t.parent.version]||(s.children[t.parent.version]=[]),s.children[t.parent.version].push(t.id)}}}return r}(r,i);return new e(n,i)}head(){return this._head}chain(){if(!this._head)return[];const e=[];let t=this._head.id;for(;t;){const s=this.nodes[t];if(!s)break;e.push(s),t=s.parent?.id??null}return e.reverse()}getTurnSiblings(e){const t=this.nodes[e];if(!t)return[];if(!t.parent)return Object.values(this.nodes).filter((e=>!e.parent));const s=this.nodes[t.parent.id];if(!s)return[t];const r=s.children[t.parent.version];return r?r.map((e=>this.nodes[e])).filter((e=>!!e)):[t]}branchInfo(e){const t=this.nodes[e];if(!t)return{versions:[],currentIndex:-1,total:0,hasPrev:!1,hasNext:!1};const s=Object.keys(t.versions).map(Number).sort(((e,t)=>e-t)),r=s.indexOf(t.activeVersion);return{versions:s,currentIndex:r,total:s.length,hasPrev:r>0,hasNext:r<s.length-1}}graph(){return{...this.nodes}}};var B=class{constructor(e){this.manager=e}get workspace(){return this.manager.workspace()}roles(){return this.manager.ctx().roles.list()}role(e){return this.manager.ctx().roles.get(e)}async createRole(e,t,s,r,i=[]){if(this.workspace.index.roles[e])return y({code:"DUPLICATE_KEY",resource:"role",key:e});const n={name:e,label:t,description:r,persona:s,preferences:i,topics:[]};return this.manager.dispatch({type:"role:add",payload:n,timestamp:(new Date).toISOString()})}async updateRole(e,t){return this.workspace.index.roles[e]?this.manager.dispatch({type:"role:update",payload:{name:e,...t},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"role",id:e})}async deleteRole(e){const t=this.workspace;if(!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});return Object.values(t.index.sessions).some((t=>t.role===e))?y({code:"INVALID_COMMAND",reason:`Cannot delete role "${e}" — it is still referenced by one or more sessions`}):this.manager.dispatch({type:"role:delete",payload:{name:e},timestamp:(new Date).toISOString()})}async addPreference(e,t){const s={id:crypto.randomUUID(),content:e,topics:t,timestamp:(new Date).toISOString()};return this.manager.dispatch({type:"preference:add",payload:s,timestamp:s.timestamp})}preferences(){return this.manager.ctx().preferences.list()}async addContext(e,t,s,r){const i={key:e,topics:s,content:t,timestamp:(new Date).toISOString(),metadata:r};return this.manager.dispatch({type:"context:add",payload:i,timestamp:i.timestamp})}context(){return this.manager.ctx().context.list()}async registerBlob(e,t,s){const r=await this.manager.dispatch({type:"blob:register",payload:{data:e,mediaType:t,filename:s},timestamp:(new Date).toISOString()});if(!r.ok)return y(r.error);const i=r.value,n=i?.index?.blobs;if(!n)return y({code:"BACKEND_ERROR",reason:"Blob registration succeeded but no blobs patch returned"});const o=Object.keys(n)[0];if(!o)return y({code:"BACKEND_ERROR",reason:"No SHA256 in patch"});const a=n[o];if(!a)return y({code:"BACKEND_ERROR",reason:"Blob record missing"});return f({sha256:o,ref:{sha256:o,mediaType:a.mediaType,sizeBytes:a.sizeBytes,filename:a.filename,previewUrl:a.previewUrl}})}},$=class e{constructor(e,t,s,r){this._id=e,this.manager=t,this.processor=s,this.turnRepository=r,this.workspace=new B(t)}workspace;_role=void 0;_preferences=[];tree;static async create(t,s,r){s.ctx().workspace;const i=new U(s.ctx().turns,s.ctx().sessions),n=new e(t,s,r,i);return await n._setRole(),await n._setPreference(),await n.refreshTurnTree(),n}async _setRole(){const e=this.meta(),t=await this.manager.ctx().roles.get(e.role);t&&(this._role=t)}async _setPreference(){const e=this.meta();this._preferences=await this.manager.ctx().preferences.load(e.preferences)}id(){return this._id}ws(){return this.manager.workspace()}meta(){return this.ws().index.sessions[this._id]}label(){return this.meta()?.label}role(){return this._role}topics(){return this.meta()?.topics??[]}preferences(){return this._preferences}head(){return this.meta()?.head??null}turns(){return this.tree.chain()}async siblings(e){return this.tree.getTurnSiblings(e)}async branchInfo(e){return this.tree.branchInfo(e)}async getTurn(e){return this.tree.graph()[e]}async rename(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,label:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setTopics(e){return this.meta()?this.dispatch({type:"session:update",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async addTopics(e){return this.meta()?this.dispatch({type:"session:topics:add",payload:{sessionId:this._id,topics:e},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async setPreferences(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t=await this.dispatch({type:"session:preferences:override",payload:{sessionId:this._id,preferences:e},timestamp:(new Date).toISOString()});return t.ok&&await this._setPreference(),t}async fork(e,t,s,r){return this.meta()?this.dispatch({type:"session:fork",payload:{sessionId:this._id,newSessionId:e,label:t,role:s,topics:r},timestamp:(new Date).toISOString()}):y({code:"NOT_FOUND",resource:"session",id:this._id})}async dispatch(e){return this.manager.dispatch(e)}async switchRole(e){const t=this.ws();if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(e!==q&&!t.index.roles[e])return y({code:"NOT_FOUND",resource:"role",id:e});const s=await this.dispatch({type:"session:update",payload:{sessionId:this._id,role:e},timestamp:(new Date).toISOString()});return s.ok&&await this._setRole(),s}async addTurn(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const t={...e,session:this._id,version:e.version??0,parent:!e.parent&&this.head()?this.head():void 0},s=await this.dispatch({type:"turn:add",payload:{sessionId:this._id,turn:t},timestamp:t.timestamp});return s.ok&&await this.refreshTurnTree(),s}async recordUserTurn(e){return this.meta()?this.addTurn(e):y({code:"NOT_FOUND",resource:"session",id:this._id})}async recordAssistantTurn(e,t){const s=this.ws();if(!s)return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!s.index.sessions[this._id])return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.processor.process(e,this._id);let i={};const n=[];for(const e of r){const t=await this.manager.dispatch(e);if(t.ok)i=_(i,t.value);else{if("PERMISSION_DENIED"!==t.error.code||e.synthetic)return t;{const t=this.describeCommand(e);n.push({cmd:e,description:t})}}}const o=await this.addTurn(e);if(!o.ok)return o;if(i=_(i,o.value),t&&n.length>0){const e=this.buildDenialTurn(n),t=await this.addTurn(e);t.ok&&(i=_(i,t.value))}return f(i)}buildDenialTurn(e){const t=new A("user",this._id);for(const s of e)t.addText(`[System] User denied: ${s.description}.`);return t.build()}describeCommand(e){return"tool:call"===e.type?`tool execution: ${e.payload.tool}`:`command: ${e.type}`}async editTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph()[e];if(!r)return y({code:"NOT_FOUND",resource:"turn",id:e});const i=r.versions[r.activeVersion],n=r.activeVersion+1,o=await this.dispatch({type:"turn:edit",payload:{sessionId:this._id,turnId:e,newBlocks:t,roleSnapshot:s??i.role,newVersion:n},timestamp:(new Date).toISOString()});return o.ok&&(await this.dispatch({type:"session:update",payload:{sessionId:this._id,head:{id:e,version:n}},timestamp:(new Date).toISOString()}),await this.refreshTurnTree()),o}async branch(e){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});if(!e.parent)return y({code:"INVALID_COMMAND",reason:"branch requires turn.parent to be set"});const t=await this.dispatch({type:"turn:branch",payload:{sessionId:this._id,turn:{...e,session:this._id}},timestamp:e.timestamp});return t.ok&&await this.refreshTurnTree(),t}async deleteTurn(e,t,s){if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const r=this.tree.graph();if(!r[e]?.versions[t])return y({code:"NOT_FOUND",resource:"turn version",id:`${e}:${t}`});const i=await this.dispatch({type:"turn:delete",payload:{sessionId:this._id,turnId:e,version:t,newHead:s},timestamp:(new Date).toISOString()});return i.ok&&await this.refreshTurnTree(),i}async switchVersionLeft(e){return this.switchVersion(e,-1)}async switchVersionRight(e){return this.switchVersion(e,1)}async switchVersion(e,t){if(!this.ws())return y({code:"NOT_FOUND",resource:"workspace",id:"current"});if(!this.meta())return y({code:"NOT_FOUND",resource:"session",id:this._id});const s=this.tree.graph()[e];if(!s)return y({code:"NOT_FOUND",resource:"turn",id:e});const r=Object.keys(s.versions).map(Number).sort(((e,t)=>e-t)),i=r.indexOf(s.activeVersion);if(-1===i)return y({code:"INVALID_COMMAND",reason:"Active version not found"});const n=i+t;if(n<0||n>=r.length)return y({code:"INVALID_COMMAND",reason:`No ${t<0?"previous":"next"} version available for turn ${e}`});const o=r[n],a=this.findSubtreeTip(this.tree.graph(),e,o),c=await this.dispatch({type:"session:update",payload:{sessionId:this._id,head:a},timestamp:(new Date).toISOString()});return c.ok&&await this.refreshTurnTree(),c}async snapshot(){const e=this,t=e.meta();if(!t)return;const s=e.ws(),r=e._role;if(!r)return;const i=await e.manager.ctx().context.getByTopics(s.index,t.topics),n=Array.from(new Set([...r.preferences,...t.preferences])),o=n.length>0?await e.manager.ctx().preferences.load(n):e._preferences,a=e.tree.chain().map((e=>e.versions[e.activeVersion])).filter((e=>!!e)),c=[...a].reverse().find((e=>"user"===e.actor));return{id:e._id,meta:t,role:r,preferences:o,context:i,model:t.metadata?.model,transcript:a,topics:t.topics,instructions:s.settings?.prompt,constraints:{role:r.constraints,session:t.constraints,turn:c?.constraints}}}async refreshTurnTree(){this.tree=await C.build(this._id,this.turnRepository)}findSubtreeTip(e,t,s){let r=t,i=s;for(;;){const t=e[r];if(!t)break;const s=t.children[i];if(!s||0===s.length)break;const n=s[0],o=e[n];if(!o)break;r=n,i=o.activeVersion}return{id:r,version:i}}},M=class{constructor(e,t){this.manager=e,this.processor=t}openOnce=new Map;async open(e){let t=this.openOnce.get(e);t||(t=new o,this.openOnce.set(e,t));const s=await t.do((async()=>{if(!this.manager.workspace().index.sessions[e])throw new Error(`Session ${e} not found in workspace index`);return $.create(e,this.manager,this.processor)}));if(s.error)throw s.error;return s.value}close(e){this.openOnce.delete(e)}async delete(e){const t=await this.manager.dispatch({type:"session:delete",payload:{sessionId:e},timestamp:(new Date).toISOString()});if(t.ok)return this.close(e),t.value=void 0,t;throw t.error}async create(t){const s=e(),r=await this.manager.dispatch({type:"session:create",payload:{...t,id:s},timestamp:(new Date).toISOString()});if(r.ok)return this.open(s);throw r.error}list(){return Object.values(this.manager.workspace().index.sessions)}metadata(e){return this.manager.workspace().index.sessions[e]}},j=class{constructor(e,t,s){this.storage=e,this.cache=t,this.bus=s}async register(e,t,s){const r=await b(e),i=await this.getRecord(r);if(i){const e={...i,refCount:i.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(e),this.cache.set(r,e),f(this.reference(e))}const n={sha256:r,mediaType:t,sizeBytes:e.byteLength,filename:s,refCount:1,remoteIds:{},createdAt:(new Date).toISOString(),lastUsedAt:(new Date).toISOString()};return this.storage.registerBlob?await this.storage.registerBlob(n,e):(await this.storage.storeBytes(r,e),await this.storage.saveRecord(n)),this.cache.set(r,n),this.bus.emit({name:"blobs:changed",payload:{sha256:r,record:n}}),f(this.reference(n))}async retain(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s={...t,refCount:t.refCount+1,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(s),this.cache.set(e,s),f(void 0)}async release(e){const t=await this.getRecord(e);if(!t)return y({code:"NOT_FOUND",resource:"blob",id:e});const s=Math.max(0,t.refCount-1),r={...t,refCount:s,lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(r),this.cache.set(e,r),f(void 0)}async purge(e){return await this.storage.deleteBytes(e),await this.storage.deleteRecord(e),this.cache.delete(e),this.bus.emit({name:"blobs:changed",payload:{sha256:e}}),f(void 0)}async recordRemoteId(e,t,s,r){const i=await this.getRecord(e);if(!i)return y({code:"NOT_FOUND",resource:"blob",id:e});const n={...i,remoteIds:{...i.remoteIds,[t]:{id:s,timestamp:r||(new Date).toISOString()}},lastUsedAt:(new Date).toISOString()};return await this.storage.saveRecord(n),this.cache.set(e,n),this.bus.emit({name:"blobs:changed",payload:{sha256:e,record:n}}),f(void 0)}async getRecord(e){const t=this.cache.get(e);if(t)return t;const s=await this.storage.loadRecord(e);return s&&this.cache.set(e,s),s}async getAllRecords(){const e=await this.storage.listRecords(),t={};for(const s of e)t[s.sha256]=s,this.cache.set(s.sha256,s);return t}reference(e){return{sha256:e.sha256,mediaType:e.mediaType,sizeBytes:e.sizeBytes,filename:e.filename}}async resolve(e,t){const s=await this.getRecord(e.sha256);if(!s)return f(null);if(t){const e=s.remoteIds[t];if(e)return f({kind:"remote",sha256:s.sha256,mediaType:s.mediaType,fileId:e.id,providerId:t,timestamp:e.timestamp});const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}const r=await this.storage.loadBytes(s.sha256);return f(r?{kind:"inline",sha256:s.sha256,mediaType:s.mediaType,data:r}:null)}async resolveMany(e,t){const s=new Map;for(const r of e){const e=await this.resolve(r,t);if(!e.ok)return y(e.error);if(null===e.value)return y({code:"BLOB_ERROR",reason:`Unable to resolve blob ${r.sha256}${t?` with adapter ${t}`:""}`});s.set(r.sha256,e.value)}return f(s)}},P=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.key,e)}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}async update(e,t){const s=await this.collection.find({field:"key",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"key",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async getByTopics(e,t){const s=new Set;for(const r of t){const t=e.topics[r];t&&t.contextKeys.forEach((e=>s.add(e)))}if(0===s.size)return[];const r=[],i=[];for(const e of s){const t=this.cache.get(e);t?i.push(t):r.push(e)}if(r.length>0){const e=await this.collection.filter({operator:"or",conditions:r.map((e=>({field:"key",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.key,e),i.push(e)}}return i.sort(((e,t)=>new Date(t.timestamp).getTime()-new Date(e.timestamp).getTime()))}},V=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async load(e){if(0===e.length)return[];const t=[],s=[];for(const r of e){const e=this.cache.get(r);e?s.push(e):t.push(r)}if(t.length>0){const e=await this.collection.filter({operator:"or",conditions:t.map((e=>({field:"id",operator:"eq",value:e})))});for(const t of e){const e=t.state();this.cache.set(e.id,e),s.push(e)}}return s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},z=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.name,e)}async update(e,t){const s=await this.collection.find({field:"name",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"name",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}async list(){const e=await this.collection.list({limit:1e3,type:"cursor",direction:"forward"});return((await e.next()).value||[]).map((e=>e.state()))}},K=class{constructor(e,t){this.collection=e,this.cache=t}async get(e){const t=this.cache.get(e);if(t)return t;const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;const r=s.state();return this.cache.set(e,r),r}async add(e){await this.collection.create(e),this.cache.set(e.id,e)}async update(e,t){const s=await this.collection.find({field:"id",operator:"eq",value:e});if(!s)return null;await s.update(t);const r=s.state();return this.cache.set(e,r),r}async delete(e){const t=await this.collection.find({field:"id",operator:"eq",value:e});if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(e),s}},L=class{constructor(e,t){this.collection=e,this.cache=t}key({id:e,session:t,version:s}){return`${t}:${s}:${e}`}async find({id:e,session:t,version:s},r=!0){const i=this.key({id:e,session:t,version:s});this.cache.get(i)&&this.cache.get(i);const n=await this.collection.find({operator:"and",conditions:[{field:"id",operator:"eq",value:e},{field:"session",operator:"eq",value:t},{field:"version",operator:"eq",value:s}]});return n?(r&&this.cache.set(i,n),n):null}async get(e){return this.find(e)}async add(e){const t=await this.collection.create(e);this.cache.set(this.key(e),t)}async update(e,t){const s=await this.find(e);return s?(await s.update(t),s.state()):null}async listBySession(e){return(await this.collection.filter({field:"session",operator:"eq",value:e})).map((e=>e.state()))}async delete(e){const t=await this.find(e,!1);if(!t)return!1;const s=await t.delete();return s&&this.cache.delete(this.key(e)),s}},W=class{cache;maxSize;constructor(e){this.cache=new Map,this.maxSize=e}get(e){const t=this.cache.get(e);return void 0!==t&&(this.cache.delete(e),this.cache.set(e,t)),t}set(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){const e=this.cache.keys().next().value;void 0!==e&&this.cache.delete(e)}this.cache.set(e,t)}has(e){return this.cache.has(e)}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}};async function H(e){const{blobStorage:t,eventBus:s=c(),getWorkspace:r,setWorkspace:i,processor:n,guard:o,toolRegistry:a,extensionReducers:d={},extensionMiddleware:h=[],extensionStores:p}=e,f=u(e.db);await f.open(e.extensionSchemas);const m={role:await f.collection(l.ROLE),preference:await f.collection(l.PREFERENCE),context:await f.collection(l.CONTEXT),session:await f.collection(l.SESSION),topic:await f.collection(l.TOPIC),turn:await f.collection(l.TURN)},y=new j(t,new W(200),s),w={roles:new z(m.role,new W(100)),preferences:new V(m.preference,new W(500)),context:new P(m.context,new W(500)),topics:new T(m.topic,new W(100)),sessions:new K(m.session,new W(50)),turns:new L(m.turn,new W(50)),blobs:y,tools:a,db:f};if(p){const e=p(w);Object.assign(w,e)}const g=new O({ctx:w,getWorkspace:r,updateWorkspace:i,guard:o,bus:s});Object.entries(F).forEach((([e,t])=>{g.register(e,t)})),Object.entries(d).forEach((([e,t])=>{g.register(e,t)})),g.use(E),h.forEach((e=>{g.use(e)}));const _=new M(g,n);return{manager:g,sessions:_,ctx:w}}export{l as COLLECTIONS,q as EMPTY_SYSTEM_ROLE,W as LRUCache,$ as Session,M as SessionManager,A as TurnBuilder,C as TurnTree,O as WorkspaceManager,v as bufferToBase64,b as computeSHA256,H as createWorkspace,u as createWorkspaceDatabase,g as del,y as error,x as getExtension,_ as merge,m as ok,w as omitNullUndefined,k as shortHash,f as success};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/utils-workspace",
3
- "version": "5.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "Content-addressed workspace and conversation management for AI applications.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",