@ibgib/space-gib 0.0.34 → 0.0.35

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.
Files changed (45) hide show
  1. package/dist/client/bootstrap.mjs +1 -1
  2. package/dist/client/{chunk-25PXC4HP.mjs → chunk-FIAGRVBY.mjs} +1487 -468
  3. package/dist/client/chunk-XLQ3UCQY.mjs +53 -0
  4. package/dist/client/css/activity-bar.css +21 -3
  5. package/dist/client/css/layout.css +126 -5
  6. package/dist/client/index.html +6 -0
  7. package/dist/client/index.mjs +22 -45
  8. package/dist/client/privacy.html +22 -22
  9. package/dist/client/script.mjs +1 -1
  10. package/dist/server/server.mjs +3 -3
  11. package/package.json +6 -6
  12. package/src/client/AUTO-GENERATED-version.mts +1 -1
  13. package/src/client/cosmos/seed-cosmos-workspace.mts +20 -6
  14. package/src/client/css/activity-bar.css +21 -3
  15. package/src/client/css/layout.css +126 -5
  16. package/src/client/dev-tools/vcs-workspace.mts +4 -4
  17. package/src/client/index.html +6 -0
  18. package/src/client/privacy.html +22 -22
  19. package/src/client/ui/component/changes/changes.css +413 -0
  20. package/src/client/ui/component/changes/changes.html +37 -0
  21. package/src/client/ui/component/changes/changes.mts +766 -0
  22. package/src/client/ui/component/changes/index.mts +9 -0
  23. package/src/client/ui/component/chat-view/chat-view.html +6 -58
  24. package/src/client/ui/component/chat-view/chat-view.mts +13 -26
  25. package/src/client/ui/component/clone/clone.mts +67 -39
  26. package/src/client/ui/component/code-editor/code-editor.css +91 -9
  27. package/src/client/ui/component/code-editor/code-editor.html +58 -45
  28. package/src/client/ui/component/code-editor/code-editor.mts +265 -49
  29. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +1 -1
  30. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +5 -10
  31. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +297 -64
  32. package/src/client/ui/component/file-explorer/file-explorer.css +475 -11
  33. package/src/client/ui/component/file-explorer/file-explorer.html +45 -65
  34. package/src/client/ui/component/file-explorer/file-explorer.mts +1164 -98
  35. package/src/client/ui/component/nested-chat/chat/chat.mts +5 -90
  36. package/src/client/ui/component/nested-chat/nested-chat.mts +10 -8
  37. package/src/client/ui/component/timeline/timeline.css +16 -1
  38. package/src/client/ui/component/timeline/timeline.mts +37 -93
  39. package/src/client/ui/router/space-gib-router-helpers.mts +33 -233
  40. package/src/client/ui/router/space-gib-router-helpers.respec.mts +298 -122
  41. package/src/client/ui/router/space-gib-router-service.mts +28 -151
  42. package/src/client/ui/router/space-gib-router-types.mts +32 -76
  43. package/src/client/ui/shell/cosmic-big-bang.mts +12 -3
  44. package/src/client/ui/shell/space-gib-shell-service.mts +687 -119
  45. package/dist/client/chunk-RXWLL2AI.mjs +0 -30
@@ -1,25 +1,34 @@
1
1
  import thisCss from "./cosmos-navigator.css";
2
2
  import thisHtml from "./cosmos-navigator.html";
3
3
 
4
- import { ROOT_ADDR } from "@ibgib/ts-gib/dist/V1/constants.mjs";
4
+ import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
5
5
  import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
6
6
  import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
7
- import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
8
- import {
9
- IbGibDynamicComponentMetaBase, IbGibDynamicComponentInstanceBase,
10
- } from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
7
+ import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
8
+ import { getSpaceIdFromIb } from "@ibgib/core-gib/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs";
9
+ import { createCosmosIbGib, addGalaxyToCosmos } from "@ibgib/core-gib/dist/cosmology/cosmos/cosmos-helpers.mjs";
10
+ import { getSpaceQualifiedIbGibAddr, getIbGibFromSpace } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
11
+ import { CosmosIbGib_V1 } from "@ibgib/core-gib/dist/cosmology/cosmos/cosmos-types.mjs";
12
+ import { GalaxyPresetType } from "@ibgib/core-gib/dist/cosmology/galaxy/galaxy-configs.mjs";
13
+ import { createGalaxyIbGib } from "@ibgib/core-gib/dist/cosmology/galaxy/galaxy-helpers.mjs";
14
+ import { IbGibDynamicComponentMetaBase, IbGibDynamicComponentInstanceBase, } from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
11
15
  import {
12
16
  ElementsBase, IbGibDynamicComponentInstance,
13
17
  IbGibDynamicComponentInstanceInitOpts,
14
18
  } from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
