@rool-dev/extension 0.3.7 → 0.3.8-dev.368b058

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.
@@ -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>} */
@@ -3179,6 +3213,52 @@ function from_html(content, flags) {
3179
3213
  };
3180
3214
  }
3181
3215
  /**
3216
+ * @param {string} content
3217
+ * @param {number} flags
3218
+ * @param {'svg' | 'math'} ns
3219
+ * @returns {() => Node | Node[]}
3220
+ */
3221
+ /* @__NO_SIDE_EFFECTS__ */
3222
+ function from_namespace(content, flags, ns = "svg") {
3223
+ /**
3224
+ * Whether or not the first item is a text/element node. If not, we need to
3225
+ * create an additional comment node to act as `effect.nodes.start`
3226
+ */
3227
+ var has_start = !content.startsWith("<!>");
3228
+ var is_fragment = (flags & 1) !== 0;
3229
+ var wrapped = `<${ns}>${has_start ? content : "<!>" + content}</${ns}>`;
3230
+ /** @type {Element | DocumentFragment} */
3231
+ var node;
3232
+ return () => {
3233
+ if (hydrating) {
3234
+ assign_nodes(hydrate_node, null);
3235
+ return hydrate_node;
3236
+ }
3237
+ if (!node) {
3238
+ var root = /* @__PURE__ */ get_first_child(create_fragment_from_html(wrapped));
3239
+ if (is_fragment) {
3240
+ node = document.createDocumentFragment();
3241
+ while (/* @__PURE__ */ get_first_child(root)) node.appendChild(/* @__PURE__ */ get_first_child(root));
3242
+ } else node = /* @__PURE__ */ get_first_child(root);
3243
+ }
3244
+ var clone = node.cloneNode(true);
3245
+ if (is_fragment) {
3246
+ var start = /* @__PURE__ */ get_first_child(clone);
3247
+ var end = clone.lastChild;
3248
+ assign_nodes(start, end);
3249
+ } else assign_nodes(clone, clone);
3250
+ return clone;
3251
+ };
3252
+ }
3253
+ /**
3254
+ * @param {string} content
3255
+ * @param {number} flags
3256
+ */
3257
+ /* @__NO_SIDE_EFFECTS__ */
3258
+ function from_svg(content, flags) {
3259
+ return /* @__PURE__ */ from_namespace(content, flags, "svg");
3260
+ }
3261
+ /**
3182
3262
  * Don't mark this as side-effect-free, hydration needs to walk all nodes
3183
3263
  * @param {any} value
3184
3264
  */
