@rool-dev/extension 0.3.7 → 0.3.8-dev.b3f8671
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/README.md +13 -1
- package/dist/dev/DevHostController.d.ts +1 -0
- package/dist/dev/DevHostController.d.ts.map +1 -1
- package/dist/dev/DevHostController.js +5 -1
- package/dist/dev/HostShell.svelte +8 -8
- package/dist/dev/HostShell.svelte.d.ts +1 -8
- package/dist/dev/HostShell.svelte.d.ts.map +1 -1
- package/dist/dev/host-shell.js +182 -68
- package/dist/dev/host-shell.js.map +1 -1
- package/dist/host.d.ts +4 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +17 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/protocol.d.ts +7 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/reactive.svelte.d.ts +67 -37
- package/dist/reactive.svelte.d.ts.map +1 -1
- package/dist/reactive.svelte.js +374 -103
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/client.d.ts +0 -139
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -360
package/README.md
CHANGED
|
@@ -183,6 +183,7 @@ These are Svelte 5 `$state` properties — use them directly in templates or `$e
|
|
|
183
183
|
| `role` | `RoolUserRole` | User's role (`owner`, `admin`, `editor`, `viewer`) |
|
|
184
184
|
| `linkAccess` | `LinkAccess` | URL sharing level |
|
|
185
185
|
| `userId` | `string` | Current user's ID |
|
|
186
|
+
| `user` | `BridgeUser` | Current user info (`{ id, name, email }`) |
|
|
186
187
|
| `isReadOnly` | `boolean` | True if viewer role |
|
|
187
188
|
|
|
188
189
|
### Object Operations
|
|
@@ -409,10 +410,20 @@ Extensions run in a sandboxed iframe (`allow-scripts allow-same-origin`). The ho
|
|
|
409
410
|
|
|
410
411
|
The bridge protocol:
|
|
411
412
|
1. Extension sends `rool:ready`
|
|
412
|
-
2. Host responds with `rool:init` (channel metadata, schema, space info)
|
|
413
|
+
2. Host responds with `rool:init` (channel metadata, schema, space info, user identity)
|
|
413
414
|
3. Extension calls channel methods → `rool:request` → host executes → `rool:response`
|
|
414
415
|
4. Host pushes real-time events → `rool:event` → extension updates reactive state
|
|
415
416
|
|
|
417
|
+
When creating a bridge host, pass `user` so the extension can display the current user's name:
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
const host = createBridgeHost({
|
|
421
|
+
channel,
|
|
422
|
+
iframe,
|
|
423
|
+
user: { id: currentUser.id, name: currentUser.name, email: currentUser.email },
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
416
427
|
## CLI Commands
|
|
417
428
|
|
|
418
429
|
| Command | Description |
|
|
@@ -431,6 +442,7 @@ import type {
|
|
|
431
442
|
ReactiveObject,
|
|
432
443
|
ReactiveWatch,
|
|
433
444
|
WatchOptions,
|
|
445
|
+
BridgeUser,
|
|
434
446
|
RoolObject,
|
|
435
447
|
RoolObjectStat,
|
|
436
448
|
SpaceSchema,
|
|
@@ -71,6 +71,7 @@ export declare class DevHostController {
|
|
|
71
71
|
registerIframe(tabId: string, el: HTMLIFrameElement): void;
|
|
72
72
|
unregisterIframe(tabId: string): void;
|
|
73
73
|
logout(): void;
|
|
74
|
+
private get _bridgeUser();
|
|
74
75
|
private _bindBridge;
|
|
75
76
|
private _bindAllBridges;
|
|
76
77
|
private _destroyTab;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevHostController.d.ts","sourceRoot":"","sources":["../../src/dev/DevHostController.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAe,sBAAsB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"DevHostController.d.ts","sourceRoot":"","sources":["../../src/dev/DevHostController.ts"],"names":[],"mappings":"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"}
|
|
@@ -358,11 +358,15 @@ export class DevHostController {
|
|
|
358
358
|
// ---------------------------------------------------------------------------
|
|
359
359
|
// Private helpers
|
|
360
360
|
// ---------------------------------------------------------------------------
|
|
361
|
+
get _bridgeUser() {
|
|
362
|
+
const cu = this.client.currentUser; // Always available after boot() authenticates
|
|
363
|
+
return { id: cu.id, name: cu.name, email: cu.email };
|
|
364
|
+
}
|
|
361
365
|
_bindBridge(tabId) {
|
|
362
366
|
const el = this.iframeEls[tabId];
|
|
363
367
|
const ch = this.channels[tabId];
|
|
364
368
|
if (el && ch && !this.bridgeHosts[tabId]) {
|
|
365
|
-
this.bridgeHosts[tabId] = createBridgeHost({ channel: ch, iframe: el });
|
|
369
|
+
this.bridgeHosts[tabId] = createBridgeHost({ channel: ch, iframe: el, user: this._bridgeUser });
|
|
366
370
|
}
|
|
367
371
|
}
|
|
368
372
|
_bindAllBridges() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { onMount, tick } from 'svelte';
|
|
2
|
+
import { getContext, onMount, tick } from 'svelte';
|
|
3
3
|
import { DevHostController } from './DevHostController.js';
|
|
4
4
|
import type { ExtensionTab } from './DevHostController.js';
|
|
5
5
|
import type { Manifest } from '../manifest.js';
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
import Sidebar from './Sidebar.svelte';
|
|
9
9
|
import AppGrid from './AppGrid.svelte';
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
interface
|
|
11
|
+
// Static config injected via mount() context — not reactive, never changes
|
|
12
|
+
interface HostConfig {
|
|
13
13
|
channelId: string;
|
|
14
14
|
extensionUrl: string;
|
|
15
15
|
manifest: Manifest | null;
|
|
16
16
|
manifestError: string | null;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const { channelId, extensionUrl, manifest, manifestError } = getContext<HostConfig>('hostConfig');
|
|
20
20
|
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
// Controller + reactive state mirror
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
let dropdownOpen: boolean = $state(false);
|
|
41
41
|
|
|
42
42
|
const controller = new DevHostController(
|
|
43
|
-
|
|
43
|
+
{ channelId, extensionUrl, manifest, manifestError },
|
|
44
44
|
syncState,
|
|
45
45
|
tick,
|
|
46
46
|
);
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
|
|
64
64
|
// Derived: published apps not yet installed (excluding the local dev app)
|
|
65
65
|
let uninstalledExtensions = $derived(
|
|
66
|
-
publishedExtensions.filter((ext) => ext.extensionId !==
|
|
66
|
+
publishedExtensions.filter((ext) => ext.extensionId !== channelId && !installedExtensionIds.includes(ext.extensionId)),
|
|
67
67
|
);
|
|
68
68
|
|
|
69
69
|
// Initial sync
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
<!-- Sidebar -->
|
|
90
90
|
<Sidebar
|
|
91
91
|
{controller}
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
{manifest}
|
|
93
|
+
{manifestError}
|
|
94
94
|
{spaces}
|
|
95
95
|
{currentSpaceId}
|
|
96
96
|
{env}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
interface Props {
|
|
3
|
-
channelId: string;
|
|
4
|
-
extensionUrl: string;
|
|
5
|
-
manifest: Manifest | null;
|
|
6
|
-
manifestError: string | null;
|
|
7
|
-
}
|
|
8
|
-
declare const HostShell: import("svelte").Component<Props, {}, "">;
|
|
1
|
+
declare const HostShell: import("svelte").Component<Record<string, never>, {}, "">;
|
|
9
2
|
type HostShell = ReturnType<typeof HostShell>;
|
|
10
3
|
export default HostShell;
|
|
11
4
|
//# sourceMappingURL=HostShell.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HostShell.svelte.d.ts","sourceRoot":"","sources":["../../src/dev/HostShell.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HostShell.svelte.d.ts","sourceRoot":"","sources":["../../src/dev/HostShell.svelte.ts"],"names":[],"mappings":"AAkHA,QAAA,MAAM,SAAS,2DAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
package/dist/dev/host-shell.js
CHANGED
|
@@ -313,6 +313,19 @@ function set_component_context(context) {
|
|
|
313
313
|
component_context = context;
|
|
314
314
|
}
|
|
315
315
|
/**
|
|
316
|
+
* Retrieves the context that belongs to the closest parent component with the specified `key`.
|
|
317
|
+
* Must be called during component initialisation.
|
|
318
|
+
*
|
|
319
|
+
* [`createContext`](https://svelte.dev/docs/svelte/svelte#createContext) is a type-safe alternative.
|
|
320
|
+
*
|
|
321
|
+
* @template T
|
|
322
|
+
* @param {any} key
|
|
323
|
+
* @returns {T}
|
|
324
|
+
*/
|
|
325
|
+
function getContext(key) {
|
|
326
|
+
return get_or_init_context_map("getContext").get(key);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
316
329
|
* @param {Record<string, unknown>} props
|
|
317
330
|
* @param {any} runes
|
|
318
331
|
* @param {Function} [fn]
|
|
@@ -355,6 +368,27 @@ function pop(component) {
|
|
|
355
368
|
function is_runes() {
|
|
356
369
|
return !legacy_mode_flag || component_context !== null && component_context.l === null;
|
|
357
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* @param {string} name
|
|
373
|
+
* @returns {Map<unknown, unknown>}
|
|
374
|
+
*/
|
|
375
|
+
function get_or_init_context_map(name) {
|
|
376
|
+
if (component_context === null) lifecycle_outside_component(name);
|
|
377
|
+
return component_context.c ??= new Map(get_parent_context(component_context) || void 0);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* @param {ComponentContext} component_context
|
|
381
|
+
* @returns {Map<unknown, unknown> | null}
|
|
382
|
+
*/
|
|
383
|
+
function get_parent_context(component_context) {
|
|
384
|
+
let parent = component_context.p;
|
|
385
|
+
while (parent !== null) {
|
|
386
|
+
const context_map = parent.c;
|
|
387
|
+
if (context_map !== null) return context_map;
|
|
388
|
+
parent = parent.p;
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
358
392
|
//#endregion
|
|
359
393
|
//#region ../../node_modules/.pnpm/svelte@5.54.0/node_modules/svelte/src/internal/client/dom/task.js
|
|
360
394
|
/** @type {Array<() => void>} */
|
|
@@ -4119,48 +4153,6 @@ function bind_this(element_or_component = {}, update, get_value, get_parts) {
|
|
|
4119
4153
|
//#region ../../node_modules/.pnpm/svelte@5.54.0/node_modules/svelte/src/internal/client/reactivity/props.js
|
|
4120
4154
|
/** @import { Effect, Source } from './types.js' */
|
|
4121
4155
|
/**
|
|
4122
|
-
* The proxy handler for rest props (i.e. `const { x, ...rest } = $props()`).
|
|
4123
|
-
* Is passed the full `$$props` object and excludes the named props.
|
|
4124
|
-
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, name?: string }>}}
|
|
4125
|
-
*/
|
|
4126
|
-
var rest_props_handler = {
|
|
4127
|
-
get(target, key) {
|
|
4128
|
-
if (target.exclude.includes(key)) return;
|
|
4129
|
-
return target.props[key];
|
|
4130
|
-
},
|
|
4131
|
-
set(target, key) {
|
|
4132
|
-
return false;
|
|
4133
|
-
},
|
|
4134
|
-
getOwnPropertyDescriptor(target, key) {
|
|
4135
|
-
if (target.exclude.includes(key)) return;
|
|
4136
|
-
if (key in target.props) return {
|
|
4137
|
-
enumerable: true,
|
|
4138
|
-
configurable: true,
|
|
4139
|
-
value: target.props[key]
|
|
4140
|
-
};
|
|
4141
|
-
},
|
|
4142
|
-
has(target, key) {
|
|
4143
|
-
if (target.exclude.includes(key)) return false;
|
|
4144
|
-
return key in target.props;
|
|
4145
|
-
},
|
|
4146
|
-
ownKeys(target) {
|
|
4147
|
-
return Reflect.ownKeys(target.props).filter((key) => !target.exclude.includes(key));
|
|
4148
|
-
}
|
|
4149
|
-
};
|
|
4150
|
-
/**
|
|
4151
|
-
* @param {Record<string, unknown>} props
|
|
4152
|
-
* @param {string[]} exclude
|
|
4153
|
-
* @param {string} [name]
|
|
4154
|
-
* @returns {Record<string, unknown>}
|
|
4155
|
-
*/
|
|
4156
|
-
/* @__NO_SIDE_EFFECTS__ */
|
|
4157
|
-
function rest_props(props, exclude, name) {
|
|
4158
|
-
return new Proxy({
|
|
4159
|
-
props,
|
|
4160
|
-
exclude
|
|
4161
|
-
}, rest_props_handler);
|
|
4162
|
-
}
|
|
4163
|
-
/**
|
|
4164
4156
|
* This function is responsible for synchronizing a possibly bound prop with the inner component state.
|
|
4165
4157
|
* It is used whenever the compiler sees that the component writes to the prop, or when it has a default prop_value.
|
|
4166
4158
|
* @template V
|
|
@@ -5638,8 +5630,8 @@ var GraphQLClient = class {
|
|
|
5638
5630
|
}
|
|
5639
5631
|
async prompt(spaceId, prompt, channelId, conversationId, options) {
|
|
5640
5632
|
return (await this.request(`
|
|
5641
|
-
mutation Prompt($spaceId: String!, $prompt: String!, $objectIds: [String!], $responseSchema: JSON, $channelId: String!, $conversationId: String!, $effort: PromptEffort, $ephemeral: Boolean, $readOnly: Boolean, $attachments: [String!], $interactionId: String
|
|
5642
|
-
prompt(spaceId: $spaceId, prompt: $prompt, objectIds: $objectIds, responseSchema: $responseSchema, channelId: $channelId, conversationId: $conversationId, effort: $effort, ephemeral: $ephemeral, readOnly: $readOnly, attachments: $attachments, interactionId: $interactionId) {
|
|
5633
|
+
mutation Prompt($spaceId: String!, $prompt: String!, $objectIds: [String!], $responseSchema: JSON, $channelId: String!, $conversationId: String!, $effort: PromptEffort, $ephemeral: Boolean, $readOnly: Boolean, $attachments: [String!], $interactionId: String!, $parentInteractionId: String) {
|
|
5634
|
+
prompt(spaceId: $spaceId, prompt: $prompt, objectIds: $objectIds, responseSchema: $responseSchema, channelId: $channelId, conversationId: $conversationId, effort: $effort, ephemeral: $ephemeral, readOnly: $readOnly, attachments: $attachments, interactionId: $interactionId, parentInteractionId: $parentInteractionId) {
|
|
5643
5635
|
message
|
|
5644
5636
|
modifiedObjectIds
|
|
5645
5637
|
}
|
|
@@ -5655,7 +5647,8 @@ var GraphQLClient = class {
|
|
|
5655
5647
|
ephemeral: options.ephemeral,
|
|
5656
5648
|
readOnly: options.readOnly,
|
|
5657
5649
|
attachments: options.attachmentUrls,
|
|
5658
|
-
interactionId: options.interactionId
|
|
5650
|
+
interactionId: options.interactionId,
|
|
5651
|
+
parentInteractionId: options.parentInteractionId
|
|
5659
5652
|
})).prompt;
|
|
5660
5653
|
}
|
|
5661
5654
|
async getAccount() {
|
|
@@ -7220,6 +7213,29 @@ function generateEntityId() {
|
|
|
7220
7213
|
for (let i = 0; i < 6; i++) result += ID_CHARS[Math.floor(Math.random() * 62)];
|
|
7221
7214
|
return result;
|
|
7222
7215
|
}
|
|
7216
|
+
/** Walk from a leaf interaction up through parentId to root, return in root→leaf order. */
|
|
7217
|
+
function walkBranch(interactions, leafId) {
|
|
7218
|
+
const path = [];
|
|
7219
|
+
let currentId = leafId;
|
|
7220
|
+
while (currentId) {
|
|
7221
|
+
const ix = interactions[currentId];
|
|
7222
|
+
if (!ix) break;
|
|
7223
|
+
path.push(ix);
|
|
7224
|
+
currentId = ix.parentId;
|
|
7225
|
+
}
|
|
7226
|
+
return path.reverse();
|
|
7227
|
+
}
|
|
7228
|
+
/** Find the default leaf: the most recent interaction by timestamp that has no children. */
|
|
7229
|
+
function findDefaultLeaf(interactions) {
|
|
7230
|
+
if (!interactions || Array.isArray(interactions)) return void 0;
|
|
7231
|
+
const childSet = /* @__PURE__ */ new Set();
|
|
7232
|
+
for (const ix of Object.values(interactions)) if (ix.parentId) childSet.add(ix.parentId);
|
|
7233
|
+
let best;
|
|
7234
|
+
for (const ix of Object.values(interactions)) if (!childSet.has(ix.id)) {
|
|
7235
|
+
if (!best || ix.timestamp > best.timestamp) best = ix;
|
|
7236
|
+
}
|
|
7237
|
+
return best?.id;
|
|
7238
|
+
}
|
|
7223
7239
|
var OBJECT_COLLECT_TIMEOUT = 3e4;
|
|
7224
7240
|
/**
|
|
7225
7241
|
* A channel is a space + channelId pair.
|
|
@@ -7260,6 +7276,7 @@ var RoolChannel = class extends EventEmitter {
|
|
|
7260
7276
|
_objectIds;
|
|
7261
7277
|
_objectStats;
|
|
7262
7278
|
_hasConnected = false;
|
|
7279
|
+
_activeLeaves = /* @__PURE__ */ new Map();
|
|
7263
7280
|
_pendingMutations = /* @__PURE__ */ new Map();
|
|
7264
7281
|
_objectResolvers = /* @__PURE__ */ new Map();
|
|
7265
7282
|
_objectBuffer = /* @__PURE__ */ new Map();
|
|
@@ -7350,14 +7367,62 @@ var RoolChannel = class extends EventEmitter {
|
|
|
7350
7367
|
return this._channel?.extensionUrl ?? null;
|
|
7351
7368
|
}
|
|
7352
7369
|
/**
|
|
7353
|
-
* Get
|
|
7370
|
+
* Get the active branch of the current conversation as a flat array (root → leaf).
|
|
7371
|
+
* Walks from the active leaf up through parentId pointers.
|
|
7354
7372
|
*/
|
|
7355
7373
|
getInteractions() {
|
|
7356
7374
|
return this._getInteractionsImpl(this._conversationId);
|
|
7357
7375
|
}
|
|
7358
7376
|
/** @internal */
|
|
7359
7377
|
_getInteractionsImpl(conversationId) {
|
|
7360
|
-
|
|
7378
|
+
const interactions = this._channel?.conversations[conversationId]?.interactions;
|
|
7379
|
+
if (!interactions) return [];
|
|
7380
|
+
if (Array.isArray(interactions)) return interactions;
|
|
7381
|
+
const leafId = this._getActiveLeafImpl(conversationId);
|
|
7382
|
+
if (!leafId) return [];
|
|
7383
|
+
return walkBranch(interactions, leafId);
|
|
7384
|
+
}
|
|
7385
|
+
/**
|
|
7386
|
+
* Get the full interaction tree for a conversation as a record.
|
|
7387
|
+
* For clients that need to render branch navigation UI.
|
|
7388
|
+
*/
|
|
7389
|
+
getTree() {
|
|
7390
|
+
return this._getTreeImpl(this._conversationId);
|
|
7391
|
+
}
|
|
7392
|
+
/** @internal */
|
|
7393
|
+
_getTreeImpl(conversationId) {
|
|
7394
|
+
const interactions = this._channel?.conversations[conversationId]?.interactions;
|
|
7395
|
+
if (!interactions || Array.isArray(interactions)) return {};
|
|
7396
|
+
return interactions;
|
|
7397
|
+
}
|
|
7398
|
+
/**
|
|
7399
|
+
* Get the active leaf interaction ID for a conversation.
|
|
7400
|
+
* Returns undefined if the conversation has no interactions.
|
|
7401
|
+
*/
|
|
7402
|
+
get activeLeafId() {
|
|
7403
|
+
return this._getActiveLeafImpl(this._conversationId);
|
|
7404
|
+
}
|
|
7405
|
+
/** @internal */
|
|
7406
|
+
_getActiveLeafImpl(conversationId) {
|
|
7407
|
+
return this._activeLeaves.get(conversationId) ?? findDefaultLeaf(this._channel?.conversations[conversationId]?.interactions);
|
|
7408
|
+
}
|
|
7409
|
+
/**
|
|
7410
|
+
* Set the active leaf for a conversation (switch branches).
|
|
7411
|
+
* Emits a conversationUpdated event so reactive wrappers refresh.
|
|
7412
|
+
*/
|
|
7413
|
+
setActiveLeaf(interactionId) {
|
|
7414
|
+
this._setActiveLeafImpl(interactionId, this._conversationId);
|
|
7415
|
+
}
|
|
7416
|
+
/** @internal */
|
|
7417
|
+
_setActiveLeafImpl(interactionId, conversationId) {
|
|
7418
|
+
const interactions = this._channel?.conversations[conversationId]?.interactions;
|
|
7419
|
+
if (!interactions || Array.isArray(interactions) || !interactions[interactionId]) throw new Error(`Interaction "${interactionId}" not found in conversation "${conversationId}"`);
|
|
7420
|
+
this._activeLeaves.set(conversationId, interactionId);
|
|
7421
|
+
this.emit("conversationUpdated", {
|
|
7422
|
+
conversationId,
|
|
7423
|
+
channelId: this._channelId,
|
|
7424
|
+
source: "local_user"
|
|
7425
|
+
});
|
|
7361
7426
|
}
|
|
7362
7427
|
/**
|
|
7363
7428
|
* Get all conversations in this channel.
|
|
@@ -7371,7 +7436,7 @@ var RoolChannel = class extends EventEmitter {
|
|
|
7371
7436
|
systemInstruction: conv.systemInstruction ?? null,
|
|
7372
7437
|
createdAt: conv.createdAt,
|
|
7373
7438
|
createdBy: conv.createdBy,
|
|
7374
|
-
interactionCount: conv.interactions.length
|
|
7439
|
+
interactionCount: Object.keys(conv.interactions).length
|
|
7375
7440
|
}));
|
|
7376
7441
|
}
|
|
7377
7442
|
/**
|
|
@@ -7780,7 +7845,7 @@ var RoolChannel = class extends EventEmitter {
|
|
|
7780
7845
|
if (!this._channel.conversations[conversationId]) this._channel.conversations[conversationId] = {
|
|
7781
7846
|
createdAt: Date.now(),
|
|
7782
7847
|
createdBy: this._userId,
|
|
7783
|
-
interactions:
|
|
7848
|
+
interactions: {}
|
|
7784
7849
|
};
|
|
7785
7850
|
}
|
|
7786
7851
|
/**
|
|
@@ -7822,14 +7887,17 @@ var RoolChannel = class extends EventEmitter {
|
|
|
7822
7887
|
}
|
|
7823
7888
|
/** @internal */
|
|
7824
7889
|
async _promptImpl(prompt, options, conversationId) {
|
|
7825
|
-
const { attachments, ...rest } = options ?? {};
|
|
7890
|
+
const { attachments, parentInteractionId: explicitParent, ...rest } = options ?? {};
|
|
7826
7891
|
let attachmentUrls;
|
|
7827
7892
|
if (attachments?.length) attachmentUrls = await Promise.all(attachments.map((file) => this.mediaClient.upload(this._id, file)));
|
|
7893
|
+
const parentInteractionId = explicitParent !== void 0 ? explicitParent : this._getActiveLeafImpl(conversationId) ?? null;
|
|
7828
7894
|
const interactionId = generateEntityId();
|
|
7895
|
+
this._activeLeaves.set(conversationId, interactionId);
|
|
7829
7896
|
const result = await this.graphqlClient.prompt(this._id, prompt, this._channelId, conversationId, {
|
|
7830
7897
|
...rest,
|
|
7831
7898
|
attachmentUrls,
|
|
7832
|
-
interactionId
|
|
7899
|
+
interactionId,
|
|
7900
|
+
parentInteractionId
|
|
7833
7901
|
});
|
|
7834
7902
|
const objects = [];
|
|
7835
7903
|
const missing = [];
|
|
@@ -8015,6 +8083,15 @@ var RoolChannel = class extends EventEmitter {
|
|
|
8015
8083
|
if (event.conversation) this._channel.conversations[event.conversationId] = event.conversation;
|
|
8016
8084
|
else delete this._channel.conversations[event.conversationId];
|
|
8017
8085
|
if (JSON.stringify(prev) === JSON.stringify(event.conversation)) break;
|
|
8086
|
+
if (event.conversation && !Array.isArray(event.conversation.interactions)) {
|
|
8087
|
+
const currentLeaf = this._getActiveLeafImpl(event.conversationId);
|
|
8088
|
+
if (currentLeaf) {
|
|
8089
|
+
for (const ix of Object.values(event.conversation.interactions)) if (ix.parentId === currentLeaf && ix.id !== currentLeaf) {
|
|
8090
|
+
this._activeLeaves.set(event.conversationId, ix.id);
|
|
8091
|
+
break;
|
|
8092
|
+
}
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8018
8095
|
this.emit("conversationUpdated", {
|
|
8019
8096
|
conversationId: event.conversationId,
|
|
8020
8097
|
channelId: event.channelId,
|
|
@@ -8123,10 +8200,22 @@ var ConversationHandle = class {
|
|
|
8123
8200
|
get conversationId() {
|
|
8124
8201
|
return this._conversationId;
|
|
8125
8202
|
}
|
|
8126
|
-
/** Get
|
|
8203
|
+
/** Get the active branch of this conversation as a flat array (root → leaf). */
|
|
8127
8204
|
getInteractions() {
|
|
8128
8205
|
return this._channel._getInteractionsImpl(this._conversationId);
|
|
8129
8206
|
}
|
|
8207
|
+
/** Get the full interaction tree as a record. */
|
|
8208
|
+
getTree() {
|
|
8209
|
+
return this._channel._getTreeImpl(this._conversationId);
|
|
8210
|
+
}
|
|
8211
|
+
/** Get the active leaf interaction ID, or undefined if empty. */
|
|
8212
|
+
get activeLeafId() {
|
|
8213
|
+
return this._channel._getActiveLeafImpl(this._conversationId);
|
|
8214
|
+
}
|
|
8215
|
+
/** Switch to a different branch by setting the active leaf. */
|
|
8216
|
+
setActiveLeaf(interactionId) {
|
|
8217
|
+
this._channel._setActiveLeafImpl(interactionId, this._conversationId);
|
|
8218
|
+
}
|
|
8130
8219
|
/** Get the system instruction for this conversation. */
|
|
8131
8220
|
getSystemInstruction() {
|
|
8132
8221
|
return this._channel._getSystemInstructionImpl(this._conversationId);
|
|
@@ -8871,6 +8960,9 @@ var ALLOWED_METHODS = new Set([
|
|
|
8871
8960
|
"alterCollection",
|
|
8872
8961
|
"dropCollection",
|
|
8873
8962
|
"getInteractions",
|
|
8963
|
+
"getTree",
|
|
8964
|
+
"setActiveLeaf",
|
|
8965
|
+
"getActiveLeafId",
|
|
8874
8966
|
"getConversations",
|
|
8875
8967
|
"getSystemInstruction",
|
|
8876
8968
|
"setSystemInstruction",
|
|
@@ -8889,6 +8981,9 @@ var ALLOWED_METHODS = new Set([
|
|
|
8889
8981
|
]);
|
|
8890
8982
|
var CONVERSATION_METHODS = new Set([
|
|
8891
8983
|
"getInteractions",
|
|
8984
|
+
"getTree",
|
|
8985
|
+
"setActiveLeaf",
|
|
8986
|
+
"getActiveLeafId",
|
|
8892
8987
|
"getSystemInstruction",
|
|
8893
8988
|
"setSystemInstruction",
|
|
8894
8989
|
"renameConversation",
|
|
@@ -8903,14 +8998,17 @@ var CONVERSATION_METHODS = new Set([
|
|
|
8903
8998
|
"setMetadata"
|
|
8904
8999
|
]);
|
|
8905
9000
|
var CONVERSATION_METHOD_MAP = { "renameConversation": "rename" };
|
|
9001
|
+
var GETTER_MAP = { "getActiveLeafId": "activeLeafId" };
|
|
8906
9002
|
var BridgeHost = class {
|
|
8907
9003
|
channel;
|
|
8908
9004
|
iframe;
|
|
9005
|
+
user;
|
|
8909
9006
|
eventCleanups = [];
|
|
8910
9007
|
_destroyed = false;
|
|
8911
9008
|
constructor(options) {
|
|
8912
9009
|
this.channel = options.channel;
|
|
8913
9010
|
this.iframe = options.iframe;
|
|
9011
|
+
this.user = options.user;
|
|
8914
9012
|
window.addEventListener("message", this._onMessage);
|
|
8915
9013
|
for (const eventName of FORWARDED_EVENTS) {
|
|
8916
9014
|
const handler = (data) => {
|
|
@@ -8935,6 +9033,7 @@ var BridgeHost = class {
|
|
|
8935
9033
|
role: this.channel.role,
|
|
8936
9034
|
linkAccess: this.channel.linkAccess,
|
|
8937
9035
|
userId: this.channel.userId,
|
|
9036
|
+
user: this.user,
|
|
8938
9037
|
schema: this.channel.getSchema(),
|
|
8939
9038
|
metadata: this.channel.getAllMetadata()
|
|
8940
9039
|
};
|
|
@@ -8969,6 +9068,7 @@ var BridgeHost = class {
|
|
|
8969
9068
|
target = this.channel.conversation(conversationId);
|
|
8970
9069
|
methodName = CONVERSATION_METHOD_MAP[method] ?? method;
|
|
8971
9070
|
}
|
|
9071
|
+
if (GETTER_MAP[methodName]) methodName = GETTER_MAP[methodName];
|
|
8972
9072
|
const fn = target[methodName];
|
|
8973
9073
|
let result;
|
|
8974
9074
|
if (typeof fn === "function") {
|
|
@@ -9307,12 +9407,21 @@ var DevHostController = class {
|
|
|
9307
9407
|
this.client.logout();
|
|
9308
9408
|
window.location.reload();
|
|
9309
9409
|
}
|
|
9410
|
+
get _bridgeUser() {
|
|
9411
|
+
const cu = this.client.currentUser;
|
|
9412
|
+
return {
|
|
9413
|
+
id: cu.id,
|
|
9414
|
+
name: cu.name,
|
|
9415
|
+
email: cu.email
|
|
9416
|
+
};
|
|
9417
|
+
}
|
|
9310
9418
|
_bindBridge(tabId) {
|
|
9311
9419
|
const el = this.iframeEls[tabId];
|
|
9312
9420
|
const ch = this.channels[tabId];
|
|
9313
9421
|
if (el && ch && !this.bridgeHosts[tabId]) this.bridgeHosts[tabId] = createBridgeHost({
|
|
9314
9422
|
channel: ch,
|
|
9315
|
-
iframe: el
|
|
9423
|
+
iframe: el,
|
|
9424
|
+
user: this._bridgeUser
|
|
9316
9425
|
});
|
|
9317
9426
|
}
|
|
9318
9427
|
_bindAllBridges() {
|
|
@@ -15127,11 +15236,7 @@ var root_1 = /* @__PURE__ */ from_html(`<div class="flex items-center justify-ce
|
|
|
15127
15236
|
var root$1 = /* @__PURE__ */ from_html(`<!> <div class="flex-1 min-w-0 flex flex-col"><!></div>`, 1);
|
|
15128
15237
|
function HostShell($$anchor, $$props) {
|
|
15129
15238
|
push($$props, true);
|
|
15130
|
-
const
|
|
15131
|
-
"$$slots",
|
|
15132
|
-
"$$events",
|
|
15133
|
-
"$$legacy"
|
|
15134
|
-
]);
|
|
15239
|
+
const { channelId, extensionUrl, manifest, manifestError } = getContext("hostConfig");
|
|
15135
15240
|
let spaces = /* @__PURE__ */ state(proxy([]));
|
|
15136
15241
|
let currentSpaceId = /* @__PURE__ */ state(null);
|
|
15137
15242
|
let statusText = /* @__PURE__ */ state("Initializing...");
|
|
@@ -15146,7 +15251,12 @@ function HostShell($$anchor, $$props) {
|
|
|
15146
15251
|
let publishMessage = /* @__PURE__ */ state(null);
|
|
15147
15252
|
let publishUrl = /* @__PURE__ */ state(null);
|
|
15148
15253
|
let dropdownOpen = /* @__PURE__ */ state(false);
|
|
15149
|
-
const controller = new DevHostController(
|
|
15254
|
+
const controller = new DevHostController({
|
|
15255
|
+
channelId,
|
|
15256
|
+
extensionUrl,
|
|
15257
|
+
manifest,
|
|
15258
|
+
manifestError
|
|
15259
|
+
}, syncState, tick);
|
|
15150
15260
|
function syncState() {
|
|
15151
15261
|
set(spaces, controller.spaces, true);
|
|
15152
15262
|
set(currentSpaceId, controller.currentSpaceId, true);
|
|
@@ -15162,7 +15272,7 @@ function HostShell($$anchor, $$props) {
|
|
|
15162
15272
|
set(publishMessage, controller.publishMessage, true);
|
|
15163
15273
|
set(publishUrl, controller.publishUrl, true);
|
|
15164
15274
|
}
|
|
15165
|
-
let uninstalledExtensions = /* @__PURE__ */ user_derived(() => get(publishedExtensions).filter((ext) => ext.extensionId !==
|
|
15275
|
+
let uninstalledExtensions = /* @__PURE__ */ user_derived(() => get(publishedExtensions).filter((ext) => ext.extensionId !== channelId && !get(installedExtensionIds).includes(ext.extensionId)));
|
|
15166
15276
|
syncState();
|
|
15167
15277
|
onMount(() => {
|
|
15168
15278
|
controller.boot();
|
|
@@ -15179,10 +15289,10 @@ function HostShell($$anchor, $$props) {
|
|
|
15179
15289
|
return controller;
|
|
15180
15290
|
},
|
|
15181
15291
|
get manifest() {
|
|
15182
|
-
return
|
|
15292
|
+
return manifest;
|
|
15183
15293
|
},
|
|
15184
15294
|
get manifestError() {
|
|
15185
|
-
return
|
|
15295
|
+
return manifestError;
|
|
15186
15296
|
},
|
|
15187
15297
|
get spaces() {
|
|
15188
15298
|
return get(spaces);
|
|
@@ -15268,14 +15378,18 @@ var style = document.createElement("style");
|
|
|
15268
15378
|
style.textContent = app_default + "\n" + gridstack_default;
|
|
15269
15379
|
document.head.appendChild(style);
|
|
15270
15380
|
var root = document.getElementById("rool-host");
|
|
15381
|
+
var channelId = root.dataset.channelId ?? "extension-dev";
|
|
15382
|
+
var extensionUrl = root.dataset.extensionUrl ?? "/";
|
|
15383
|
+
var manifest = root.dataset.manifest ? JSON.parse(root.dataset.manifest) : null;
|
|
15384
|
+
var manifestError = root.dataset.manifestError ?? null;
|
|
15271
15385
|
mount(HostShell, {
|
|
15272
15386
|
target: root,
|
|
15273
|
-
|
|
15274
|
-
channelId
|
|
15275
|
-
extensionUrl
|
|
15276
|
-
manifest
|
|
15277
|
-
manifestError
|
|
15278
|
-
}
|
|
15387
|
+
context: new Map([["hostConfig", {
|
|
15388
|
+
channelId,
|
|
15389
|
+
extensionUrl,
|
|
15390
|
+
manifest,
|
|
15391
|
+
manifestError
|
|
15392
|
+
}]])
|
|
15279
15393
|
});
|
|
15280
15394
|
//#endregion
|
|
15281
15395
|
|