15
19
  import { getComponentCtorArg } from "@ibgib/web-gib/dist/app-bootstrap/init-orchestration.mjs";
16
- import { seedInMemoryCosmosWorkspace } from "../../../cosmos/seed-cosmos-workspace.mjs";
20
+ import { promptForText } from "@ibgib/web-gib/dist/helpers.web.mjs";
21
+
22
+ import { getPlaygroundMetaspaceAndSpace, seedInMemoryCosmosWorkspace } from "../../../cosmos/seed-cosmos-workspace.mjs";
23
+ import { executeVcsInit } from "@ibgib/core-gib/dist/cosmology/branching/commands/core-init-cmd.mjs";
24
+ import { GalaxyIbGib_V1 } from "@ibgib/core-gib/dist/cosmology/galaxy/galaxy-types.mjs";
25
+ import { getSpaceGibRouterSvc } from "../../router/index.mjs";
17
26
 
18
27
  export const COSMOS_NAVIGATOR_COMPONENT_NAME = 'space-gib-cosmos-navigator';
19
28
 
20
29
  export interface AttachedSpace {
21
30
  id: string;
22
- type: 'code' | 'text';
31
+ type: GalaxyPresetType | 'code' | 'text';
23
32
  name: string;
24
33
  shortLabel: string;
25
34
  icon: string;
@@ -28,6 +37,7 @@ export interface AttachedSpace {
28
37
  export interface CosmosInfo {
29
38
  id: string;
30
39
  name: string;
40
+ ibGibAddr?: IbGibAddr;
31
41
  spaces: AttachedSpace[];
32
42
  createdAt: number;
33
43
  isTemporary?: boolean;
@@ -89,8 +99,8 @@ export interface CosmosNavigatorElements extends ElementsBase {
89
99
  activeCosmosTitleCaptionEl: HTMLSpanElement;
90
100
  activeCosmosTempBadgeEl?: HTMLSpanElement;
91
101
  superspaceSatellitesEl: HTMLDivElement;
92
- btnSatCodeEl: HTMLButtonElement;
93
- btnSatTextEl: HTMLButtonElement;
102
+ btnSatCodeEl?: HTMLButtonElement;
103
+ btnSatTextEl?: HTMLButtonElement;
94
104
  nodeAgentWrapperEl: HTMLDivElement;
95
105
  btnNodeAgentEl: HTMLButtonElement;
96
106
  }
@@ -119,6 +129,8 @@ export class CosmosNavigatorComponentInstance
119
129
  private isSpaceLaunching: boolean = false;
120
130
 
121
131
  // Canvas & Starfield State
132
+ public hasBigBangExploded: boolean = false;
133
+ private starfieldFadeAlpha: number = 0;
122
134
  private ctx: CanvasRenderingContext2D | null = null;
123
135
  private animFrameId: number | null = null;
124
136
  private resizeObserver: ResizeObserver | null = null;
@@ -212,6 +224,8 @@ export class CosmosNavigatorComponentInstance
212
224
  this.cosmoses = [];
213
225
  this.activeCosmosId = null;
214
226
  this.zoomState = 'polycosmos';
227
+ this.hasBigBangExploded = false;
228
+ this.starfieldFadeAlpha = 0;
215
229
 
216
230
  // Clear any stale keys from earlier runs so reload presents a clean slate
217
231
  try {
@@ -319,22 +333,27 @@ export class CosmosNavigatorComponentInstance
319
333
 
320
334
  ctx.clearRect(0, 0, w, h);
321
335
 
322
- // 1. Draw starfield
323
- for (let i = 0; i < this.stars.length; i++) {
324
- const s = this.stars[i];
325
- s.phase += s.speed;
326
- const currentAlpha = Math.max(0.1, Math.min(1.0, s.alpha + Math.sin(s.phase) * 0.35));
327
-
328
- ctx.fillStyle = `rgba(255, 255, 255, ${currentAlpha})`;
329
- ctx.beginPath();
330
- ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
331
- ctx.fill();
332
-
333
- // Subtle drift
334
- s.y -= 0.08;
335
- if (s.y < 0) {
336
- s.y = h;
337
- s.x = Math.random() * w;
336
+ // 1. Draw starfield (only after Big Bang explosion)
337
+ if (this.hasBigBangExploded) {
338
+ if (this.starfieldFadeAlpha < 1.0) {
339
+ this.starfieldFadeAlpha = Math.min(1.0, this.starfieldFadeAlpha + 0.02);
340
+ }
341
+ for (let i = 0; i < this.stars.length; i++) {
342
+ const s = this.stars[i];
343
+ s.phase += s.speed;
344
+ const currentAlpha = Math.max(0.1, Math.min(1.0, s.alpha + Math.sin(s.phase) * 0.35)) * this.starfieldFadeAlpha;
345
+
346
+ ctx.fillStyle = `rgba(255, 255, 255, ${currentAlpha})`;
347
+ ctx.beginPath();
348
+ ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
349
+ ctx.fill();
350
+
351
+ // Subtle drift
352
+ s.y -= 0.08;
353
+ if (s.y < 0) {
354
+ s.y = h;
355
+ s.x = Math.random() * w;
356
+ }
338
357
  }
339
358
  }
340
359
 
@@ -380,6 +399,7 @@ export class CosmosNavigatorComponentInstance
380
399
  }
381
400
 
382
401
  public triggerBigBangExplosion(): void {
402
+ this.hasBigBangExploded = true;
383
403
  if (!this.el.canvasEl) return;
384
404
  const w = this.el.canvasEl.width;
385
405
  const h = this.el.canvasEl.height;
@@ -472,38 +492,17 @@ export class CosmosNavigatorComponentInstance
472
492
  this.selectCosmos(seeded.id);
473
493
  } catch (seedErr) {
474
494
  console.error(`${this.lc} Failed to seed in-memory cosmos: ${extractErrorMsg(seedErr)}`);
475
- const fallback = this.createCosmos('welcome-cosmos');
476
- this.selectCosmos(fallback.id);
495
+ throw seedErr;
477
496
  }
478
497
  } else {
479
498
  const nextIndex = this.cosmoses.length + 1;
480
- const newCosmos = this.createCosmos(`cosmos-${nextIndex}`);
499
+ const newCosmos = await this.createCosmos(`cosmos-${nextIndex}`);
481
500
  this.selectCosmos(newCosmos.id);
482
501
  }
483
-
484
502
  });
485
503
  });