@@ -4119,48 +4199,6 @@ function bind_this(element_or_component = {}, update, get_value, get_parts) {
4119
4199
  //#region ../../node_modules/.pnpm/svelte@5.54.0/node_modules/svelte/src/internal/client/reactivity/props.js
4120
4200
  /** @import { Effect, Source } from './types.js' */
4121
4201
  /**
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
4202
  * This function is responsible for synchronizing a possibly bound prop with the inner component state.
4165
4203
  * It is used whenever the compiler sees that the component writes to the prop, or when it has a default prop_value.
4166
4204
  * @template V
@@ -5638,8 +5676,8 @@ var GraphQLClient = class {
5638
5676
  }
5639
5677
  async prompt(spaceId, prompt, channelId, conversationId, options) {
5640
5678
  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) {
5679
+ 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) {
5680
+ 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
5681
  message
5644
5682
  modifiedObjectIds
5645
5683
  }
@@ -5655,7 +5693,8 @@ var GraphQLClient = class {
5655
5693
  ephemeral: options.ephemeral,
5656
5694
  readOnly: options.readOnly,
5657
5695
  attachments: options.attachmentUrls,
5658
- interactionId: options.interactionId
5696
+ interactionId: options.interactionId,
5697
+ parentInteractionId: options.parentInteractionId
5659
5698
  })).prompt;
5660
5699
  }
5661
5700
  async getAccount() {
@@ -7220,6 +7259,29 @@ function generateEntityId() {
7220
7259
  for (let i = 0; i < 6; i++) result += ID_CHARS[Math.floor(Math.random() * 62)];
7221
7260
  return result;
7222
7261
  }
7262
+ /** Walk from a leaf interaction up through parentId to root, return in root→leaf order. */
7263
+ function walkBranch(interactions, leafId) {
7264
+ const path = [];
7265
+ let currentId = leafId;
7266
+ while (currentId) {
7267
+ const ix = interactions[currentId];
7268
+ if (!ix) break;
7269
+ path.push(ix);
7270
+ currentId = ix.parentId;
7271
+ }
7272
+ return path.reverse();
7273
+ }
7274
+ /** Find the default leaf: the most recent interaction by timestamp that has no children. */
7275
+ function findDefaultLeaf(interactions) {
7276
+ if (!interactions || Array.isArray(interactions)) return void 0;
7277
+ const childSet = /* @__PURE__ */ new Set();
7278
+ for (const ix of Object.values(interactions)) if (ix.parentId) childSet.add(ix.parentId);
7279
+ let best;
7280
+ for (const ix of Object.values(interactions)) if (!childSet.has(ix.id)) {
7281
+ if (!best || ix.timestamp > best.timestamp) best = ix;
7282
+ }
7283
+ return best?.id;
7284
+ }
7223
7285
  var OBJECT_COLLECT_TIMEOUT = 3e4;
7224
7286
  /**
7225
7287
  * A channel is a space + channelId pair.
@@ -7260,6 +7322,7 @@ var RoolChannel = class extends EventEmitter {
7260
7322
  _objectIds;
7261
7323
  _objectStats;
7262
7324
  _hasConnected = false;
7325
+ _activeLeaves = /* @__PURE__ */ new Map();
7263
7326
  _pendingMutations = /* @__PURE__ */ new Map();
7264
7327
  _objectResolvers = /* @__PURE__ */ new Map();
7265
7328
  _objectBuffer = /* @__PURE__ */ new Map();
@@ -7350,14 +7413,62 @@ var RoolChannel = class extends EventEmitter {
7350
7413
  return this._channel?.extensionUrl ?? null;
7351
7414
  }
7352
7415
  /**
7353
- * Get interactions for the current conversation.
7416
+ * Get the active branch of the current conversation as a flat array (root → leaf).
7417
+ * Walks from the active leaf up through parentId pointers.
7354
7418
  */
7355
7419
  getInteractions() {
7356
7420
  return this._getInteractionsImpl(this._conversationId);
7357
7421
  }
7358
7422
  /** @internal */
7359
7423
  _getInteractionsImpl(conversationId) {
7360
- return this._channel?.conversations[conversationId]?.interactions ?? [];
7424
+ const interactions = this._channel?.conversations[conversationId]?.interactions;
7425
+ if (!interactions) return [];
7426
+ if (Array.isArray(interactions)) return interactions;
7427
+ const leafId = this._getActiveLeafImpl(conversationId);
7428
+ if (!leafId) return [];
7429
+ return walkBranch(interactions, leafId);
7430
+ }
7431
+ /**
7432
+ * Get the full interaction tree for a conversation as a record.
7433
+ * For clients that need to render branch navigation UI.
7434
+ */
7435
+ getTree() {
7436
+ return this._getTreeImpl(this._conversationId);
7437
+ }
7438
+ /** @internal */
7439
+ _getTreeImpl(conversationId) {
7440
+ const interactions = this._channel?.conversations[conversationId]?.interactions;
7441
+ if (!interactions || Array.isArray(interactions)) return {};
7442
+ return interactions;
7443
+ }
7444
+ /**
7445
+ * Get the active leaf interaction ID for a conversation.
7446
+ * Returns undefined if the conversation has no interactions.
7447
+ */
7448
+ get activeLeafId() {
7449
+ return this._getActiveLeafImpl(this._conversationId);
7450
+ }
7451
+ /** @internal */
7452
+ _getActiveLeafImpl(conversationId) {
7453
+ return this._activeLeaves.get(conversationId) ?? findDefaultLeaf(this._channel?.conversations[conversationId]?.interactions);
7454
+ }
7455
+ /**
7456
+ * Set the active leaf for a conversation (switch branches).
7457
+ * Emits a conversationUpdated event so reactive wrappers refresh.
7458
+ */
7459
+ setActiveLeaf(interactionId) {
7460
+ this._setActiveLeafImpl(interactionId, this._conversationId);
7461
+ }
7462
+ /** @internal */
7463
+ _setActiveLeafImpl(interactionId, conversationId) {
7464
+ const interactions = this._channel?.conversations[conversationId]?.interactions;
7465
+ if (!interactions || Array.isArray(interactions) || !interactions[interactionId]) throw new Error(`Interaction "${interactionId}" not found in conversation "${conversationId}"`);
7466
+ this._activeLeaves.set(conversationId, interactionId);
7467
+ this.emit("conversationUpdated", {
7468
+ conversationId,
7469
+ channelId: this._channelId,
7470
+ source: "local_user"
7471
+ });
7361
7472
  }
7362
7473
  /**
7363
7474
  * Get all conversations in this channel.
@@ -7371,7 +7482,7 @@ var RoolChannel = class extends EventEmitter {
7371
7482
  systemInstruction: conv.systemInstruction ?? null,
7372
7483
  createdAt: conv.createdAt,
7373
7484
  createdBy: conv.createdBy,
7374
- interactionCount: conv.interactions.length
7485
+ interactionCount: Object.keys(conv.interactions).length
7375
7486
  }));
7376
7487
  }
7377
7488
  /**
@@ -7780,7 +7891,7 @@ var RoolChannel = class extends EventEmitter {
7780
7891
  if (!this._channel.conversations[conversationId]) this._channel.conversations[conversationId] = {
7781
7892
  createdAt: Date.now(),
7782
7893
  createdBy: this._userId,
7783
- interactions: []
7894
+ interactions: {}
7784
7895
  };
7785
7896
  }
7786
7897
  /**
@@ -7822,14 +7933,17 @@ var RoolChannel = class extends EventEmitter {
7822
7933
  }
7823
7934
  /** @internal */
7824
7935
  async _promptImpl(prompt, options, conversationId) {
7825
- const { attachments, ...rest } = options ?? {};
7936
+ const { attachments, parentInteractionId: explicitParent, ...rest } = options ?? {};
7826
7937
  let attachmentUrls;
7827
7938
  if (attachments?.length) attachmentUrls = await Promise.all(attachments.map((file) => this.mediaClient.upload(this._id, file)));
7939
+ const parentInteractionId = explicitParent !== void 0 ? explicitParent : this._getActiveLeafImpl(conversationId) ?? null;
7828
7940
  const interactionId = generateEntityId();
7941
+ this._activeLeaves.set(conversationId, interactionId);
7829
7942
  const result = await this.graphqlClient.prompt(this._id, prompt, this._channelId, conversationId, {
7830
7943
  ...rest,
7831
7944
  attachmentUrls,
7832
- interactionId
7945
+ interactionId,
7946
+ parentInteractionId
7833
7947
  });
7834
7948
  const objects = [];
7835
7949
  const missing = [];
@@ -8015,6 +8129,15 @@ var RoolChannel = class extends EventEmitter {
8015
8129
  if (event.conversation) this._channel.conversations[event.conversationId] = event.conversation;
8016
8130
  else delete this._channel.conversations[event.conversationId];
8017
8131
  if (JSON.stringify(prev) === JSON.stringify(event.conversation)) break;
8132
+ if (event.conversation && !Array.isArray(event.conversation.interactions)) {
8133
+ const currentLeaf = this._getActiveLeafImpl(event.conversationId);
8134
+ if (currentLeaf) {
8135
+ for (const ix of Object.values(event.conversation.interactions)) if (ix.parentId === currentLeaf && ix.id !== currentLeaf) {
8136
+ this._activeLeaves.set(event.conversationId, ix.id);
8137
+ break;
8138
+ }
8139
+ }
8140
+ }
8018
8141
  this.emit("conversationUpdated", {
8019
8142
  conversationId: event.conversationId,
8020
8143
  channelId: event.channelId,
@@ -8123,10 +8246,22 @@ var ConversationHandle = class {
8123
8246
  get conversationId() {
8124
8247
  return this._conversationId;
8125
8248
  }
8126
- /** Get interactions for this conversation. */
8249
+ /** Get the active branch of this conversation as a flat array (root → leaf). */
8127
8250
  getInteractions() {
8128
8251
  return this._channel._getInteractionsImpl(this._conversationId);
8129
8252
  }
8253
+ /** Get the full interaction tree as a record. */
8254
+ getTree() {
8255
+ return this._channel._getTreeImpl(this._conversationId);
8256
+ }
8257
+ /** Get the active leaf interaction ID, or undefined if empty. */
8258
+ get activeLeafId() {
8259
+ return this._channel._getActiveLeafImpl(this._conversationId);
8260
+ }
8261
+ /** Switch to a different branch by setting the active leaf. */
8262
+ setActiveLeaf(interactionId) {
8263
+ this._channel._setActiveLeafImpl(interactionId, this._conversationId);
8264
+ }
8130
8265
  /** Get the system instruction for this conversation. */
8131
8266
  getSystemInstruction() {
8132
8267
  return this._channel._getSystemInstructionImpl(this._conversationId);
@@ -8871,6 +9006,9 @@ var ALLOWED_METHODS = new Set([
8871
9006
  "alterCollection",
8872
9007
  "dropCollection",
8873
9008
  "getInteractions",
9009
+ "getTree",
9010
+ "setActiveLeaf",
9011
+ "getActiveLeafId",
8874
9012
  "getConversations",
8875
9013
  "getSystemInstruction",
8876
9014
  "setSystemInstruction",
@@ -8889,6 +9027,9 @@ var ALLOWED_METHODS = new Set([
8889
9027
  ]);
8890
9028
  var CONVERSATION_METHODS = new Set([
8891
9029
  "getInteractions",
9030
+ "getTree",
9031
+ "setActiveLeaf",
9032
+ "getActiveLeafId",
8892
9033
  "getSystemInstruction",
8893
9034
  "setSystemInstruction",
8894
9035
  "renameConversation",
@@ -8903,14 +9044,19 @@ var CONVERSATION_METHODS = new Set([
8903
9044
  "setMetadata"
8904
9045
  ]);
8905
9046
  var CONVERSATION_METHOD_MAP = { "renameConversation": "rename" };
9047
+ var GETTER_MAP = { "getActiveLeafId": "activeLeafId" };
8906
9048
  var BridgeHost = class {
8907
9049
  channel;
8908
9050
  iframe;
9051
+ user;
9052
+ _colorScheme;
8909
9053
  eventCleanups = [];
8910
9054
  _destroyed = false;
8911
9055
  constructor(options) {
8912
9056
  this.channel = options.channel;
8913
9057
  this.iframe = options.iframe;
9058
+ this.user = options.user;
9059
+ this._colorScheme = options.colorScheme ?? "light";
8914
9060
  window.addEventListener("message", this._onMessage);
8915
9061
  for (const eventName of FORWARDED_EVENTS) {
8916
9062
  const handler = (data) => {
@@ -8935,6 +9081,8 @@ var BridgeHost = class {
8935
9081
  role: this.channel.role,
8936
9082
  linkAccess: this.channel.linkAccess,
8937
9083
  userId: this.channel.userId,
9084
+ user: this.user,
9085
+ colorScheme: this._colorScheme,
8938
9086
  schema: this.channel.getSchema(),
8939
9087
  metadata: this.channel.getAllMetadata()
8940
9088
  };
@@ -8969,6 +9117,7 @@ var BridgeHost = class {
8969
9117
  target = this.channel.conversation(conversationId);
8970
9118
  methodName = CONVERSATION_METHOD_MAP[method] ?? method;
8971
9119
  }
9120
+ if (GETTER_MAP[methodName]) methodName = GETTER_MAP[methodName];
8972
9121
  const fn = target[methodName];
8973
9122
  let result;
8974
9123
  if (typeof fn === "function") {
@@ -8989,6 +9138,15 @@ var BridgeHost = class {
8989
9138
  });
8990
9139
  }
8991
9140
  }
9141
+ /** Update the color scheme and push to the extension iframe. */
9142
+ setColorScheme(colorScheme) {
9143
+ this._colorScheme = colorScheme;
9144
+ this._postToApp({
9145
+ type: "rool:event",
9146
+ name: "colorSchemeChanged",
9147
+ data: { colorScheme }
9148
+ });
9149
+ }
8992
9150
  _postToApp(message) {
8993
9151
  if (this._destroyed) return;
8994
9152
  this.iframe.contentWindow?.postMessage(message, "*");
@@ -9076,6 +9234,7 @@ var DevHostController = class {
9076
9234
  publishedExtensions = [];
9077
9235
  installedExtensionIds = [];
9078
9236
  sidebarCollapsed = false;
9237
+ colorScheme = "light";
9079
9238
  publishState = "idle";
9080
9239
  publishMessage = null;
9081
9240
  publishUrl = null;
@@ -9095,6 +9254,7 @@ var DevHostController = class {
9095
9254
  this._spaceKey = `rool-devhost:${options.channelId}:space`;
9096
9255
  this.env = this._getSavedEnv();
9097
9256
  this.sidebarCollapsed = storageGet("rool-devhost:collapsed") === "true";
9257
+ this.colorScheme = this._getSavedColorScheme();
9098
9258
  }
9099
9259
  get tabs() {
9100
9260
  return [{
@@ -9296,6 +9456,12 @@ var DevHostController = class {
9296
9456
  storageSet("rool-devhost:collapsed", String(this.sidebarCollapsed));
9297
9457
  this._onChange();
9298
9458
  }
9459
+ toggleColorScheme() {
9460
+ this.colorScheme = this.colorScheme === "light" ? "dark" : "light";
9461
+ storageSet("rool-devhost:colorScheme", this.colorScheme);
9462
+ for (const host of Object.values(this.bridgeHosts)) host.setColorScheme(this.colorScheme);
9463
+ this._onChange();
9464
+ }
9299
9465
  registerIframe(tabId, el) {
9300
9466
  this.iframeEls[tabId] = el;
9301
9467
  this._bindBridge(tabId);
@@ -9307,12 +9473,22 @@ var DevHostController = class {
9307
9473
  this.client.logout();
9308
9474
  window.location.reload();
9309
9475
  }
9476
+ get _bridgeUser() {
9477
+ const cu = this.client.currentUser;
9478
+ return {
9479
+ id: cu.id,
9480
+ name: cu.name,
9481
+ email: cu.email
9482
+ };
9483
+ }
9310
9484
  _bindBridge(tabId) {
9311
9485
  const el = this.iframeEls[tabId];
9312
9486
  const ch = this.channels[tabId];
9313
9487
  if (el && ch && !this.bridgeHosts[tabId]) this.bridgeHosts[tabId] = createBridgeHost({
9314
9488
  channel: ch,
9315
- iframe: el
9489
+ iframe: el,
9490
+ user: this._bridgeUser,
9491
+ colorScheme: this.colorScheme
9316
9492
  });
9317
9493
  }
9318
9494
  _bindAllBridges() {
@@ -9355,6 +9531,11 @@ var DevHostController = class {
9355
9531
  if (saved === "local" || saved === "dev" || saved === "prod") return saved;
9356
9532
  return "prod";
9357
9533
  }
9534
+ _getSavedColorScheme() {
9535
+ const saved = storageGet("rool-devhost:colorScheme");
9536
+ if (saved === "light" || saved === "dark") return saved;
9537
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
9538
+ }
9358
9539
  };
9359
9540
  //#endregion
9360
9541
  //#region src/dev/Sidebar.svelte
@@ -9381,7 +9562,9 @@ var root_19 = /* @__PURE__ */ from_html(`<div class="absolute top-full mt-1 left
9381
9562
  var root_28 = /* @__PURE__ */ from_html(`<a target="_blank" rel="noopener noreferrer" class="block text-[11px] text-indigo-500 hover:text-indigo-600 mt-1.5 truncate"> </a>`);
9382
9563
  var root_29 = /* @__PURE__ */ from_html(`<div class="text-[11px] text-red-500 mt-1.5"> </div>`);
9383
9564
  var root_22 = /* @__PURE__ */ from_html(`<div class="px-4 py-3 border-b border-slate-100"><div class="text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Publish</div> <button><!></button> <!></div>`);
9384
- var root_2$1 = /* @__PURE__ */ from_html(`<div class="w-[280px] shrink-0 bg-white border-r border-slate-200 flex flex-col overflow-y-auto"><div class="px-4 pt-4 pb-3 border-b border-slate-100"><div class="flex items-start justify-between mb-1"><!> <button class="p-1 -mr-1 text-slate-400 hover:text-slate-600 transition-colors shrink-0" title="Collapse sidebar"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"></path></svg></button></div> <!> <!> <!></div> <!> <!> <!> <div class="px-4 py-3 border-b border-slate-100"><div class="text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Environment</div> <div class="flex rounded-md border border-slate-200 overflow-hidden"><button>Local</button> <button>Dev</button> <button>Prod</button></div> <div class="text-[10px] text-slate-400 mt-1 font-mono"> </div></div> <div class="px-4 py-3 border-b border-slate-100"><div class="text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Space</div> <div class="relative" data-dropdown=""><button type="button"> <svg class="absolute right-2.5 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"></path></svg></button> <!></div> <div class="text-[11px] text-slate-400 leading-normal mt-1.5"><span></span> </div></div> <!> <div class="px-4 py-3 mt-auto flex items-center justify-between"><a href="https://docs.rool.dev/app" target="_blank" rel="noopener noreferrer" class="text-[11px] text-slate-400 hover:text-indigo-500 transition-colors">Documentation</a> <button class="text-[11px] text-slate-400 hover:text-red-500 transition-colors">Sign out</button></div></div>`);
9565
+ var root_30 = /* @__PURE__ */ from_svg(`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>`);
9566
+ var root_31 = /* @__PURE__ */ from_svg(`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>`);
9567
+ var root_2$1 = /* @__PURE__ */ from_html(`<div class="w-[280px] shrink-0 bg-white border-r border-slate-200 flex flex-col overflow-y-auto"><div class="px-4 pt-4 pb-3 border-b border-slate-100"><div class="flex items-start justify-between mb-1"><!> <button class="p-1 -mr-1 text-slate-400 hover:text-slate-600 transition-colors shrink-0" title="Collapse sidebar"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"></path></svg></button></div> <!> <!> <!></div> <!> <!> <!> <div class="px-4 py-3 border-b border-slate-100"><div class="text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Environment</div> <div class="flex rounded-md border border-slate-200 overflow-hidden"><button>Local</button> <button>Dev</button> <button>Prod</button></div> <div class="text-[10px] text-slate-400 mt-1 font-mono"> </div></div> <div class="px-4 py-3 border-b border-slate-100"><div class="text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Space</div> <div class="relative" data-dropdown=""><button type="button"> <svg class="absolute right-2.5 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"></path></svg></button> <!></div> <div class="text-[11px] text-slate-400 leading-normal mt-1.5"><span></span> </div></div> <!> <div class="px-4 py-3 mt-auto flex items-center justify-between"><a href="https://docs.rool.dev/extension" target="_blank" rel="noopener noreferrer" class="text-[11px] text-slate-400 hover:text-indigo-500 transition-colors">Documentation</a> <button class="p-1 text-slate-400 hover:text-indigo-500 transition-colors"><!></button> <button class="text-[11px] text-slate-400 hover:text-red-500 transition-colors">Sign out</button></div></div>`);
9385
9568
  function Sidebar($$anchor, $$props) {
9386
9569
  push($$props, true);
9387
9570
  let dropdownOpen = prop($$props, "dropdownOpen", 15);
@@ -9402,7 +9585,7 @@ function Sidebar($$anchor, $$props) {
9402
9585
  delegated("click", button, () => $$props.controller.toggleSidebar());
9403
9586
  append($$anchor, div);
9404
9587
  };
9405
- var alternate_2 = ($$anchor) => {
9588
+ var alternate_3 = ($$anchor) => {
9406
9589
  var div_2 = root_2$1();
9407
9590
  var div_3 = child(div_2);
9408
9591
  var div_4 = child(div_3);
@@ -9709,6 +9892,19 @@ function Sidebar($$anchor, $$props) {
9709
9892
  });
9710
9893
  var div_38 = sibling(node_14, 2);
9711
9894
  var button_8 = sibling(child(div_38), 2);
9895
+ var node_17 = child(button_8);
9896
+ var consequent_22 = ($$anchor) => {
9897
+ append($$anchor, root_30());
9898
+ };
9899
+ var alternate_2 = ($$anchor) => {
9900
+ append($$anchor, root_31());
9901
+ };
9902
+ if_block(node_17, ($$render) => {
9903
+ if ($$props.colorScheme === "light") $$render(consequent_22);
9904
+ else $$render(alternate_2, -1);
9905
+ });
9906
+ reset(button_8);
9907
+ var button_9 = sibling(button_8, 2);
9712
9908
  reset(div_38);
9713
9909
  reset(div_2);
9714
9910
  template_effect(() => {
@@ -9720,6 +9916,7 @@ function Sidebar($$anchor, $$props) {
9720
9916
  set_text(text_12, `${get(selectedSpace)?.name ?? "Select a space..." ?? ""} `);
9721
9917
  set_class(span_6, 1, `inline-block w-1.5 h-1.5 rounded-full mr-1 align-middle ${$$props.statusState === "ok" ? "bg-green-500" : $$props.statusState === "loading" ? "bg-amber-500" : "bg-slate-400"}`);
9722
9918
  set_text(text_14, ` ${$$props.statusText ?? ""}`);
9919
+ set_attribute(button_8, "title", $$props.colorScheme === "light" ? "Switch to dark mode" : "Switch to light mode");
9723
9920
  });
9724
9921
  delegated("click", button_1, () => $$props.controller.toggleSidebar());
9725
9922
  delegated("click", button_2, () => $$props.controller.switchEnv("local"));
@@ -9729,12 +9926,13 @@ function Sidebar($$anchor, $$props) {
9729
9926
  e.stopPropagation();
9730
9927
  dropdownOpen(!dropdownOpen());
9731
9928
  });
9732
- delegated("click", button_8, () => $$props.controller.logout());
9929
+ delegated("click", button_8, () => $$props.controller.toggleColorScheme());
9930
+ delegated("click", button_9, () => $$props.controller.logout());
9733
9931
  append($$anchor, div_2);
9734
9932
  };
9735
9933
  if_block(node, ($$render) => {
9736
9934
  if ($$props.sidebarCollapsed) $$render(consequent);
9737
- else $$render(alternate_2, -1);
9935
+ else $$render(alternate_3, -1);
9738
9936
  });
9739
9937
  append($$anchor, fragment);
9740
9938
  pop();
@@ -15127,11 +15325,7 @@ var root_1 = /* @__PURE__ */ from_html(`<div class="flex items-center justify-ce
15127
15325
  var root$1 = /* @__PURE__ */ from_html(`<!> <div class="flex-1 min-w-0 flex flex-col"><!></div>`, 1);
15128
15326
  function HostShell($$anchor, $$props) {
15129
15327
  push($$props, true);
15130
- const props = /* @__PURE__ */ rest_props($$props, [
15131
- "$$slots",
15132
- "$$events",
15133
- "$$legacy"
15134
- ]);
15328
+ const { channelId, extensionUrl, manifest, manifestError } = getContext("hostConfig");
15135
15329
  let spaces = /* @__PURE__ */ state(proxy([]));
15136
15330
  let currentSpaceId = /* @__PURE__ */ state(null);
15137
15331
  let statusText = /* @__PURE__ */ state("Initializing...");
@@ -15142,11 +15336,17 @@ function HostShell($$anchor, $$props) {
15142
15336
  let publishedExtensions = /* @__PURE__ */ state(proxy([]));
15143
15337
  let installedExtensionIds = /* @__PURE__ */ state(proxy([]));
15144
15338
  let tabs = /* @__PURE__ */ state(proxy([]));
15339
+ let colorScheme = /* @__PURE__ */ state("light");
15145
15340
  let publishState = /* @__PURE__ */ state("idle");
15146
15341
  let publishMessage = /* @__PURE__ */ state(null);
15147
15342
  let publishUrl = /* @__PURE__ */ state(null);
15148
15343
  let dropdownOpen = /* @__PURE__ */ state(false);
15149
- const controller = new DevHostController(props, syncState, tick);
15344
+ const controller = new DevHostController({
15345
+ channelId,
15346
+ extensionUrl,
15347
+ manifest,
15348
+ manifestError
15349
+ }, syncState, tick);
15150
15350
  function syncState() {
15151
15351
  set(spaces, controller.spaces, true);
15152
15352
  set(currentSpaceId, controller.currentSpaceId, true);
@@ -15154,6 +15354,7 @@ function HostShell($$anchor, $$props) {
15154
15354
  set(statusState, controller.statusState, true);
15155
15355
  set(placeholderText, controller.placeholderText, true);
15156
15356
  set(sidebarCollapsed, controller.sidebarCollapsed, true);
15357
+ set(colorScheme, controller.colorScheme, true);
15157
15358
  set(env, controller.env, true);
15158
15359
  set(publishedExtensions, controller.publishedExtensions, true);
15159
15360
  set(installedExtensionIds, controller.installedExtensionIds, true);
@@ -15162,7 +15363,7 @@ function HostShell($$anchor, $$props) {
15162
15363
  set(publishMessage, controller.publishMessage, true);
15163
15364
  set(publishUrl, controller.publishUrl, true);
15164
15365
  }
15165
- let uninstalledExtensions = /* @__PURE__ */ user_derived(() => get(publishedExtensions).filter((ext) => ext.extensionId !== $$props.channelId && !get(installedExtensionIds).includes(ext.extensionId)));
15366
+ let uninstalledExtensions = /* @__PURE__ */ user_derived(() => get(publishedExtensions).filter((ext) => ext.extensionId !== channelId && !get(installedExtensionIds).includes(ext.extensionId)));
15166
15367
  syncState();
15167
15368
  onMount(() => {
15168
15369
  controller.boot();
@@ -15179,10 +15380,10 @@ function HostShell($$anchor, $$props) {
15179
15380
  return controller;
15180
15381
  },
15181
15382
  get manifest() {
15182
- return $$props.manifest;
15383
+ return manifest;
15183
15384
  },
15184
15385
  get manifestError() {
15185
- return $$props.manifestError;
15386
+ return manifestError;
15186
15387
  },
15187
15388
  get spaces() {
15188
15389
  return get(spaces);
@@ -15202,6 +15403,9 @@ function HostShell($$anchor, $$props) {
15202
15403
  get sidebarCollapsed() {
15203
15404
  return get(sidebarCollapsed);
15204
15405
  },
15406
+ get colorScheme() {
15407
+ return get(colorScheme);
15408
+ },
15205
15409
  get publishState() {
15206
15410
  return get(publishState);
15207
15411
  },
@@ -15268,14 +15472,18 @@ var style = document.createElement("style");
15268
15472
  style.textContent = app_default + "\n" + gridstack_default;
15269
15473
  document.head.appendChild(style);
15270
15474
  var root = document.getElementById("rool-host");
15475
+ var channelId = root.dataset.channelId ?? "extension-dev";
15476
+ var extensionUrl = root.dataset.extensionUrl ?? "/";
15477
+ var manifest = root.dataset.manifest ? JSON.parse(root.dataset.manifest) : null;
15478
+ var manifestError = root.dataset.manifestError ?? null;
15271
15479
  mount(HostShell, {
15272
15480
  target: root,
15273
- props: {
15274
- channelId: root.dataset.channelId ?? "extension-dev",
15275
- extensionUrl: root.dataset.extensionUrl ?? "/",
15276
- manifest: root.dataset.manifest ? JSON.parse(root.dataset.manifest) : null,
15277
- manifestError: root.dataset.manifestError ?? null
15278
- }
15481
+ context: new Map([["hostConfig", {
15482
+ channelId,
15483
+ extensionUrl,
15484
+ manifest,
15485
+ manifestError
15486
+ }]])
15279
15487
  });
15280
15488
  //#endregion
15281
15489