486
504
 
487
- // Satellites Click (Code Space & Text Space)
488
- this.el.btnSatCodeEl.addEventListener('click', (e) => {
489
- e.stopPropagation();
490
- this.handleSpaceClick('code');
491
- });
492
-
493
- this.el.btnSatTextEl.addEventListener('click', (e) => {
494
- e.stopPropagation();
495
- this.handleSpaceClick('text');
496
- });
497
505
 
498
- // Hover over satellites pauses the orbit & cosmos galaxy spin (drifting buttons keep moving)
499
- [this.el.btnSatCodeEl, this.el.btnSatTextEl].forEach(btn => {
500
- btn?.addEventListener('mouseenter', () => {
501
- this.el.activeCosmosStageEl?.classList.add('satellites-hovered');
502
- });
503
- btn?.addEventListener('mouseleave', () => {
504
- this.el.activeCosmosStageEl?.classList.remove('satellites-hovered');
505
- });
506
- });
507
506
 
508
507
  // Pitch Node Click (💰)
509
508
  this.el.btnNodePitchEl?.addEventListener('click', (e) => {
@@ -522,6 +521,94 @@ export class CosmosNavigatorComponentInstance
522
521
  e.stopPropagation();
523
522
  this.handleAgentClick();
524
523
  });
524
+
525
+ // Code Galaxy Revolving Satellite Button Click (</>)
526
+ this.el.btnSatCodeEl?.addEventListener('click', async (e) => {
527
+ e.stopPropagation();
528
+ await this.handleSatCodeClick();
529
+ });
530
+
531
+ // Notes Galaxy Revolving Satellite Button Click (📝)
532
+ this.el.btnSatTextEl?.addEventListener('click', async (e) => {
533
+ e.stopPropagation();
534
+ await this.handleSatTextClick();
535
+ });
536
+
537
+ // Hover pause on satellites
538
+ [this.el.btnSatCodeEl, this.el.btnSatTextEl].forEach(btn => {
539
+ btn?.addEventListener('mouseenter', () => {
540
+ this.el.activeCosmosStageEl?.classList.add('satellites-hovered');
541
+ });
542
+ btn?.addEventListener('mouseleave', () => {
543
+ this.el.activeCosmosStageEl?.classList.remove('satellites-hovered');
544
+ });
545
+ });
546
+ }
547
+
548
+ public async handleSatCodeClick(): Promise<void> {
549
+ const activeCosmos = this.getActiveCosmos();
550
+ if (!activeCosmos) return;
551
+
552
+ const count = activeCosmos.spaces.filter(s => s.type === 'code').length;
553
+ const defaultName = count === 0 ? 'code-1' : `code-${count + 1}`;
554
+ const galaxyName = await promptForText({
555
+ title: 'Create Code Galaxy',
556
+ msg: `Name of the new Code Galaxy for [${activeCosmos.name}]:`,
557
+ defaultValue: defaultName,
558
+ cancelable: true,
559
+ });
560
+
561
+ if (!galaxyName) return;
562
+
563
+ const sourceBtn = this.el.btnSatCodeEl || this.el.btnNodeSuperspaceEl;
564
+ const sourceWrapper = (sourceBtn?.closest('.satellite-wrapper') as HTMLElement) || sourceBtn;
565
+
566
+ let space = activeCosmos.spaces.find(s => s.id === galaxyName || s.name === galaxyName);
567
+ if (!space) {
568
+ space = await this.createAndAttachGalaxy({
569
+ cosmosId: activeCosmos.id,
570
+ galaxyName,
571
+ discriminator: GalaxyPresetType.code,
572
+ skipEvent: true,
573
+ });
574
+ }
575
+
576
+ if (space) {
577
+ this.handleSpaceClick(space, sourceBtn, sourceWrapper);
578
+ }
579
+ }
580
+
581
+ public async handleSatTextClick(): Promise<void> {
582
+ const activeCosmos = this.getActiveCosmos();
583
+ if (!activeCosmos) return;
584
+
585
+ const count = activeCosmos.spaces.filter(s => s.type === 'text' || s.type === GalaxyPresetType.notes).length;
586
+ const defaultName = count === 0 ? 'notes-1' : `notes-${count + 1}`;
587
+ const galaxyName = await promptForText({
588
+ title: 'Create Notes Galaxy',
589
+ msg: `Name of the new Notes Galaxy for [${activeCosmos.name}]:`,
590
+ defaultValue: defaultName,
591
+ cancelable: true,
592
+ });
593
+
594
+ if (!galaxyName) return;
595
+
596
+ const sourceBtn = this.el.btnSatTextEl || this.el.btnNodeSuperspaceEl;
597
+ const sourceWrapper = (sourceBtn?.closest('.satellite-wrapper') as HTMLElement) || sourceBtn;
598
+
599
+ let space = activeCosmos.spaces.find(s => s.id === galaxyName || s.name === galaxyName);
600
+ if (!space) {
601
+ space = await this.createAndAttachGalaxy({
602
+ cosmosId: activeCosmos.id,
603
+ galaxyName,
604
+ discriminator: GalaxyPresetType.notes,
605
+ skipEvent: true,
606
+ });
607
+ }
608
+
609
+ if (space) {
610
+ this.handleSpaceClick(space, sourceBtn, sourceWrapper);
611
+ }
525
612
  }
526
613
 
527
614
  private launchProjectile({
@@ -818,7 +905,11 @@ export class CosmosNavigatorComponentInstance
818
905
  }
819
906
  }
820
907
 
821
- public handleSpaceClick(type: 'code' | 'text'): AttachedSpace | null {
908
+ public handleSpaceClick(
909
+ typeOrSpace: AttachedSpace | 'code' | 'text',
910
+ sourceBtn?: HTMLElement,
911
+ sourceWrapper?: HTMLElement
912
+ ): AttachedSpace | null {
822
913
  if (!this.activeCosmosId) return null;
823
914
  const activeCosmos = this.getActiveCosmos();
824
915
  if (!activeCosmos) { return null; }
@@ -828,9 +919,12 @@ export class CosmosNavigatorComponentInstance
828
919
  this.initialOnboardingDone = true;
829
920
  this.isSpaceLaunching = true;
830
921
 
922
+ const type = typeof typeOrSpace === 'string' ? typeOrSpace : typeOrSpace.type;
923
+ const space = typeof typeOrSpace === 'object' ? typeOrSpace : undefined;
924
+
831
925
  const count = activeCosmos.spaces.filter(s => s.type === type).length;
832
926
  const existingSpacesCount = activeCosmos.spaces.length;
833
- const newSpace: AttachedSpace = {
927
+ const newSpace: AttachedSpace = space || {
834
928
  id: `${type}-space-${count + 1}-${Date.now()}`,
835
929
  type,
836
930
  name: type === 'code' ? `Code Space ${count + 1}` : `Text Space ${count + 1}`,
@@ -838,11 +932,13 @@ export class CosmosNavigatorComponentInstance
838
932
  icon: type === 'code' ? '</>' : '📝',
839
933
  };
840
934
 
841
- activeCosmos.spaces.push(newSpace);
842
- this.saveState();
935
+ if (!activeCosmos.spaces.some(s => s.id === newSpace.id)) {
936
+ activeCosmos.spaces.push(newSpace);
937
+ this.saveState();
938
+ }
843
939
 
844
- const sourceBtnEl = type === 'code' ? this.el.btnSatCodeEl : this.el.btnSatTextEl;
845
- const sourceWrapperEl = (sourceBtnEl?.closest('.satellite-wrapper') as HTMLElement) || sourceBtnEl;
940
+ const sourceBtnEl = sourceBtn || (this.el.superspaceSatellitesEl?.querySelector('.satellite-node-btn') as HTMLElement) || this.el.btnNodeSuperspaceEl;
941
+ const sourceWrapperEl = sourceWrapper || (sourceBtnEl?.closest('.satellite-wrapper') as HTMLElement) || sourceBtnEl;
846
942
 
847
943
  const headerH = document.getElementById('main-header')?.getBoundingClientRect().height || 60;
848
944
  const targetTop = headerH + 128 + (existingSpacesCount * 50);
@@ -878,8 +974,8 @@ export class CosmosNavigatorComponentInstance
878
974
  sourceWrapperEl,
879
975
  sourceBtnEl,
880
976
  fallbackTarget,
881
- emoji: type === 'code' ? '</>' : '📝',
882
- projectileType: type,
977
+ emoji: newSpace.icon || (type === 'code' ? '</>' : '📝'),
978
+ projectileType: type === 'code' ? 'code' : 'text',
883
979
  duration: 1400,
884
980
  onDocked: () => {
885
981
  this.isSpaceLaunching = false;
@@ -900,21 +996,134 @@ export class CosmosNavigatorComponentInstance
900
996
  return newSpace;
901
997
  }
902
998
 
903
- public createCosmos(name?: string, isTemporary?: boolean): CosmosInfo {
904
- const id = `cosmos-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
999
+ public async createAndAttachGalaxy({
1000
+ cosmosId,
1001
+ galaxyName,
1002
+ discriminator,
1003
+ skipEvent = false,
1004
+ }: {
1005
+ cosmosId?: string;
1006
+ galaxyName: string;
1007
+ discriminator?: GalaxyPresetType | 'code' | 'notes';
1008
+ skipEvent?: boolean;
1009
+ }): Promise<AttachedSpace | undefined> {
1010
+ const cosmos = cosmosId ? this.cosmoses.find(c => c.id === cosmosId) : this.getActiveCosmos();
1011
+ if (!cosmos) return undefined;
1012
+
1013
+ try {
1014
+ const { metaspace, space } = await getPlaygroundMetaspaceAndSpace();
1015
+ const spaceId = space?.ib ? getSpaceIdFromIb(space.ib) || 'temp_space' : 'temp_space';
1016
+
1017
+ // 1. Fetch Cosmos IbGib
1018
+ let cosmosIbGib: CosmosIbGib_V1 | undefined;
1019
+ if (cosmos.ibGibAddr) {
1020
+ cosmosIbGib = await getIbGibFromSpace<CosmosIbGib_V1>({ addr: cosmos.ibGibAddr, space });
1021
+ }
1022
+ if (!cosmosIbGib) {
1023
+ // Try by name in router cache
1024
+ const router = getSpaceGibRouterSvc();
1025
+ cosmosIbGib = router.cosmosManifestCache?.get(cosmos.name);
1026
+ }
1027
+ if (!cosmosIbGib) {
1028
+ throw new Error(`cosmosIbGib not found for cosmos "${cosmos.name}" (addr: ${cosmos.ibGibAddr || 'none'}). (E: 661ab8c2b7b8800be247f588b17ee726)`);
1029
+ }
1030
+
1031
+ // 2. Create Galaxy IbGib
1032
+ let galaxyIbGib: GalaxyIbGib_V1;
1033
+ const isCode = discriminator === GalaxyPresetType.code;
1034
+ if (isCode) {
1035
+ const initRes = await executeVcsInit({
1036
+ metaspace,
1037
+ localSpace: space,
1038
+ galaxyName,
1039
+ branchName: 'main',
1040
+ });
1041
+ galaxyIbGib = initRes.galaxyIbGib;
1042
+ } else {
1043
+ galaxyIbGib = await createGalaxyIbGib({
1044
+ galaxyName,
1045
+ discriminator: GalaxyPresetType.notes,
1046
+ space,
1047
+ metaspace,
1048
+ });
1049
+ }
1050
+
1051
+ // 3. Add galaxy to cosmos manifest
1052
+ const sqGalaxyAddr = getSpaceQualifiedIbGibAddr({
1053
+ spaceId,
1054
+ ibGibAddr: getIbGibAddr({ ibGib: galaxyIbGib }),
1055
+ });
1056
+ cosmosIbGib = await addGalaxyToCosmos({
1057
+ cosmosIbGib,
1058
+ sqGalaxyAddr,
1059
+ galaxyIbGib,
1060
+ space,
1061
+ metaspace,
1062
+ });
1063
+
1064
+ // 4. Update cosmos ibGibAddr and router manifest cache
1065
+ cosmos.ibGibAddr = getIbGibAddr({ ibGib: cosmosIbGib });
1066
+ getSpaceGibRouterSvc().setCosmosManifest(cosmos.name, cosmosIbGib);
1067
+
1068
+ // 5. Update local cosmos state
1069
+ const newSpace: AttachedSpace = {
1070
+ id: galaxyName,
1071
+ type: isCode ? GalaxyPresetType.code : GalaxyPresetType.notes,
1072
+ name: galaxyName,
1073
+ shortLabel: galaxyName,
1074
+ icon: isCode ? '</>' : '📝',
1075
+ };
1076
+ if (!cosmos.spaces.some(s => s.id === galaxyName)) {
1077
+ cosmos.spaces.push(newSpace);
1078
+ }
1079
+ this.saveState();
1080
+
1081
+ // 7. Dispatch space added event if not skipped (e.g. handleSpaceClick dispatches on projectile dock)
1082
+ if (!skipEvent) {
1083
+ this.dispatchEvent(new CustomEvent('space-gib-space-added', {
1084
+ detail: {
1085
+ cosmosId: cosmos.id,
1086
+ space: newSpace,
1087
+ cosmos,
1088
+ },
1089
+ bubbles: true,
1090
+ composed: true,
1091
+ }));
1092
+ }
1093
+
1094
+ return newSpace;
1095
+ } catch (err) {
1096
+ console.error(`${this.lc} Failed to create and attach galaxy: ${extractErrorMsg(err)}`);
1097
+ throw err;
1098
+ }
1099
+ }
1100
+
1101
+ public async createCosmos(name?: string, isTemporary?: boolean): Promise<CosmosInfo> {
905
1102
  const cosmosName = name || `cosmos-${this.cosmoses.length + 1}`;
906
1103
  const hasIdentity = Boolean((globalThis as any).ibgib?.identity?.domainIdentity);
907
1104
  const temp = isTemporary !== undefined ? isTemporary : !hasIdentity;
1105
+
1106
+ const { metaspace, space } = await getPlaygroundMetaspaceAndSpace();
1107
+ const cosmosIbGib = await createCosmosIbGib({
1108
+ cosmosName,
1109
+ description: `${cosmosName} Cosmos`,
1110
+ space,
1111
+ metaspace,
1112
+ });
1113
+ const ibGibAddr = getIbGibAddr({ ibGib: cosmosIbGib });
1114
+ getSpaceGibRouterSvc().setCosmosManifest(cosmosName, cosmosIbGib);
1115
+
908
1116
  const newCosmos: CosmosInfo = {
909
- id,
1117
+ id: cosmosName,
910
1118
  name: cosmosName,
1119
+ ibGibAddr,
911
1120
  isTemporary: temp,
912
1121
  spaces: [],
913
1122
  createdAt: Date.now(),
914
1123
  };
915
1124
 
916
1125
  this.cosmoses.push(newCosmos);
917
- this.activeCosmosId = id;
1126
+ this.activeCosmosId = newCosmos.id;
918
1127
  this.saveState();
919
1128
  return newCosmos;
920
1129
  }
@@ -928,11 +1137,11 @@ export class CosmosNavigatorComponentInstance
928
1137
  this.setZoomState('cosmos', cosmos.id);
929
1138
  }
930
1139
 
931
- public async ensureCosmos(cosmosId: string): Promise<CosmosInfo> {
932
- let existing = this.cosmoses.find(c => c.id === cosmosId || c.name === cosmosId);
1140
+ public async findCosmos(cosmosNameOrId: string): Promise<CosmosInfo | undefined> {
1141
+ let existing = this.cosmoses.find(c => c.id === cosmosNameOrId || c.name === cosmosNameOrId);
933
1142
  if (existing) { return existing; }
934
1143
 
935
- if (cosmosId === 'welcome-cosmos' || cosmosId === 'my-cosmos') {
1144
+ if (cosmosNameOrId === 'welcome-cosmos') {
936
1145
  const seeded = await seedInMemoryCosmosWorkspace();
937
1146
  if (!this.cosmoses.some(c => c.id === seeded.id)) {
938
1147
  this.cosmoses.push(seeded);
@@ -940,7 +1149,26 @@ export class CosmosNavigatorComponentInstance
940
1149
  return seeded;
941
1150
  }
942
1151
 
943
- return this.createCosmos(cosmosId);
1152
+ const router = getSpaceGibRouterSvc();
1153
+ const cachedManifest = router.getCachedCosmosManifest(cosmosNameOrId);
1154
+ if (cachedManifest) {
1155
+ const ibGibAddr = getIbGibAddr({ ibGib: cachedManifest });
1156
+ const restoredCosmos: CosmosInfo = {
1157
+ id: cosmosNameOrId,
1158
+ name: cosmosNameOrId,
1159
+ ibGibAddr,
1160
+ spaces: [],
1161
+ createdAt: Date.now(),
1162
+ };
1163
+ this.cosmoses.push(restoredCosmos);
1164
+ return restoredCosmos;
1165
+ }
1166
+
1167
+ return undefined;
1168
+ }
1169
+
1170
+ public async ensureCosmos(cosmosId: string): Promise<CosmosInfo | undefined> {
1171
+ return this.findCosmos(cosmosId);
944
1172
  }
945
1173
 
946
1174
  public setZoomState(state: 'polycosmos' | 'cosmos', cosmosId?: string): void {
@@ -971,6 +1199,11 @@ export class CosmosNavigatorComponentInstance
971
1199
  }
972
1200
 
973
1201
  private renderCurrentState(): void {
1202
+ if (this.zoomState === 'cosmos' || this.cosmoses.length > 0) {
1203
+ this.hasBigBangExploded = true;
1204
+ this.starfieldFadeAlpha = 1.0;
1205
+ }
1206
+
974
1207
  if (this.zoomState === 'polycosmos') {
975
1208
  this.clearAutoDockTimer();
976
1209
  this.el.rootEl.classList.remove('zoom-cosmos');