@ibgib/space-gib 0.0.34 → 0.0.36

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 (54) hide show
  1. package/dist/client/bootstrap.mjs +1 -1
  2. package/dist/client/{chunk-25PXC4HP.mjs → chunk-5DTAUY3E.mjs} +1586 -464
  3. package/dist/client/chunk-J7X3XTAI.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/css/tutorial.css +327 -0
  7. package/dist/client/index.html +6 -0
  8. package/dist/client/index.mjs +22 -45
  9. package/dist/client/privacy.html +22 -22
  10. package/dist/client/script.mjs +1 -1
  11. package/dist/client/style.css +1 -0
  12. package/dist/server/server.mjs +3 -3
  13. package/package.json +6 -6
  14. package/src/client/AUTO-GENERATED-version.mts +1 -1
  15. package/src/client/cosmos/seed-cosmos-workspace.mts +20 -6
  16. package/src/client/css/activity-bar.css +21 -3
  17. package/src/client/css/layout.css +126 -5
  18. package/src/client/css/tutorial.css +327 -0
  19. package/src/client/dev-tools/vcs-workspace.mts +4 -4
  20. package/src/client/index.html +6 -0
  21. package/src/client/privacy.html +22 -22
  22. package/src/client/style.css +1 -0
  23. package/src/client/ui/component/changes/changes.css +413 -0
  24. package/src/client/ui/component/changes/changes.html +37 -0
  25. package/src/client/ui/component/changes/changes.mts +766 -0
  26. package/src/client/ui/component/changes/index.mts +9 -0
  27. package/src/client/ui/component/chat-view/chat-view.html +6 -58
  28. package/src/client/ui/component/chat-view/chat-view.mts +13 -26
  29. package/src/client/ui/component/clone/clone.mts +67 -39
  30. package/src/client/ui/component/code-editor/code-editor.css +91 -9
  31. package/src/client/ui/component/code-editor/code-editor.html +58 -45
  32. package/src/client/ui/component/code-editor/code-editor.mts +265 -49
  33. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +1 -1
  34. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +5 -10
  35. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +328 -64
  36. package/src/client/ui/component/file-explorer/file-explorer.css +475 -11
  37. package/src/client/ui/component/file-explorer/file-explorer.html +45 -65
  38. package/src/client/ui/component/file-explorer/file-explorer.mts +1164 -98
  39. package/src/client/ui/component/nested-chat/chat/chat.mts +5 -90
  40. package/src/client/ui/component/nested-chat/nested-chat.mts +10 -8
  41. package/src/client/ui/component/timeline/timeline.css +16 -1
  42. package/src/client/ui/component/timeline/timeline.mts +37 -93
  43. package/src/client/ui/component/tutorial/index.mts +9 -0
  44. package/src/client/ui/component/tutorial/scripts/pitch-tour-script.mts +265 -0
  45. package/src/client/ui/component/tutorial/tutorial-controller.mts +622 -0
  46. package/src/client/ui/component/tutorial/tutorial-types.mts +45 -0
  47. package/src/client/ui/component/tutorial/tutorial.css +260 -0
  48. package/src/client/ui/router/space-gib-router-helpers.mts +33 -233
  49. package/src/client/ui/router/space-gib-router-helpers.respec.mts +298 -122
  50. package/src/client/ui/router/space-gib-router-service.mts +28 -151
  51. package/src/client/ui/router/space-gib-router-types.mts +32 -76
  52. package/src/client/ui/shell/cosmic-big-bang.mts +12 -3
  53. package/src/client/ui/shell/space-gib-shell-service.mts +715 -143
  54. 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,125 @@ 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
+ /**
582
+ * Programmatically launches the Code Galaxy satellite without a prompt modal.
583
+ * Ideal for automated tutorials, tours, and scripted actions.
584
+ */
585
+ public async launchCodeGalaxyProgrammatic(galaxyName: string = 'code-1'): Promise<AttachedSpace | null> {
586
+ let activeCosmos = this.getActiveCosmos();
587
+ if (!activeCosmos && this.cosmoses.length > 0) {
588
+ this.selectCosmos(this.cosmoses[0].id);
589
+ activeCosmos = this.getActiveCosmos();
590
+ }
591
+ if (!activeCosmos) return null;
592
+
593
+ const sourceBtn = this.el.btnSatCodeEl || this.el.btnNodeSuperspaceEl;
594
+ const sourceWrapper = (sourceBtn?.closest('.satellite-wrapper') as HTMLElement) || sourceBtn;
595
+
596
+ let space = activeCosmos.spaces.find(s => s.id === galaxyName || s.name === galaxyName);
597
+ if (!space) {
598
+ space = await this.createAndAttachGalaxy({
599
+ cosmosId: activeCosmos.id,
600
+ galaxyName,
601
+ discriminator: GalaxyPresetType.code,
602
+ skipEvent: true,
603
+ });
604
+ }
605
+
606
+ if (space) {
607
+ return this.handleSpaceClick(space, sourceBtn, sourceWrapper);
608
+ }
609
+ return null;
610
+ }
611
+
612
+ public async handleSatTextClick(): Promise<void> {
613
+ const activeCosmos = this.getActiveCosmos();
614
+ if (!activeCosmos) return;
615
+
616
+ const count = activeCosmos.spaces.filter(s => s.type === 'text' || s.type === GalaxyPresetType.notes).length;
617
+ const defaultName = count === 0 ? 'notes-1' : `notes-${count + 1}`;
618
+ const galaxyName = await promptForText({
619
+ title: 'Create Notes Galaxy',
620
+ msg: `Name of the new Notes Galaxy for [${activeCosmos.name}]:`,
621
+ defaultValue: defaultName,
622
+ cancelable: true,
623
+ });
624
+
625
+ if (!galaxyName) return;
626
+
627
+ const sourceBtn = this.el.btnSatTextEl || this.el.btnNodeSuperspaceEl;
628
+ const sourceWrapper = (sourceBtn?.closest('.satellite-wrapper') as HTMLElement) || sourceBtn;
629
+
630
+ let space = activeCosmos.spaces.find(s => s.id === galaxyName || s.name === galaxyName);
631
+ if (!space) {
632
+ space = await this.createAndAttachGalaxy({
633
+ cosmosId: activeCosmos.id,
634
+ galaxyName,
635
+ discriminator: GalaxyPresetType.notes,
636
+ skipEvent: true,
637
+ });
638
+ }
639
+
640
+ if (space) {
641
+ this.handleSpaceClick(space, sourceBtn, sourceWrapper);
642
+ }
525
643
  }
526
644
 
527
645
  private launchProjectile({
@@ -818,7 +936,11 @@ export class CosmosNavigatorComponentInstance
818
936
  }
819
937
  }
820
938
 
821
- public handleSpaceClick(type: 'code' | 'text'): AttachedSpace | null {
939
+ public handleSpaceClick(
940
+ typeOrSpace: AttachedSpace | 'code' | 'text',
941
+ sourceBtn?: HTMLElement,
942
+ sourceWrapper?: HTMLElement
943
+ ): AttachedSpace | null {
822
944
  if (!this.activeCosmosId) return null;
823
945
  const activeCosmos = this.getActiveCosmos();
824
946
  if (!activeCosmos) { return null; }
@@ -828,9 +950,12 @@ export class CosmosNavigatorComponentInstance
828
950
  this.initialOnboardingDone = true;
829
951
  this.isSpaceLaunching = true;
830
952
 
953
+ const type = typeof typeOrSpace === 'string' ? typeOrSpace : typeOrSpace.type;
954
+ const space = typeof typeOrSpace === 'object' ? typeOrSpace : undefined;
955
+
831
956
  const count = activeCosmos.spaces.filter(s => s.type === type).length;
832
957
  const existingSpacesCount = activeCosmos.spaces.length;
833
- const newSpace: AttachedSpace = {
958
+ const newSpace: AttachedSpace = space || {
834
959
  id: `${type}-space-${count + 1}-${Date.now()}`,
835
960
  type,
836
961
  name: type === 'code' ? `Code Space ${count + 1}` : `Text Space ${count + 1}`,
@@ -838,11 +963,13 @@ export class CosmosNavigatorComponentInstance
838
963
  icon: type === 'code' ? '</>' : '📝',
839
964
  };
840
965
 
841
- activeCosmos.spaces.push(newSpace);
842
- this.saveState();
966
+ if (!activeCosmos.spaces.some(s => s.id === newSpace.id)) {
967
+ activeCosmos.spaces.push(newSpace);
968
+ this.saveState();
969
+ }
843
970
 
844
- const sourceBtnEl = type === 'code' ? this.el.btnSatCodeEl : this.el.btnSatTextEl;
845
- const sourceWrapperEl = (sourceBtnEl?.closest('.satellite-wrapper') as HTMLElement) || sourceBtnEl;
971
+ const sourceBtnEl = sourceBtn || (this.el.superspaceSatellitesEl?.querySelector('.satellite-node-btn') as HTMLElement) || this.el.btnNodeSuperspaceEl;
972
+ const sourceWrapperEl = sourceWrapper || (sourceBtnEl?.closest('.satellite-wrapper') as HTMLElement) || sourceBtnEl;
846
973
 
847
974
  const headerH = document.getElementById('main-header')?.getBoundingClientRect().height || 60;
848
975
  const targetTop = headerH + 128 + (existingSpacesCount * 50);
@@ -878,8 +1005,8 @@ export class CosmosNavigatorComponentInstance
878
1005
  sourceWrapperEl,
879
1006
  sourceBtnEl,
880
1007
  fallbackTarget,
881
- emoji: type === 'code' ? '</>' : '📝',
882
- projectileType: type,
1008
+ emoji: newSpace.icon || (type === 'code' ? '</>' : '📝'),
1009
+ projectileType: type === 'code' ? 'code' : 'text',
883
1010
  duration: 1400,
884
1011
  onDocked: () => {
885
1012
  this.isSpaceLaunching = false;
@@ -900,21 +1027,134 @@ export class CosmosNavigatorComponentInstance
900
1027
  return newSpace;
901
1028
  }
902
1029
 
903
- public createCosmos(name?: string, isTemporary?: boolean): CosmosInfo {
904
- const id = `cosmos-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
1030
+ public async createAndAttachGalaxy({
1031
+ cosmosId,
1032
+ galaxyName,
1033
+ discriminator,
1034
+ skipEvent = false,
1035
+ }: {
1036
+ cosmosId?: string;
1037
+ galaxyName: string;
1038
+ discriminator?: GalaxyPresetType | 'code' | 'notes';
1039
+ skipEvent?: boolean;
1040
+ }): Promise<AttachedSpace | undefined> {
1041
+ const cosmos = cosmosId ? this.cosmoses.find(c => c.id === cosmosId) : this.getActiveCosmos();
1042
+ if (!cosmos) return undefined;
1043
+
1044
+ try {
1045
+ const { metaspace, space } = await getPlaygroundMetaspaceAndSpace();
1046
+ const spaceId = space?.ib ? getSpaceIdFromIb(space.ib) || 'temp_space' : 'temp_space';
1047
+
1048
+ // 1. Fetch Cosmos IbGib
1049
+ let cosmosIbGib: CosmosIbGib_V1 | undefined;
1050
+ if (cosmos.ibGibAddr) {
1051
+ cosmosIbGib = await getIbGibFromSpace<CosmosIbGib_V1>({ addr: cosmos.ibGibAddr, space });
1052
+ }
1053
+ if (!cosmosIbGib) {
1054
+ // Try by name in router cache
1055
+ const router = getSpaceGibRouterSvc();
1056
+ cosmosIbGib = router.cosmosManifestCache?.get(cosmos.name);
1057
+ }
1058
+ if (!cosmosIbGib) {
1059
+ throw new Error(`cosmosIbGib not found for cosmos "${cosmos.name}" (addr: ${cosmos.ibGibAddr || 'none'}). (E: 661ab8c2b7b8800be247f588b17ee726)`);
1060
+ }
1061
+
1062
+ // 2. Create Galaxy IbGib
1063
+ let galaxyIbGib: GalaxyIbGib_V1;
1064
+ const isCode = discriminator === GalaxyPresetType.code;
1065
+ if (isCode) {
1066
+ const initRes = await executeVcsInit({
1067
+ metaspace,
1068
+ localSpace: space,
1069
+ galaxyName,
1070
+ branchName: 'main',
1071
+ });
1072
+ galaxyIbGib = initRes.galaxyIbGib;
1073
+ } else {
1074
+ galaxyIbGib = await createGalaxyIbGib({
1075
+ galaxyName,
1076
+ discriminator: GalaxyPresetType.notes,
1077
+ space,
1078
+ metaspace,
1079
+ });
1080
+ }
1081
+
1082
+ // 3. Add galaxy to cosmos manifest
1083
+ const sqGalaxyAddr = getSpaceQualifiedIbGibAddr({
1084
+ spaceId,
1085
+ ibGibAddr: getIbGibAddr({ ibGib: galaxyIbGib }),
1086
+ });
1087
+ cosmosIbGib = await addGalaxyToCosmos({
1088
+ cosmosIbGib,
1089
+ sqGalaxyAddr,
1090
+ galaxyIbGib,
1091
+ space,
1092
+ metaspace,
1093
+ });
1094
+
1095
+ // 4. Update cosmos ibGibAddr and router manifest cache
1096
+ cosmos.ibGibAddr = getIbGibAddr({ ibGib: cosmosIbGib });
1097
+ getSpaceGibRouterSvc().setCosmosManifest(cosmos.name, cosmosIbGib);
1098
+
1099
+ // 5. Update local cosmos state
1100
+ const newSpace: AttachedSpace = {
1101
+ id: galaxyName,
1102
+ type: isCode ? GalaxyPresetType.code : GalaxyPresetType.notes,
1103
+ name: galaxyName,
1104
+ shortLabel: galaxyName,
1105
+ icon: isCode ? '</>' : '📝',
1106
+ };
1107
+ if (!cosmos.spaces.some(s => s.id === galaxyName)) {
1108
+ cosmos.spaces.push(newSpace);
1109
+ }
1110
+ this.saveState();
1111
+
1112
+ // 7. Dispatch space added event if not skipped (e.g. handleSpaceClick dispatches on projectile dock)
1113
+ if (!skipEvent) {
1114
+ this.dispatchEvent(new CustomEvent('space-gib-space-added', {
1115
+ detail: {
1116
+ cosmosId: cosmos.id,
1117
+ space: newSpace,
1118
+ cosmos,
1119
+ },
1120
+ bubbles: true,
1121
+ composed: true,
1122
+ }));
1123
+ }
1124
+
1125
+ return newSpace;
1126
+ } catch (err) {
1127
+ console.error(`${this.lc} Failed to create and attach galaxy: ${extractErrorMsg(err)}`);
1128
+ throw err;
1129
+ }
1130
+ }
1131
+
1132
+ public async createCosmos(name?: string, isTemporary?: boolean): Promise<CosmosInfo> {
905
1133
  const cosmosName = name || `cosmos-${this.cosmoses.length + 1}`;
906
1134
  const hasIdentity = Boolean((globalThis as any).ibgib?.identity?.domainIdentity);
907
1135
  const temp = isTemporary !== undefined ? isTemporary : !hasIdentity;
1136
+
1137
+ const { metaspace, space } = await getPlaygroundMetaspaceAndSpace();
1138
+ const cosmosIbGib = await createCosmosIbGib({
1139
+ cosmosName,
1140
+ description: `${cosmosName} Cosmos`,
1141
+ space,
1142
+ metaspace,
1143
+ });
1144
+ const ibGibAddr = getIbGibAddr({ ibGib: cosmosIbGib });
1145
+ getSpaceGibRouterSvc().setCosmosManifest(cosmosName, cosmosIbGib);
1146
+
908
1147
  const newCosmos: CosmosInfo = {
909
- id,
1148
+ id: cosmosName,
910
1149
  name: cosmosName,
1150
+ ibGibAddr,
911
1151
  isTemporary: temp,
912
1152
  spaces: [],
913
1153
  createdAt: Date.now(),
914
1154
  };
915
1155
 
916
1156
  this.cosmoses.push(newCosmos);
917
- this.activeCosmosId = id;
1157
+ this.activeCosmosId = newCosmos.id;
918
1158
  this.saveState();
919
1159
  return newCosmos;
920
1160
  }
@@ -928,11 +1168,11 @@ export class CosmosNavigatorComponentInstance
928
1168
  this.setZoomState('cosmos', cosmos.id);
929
1169
  }
930
1170
 
931
- public async ensureCosmos(cosmosId: string): Promise<CosmosInfo> {
932
- let existing = this.cosmoses.find(c => c.id === cosmosId || c.name === cosmosId);
1171
+ public async findCosmos(cosmosNameOrId: string): Promise<CosmosInfo | undefined> {
1172
+ let existing = this.cosmoses.find(c => c.id === cosmosNameOrId || c.name === cosmosNameOrId);
933
1173
  if (existing) { return existing; }
934
1174
 
935
- if (cosmosId === 'welcome-cosmos' || cosmosId === 'my-cosmos') {
1175
+ if (cosmosNameOrId === 'welcome-cosmos') {
936
1176
  const seeded = await seedInMemoryCosmosWorkspace();
937
1177
  if (!this.cosmoses.some(c => c.id === seeded.id)) {
938
1178
  this.cosmoses.push(seeded);
@@ -940,7 +1180,26 @@ export class CosmosNavigatorComponentInstance
940
1180
  return seeded;
941
1181
  }
942
1182
 
943
- return this.createCosmos(cosmosId);
1183
+ const router = getSpaceGibRouterSvc();
1184
+ const cachedManifest = router.getCachedCosmosManifest(cosmosNameOrId);
1185
+ if (cachedManifest) {
1186
+ const ibGibAddr = getIbGibAddr({ ibGib: cachedManifest });
1187
+ const restoredCosmos: CosmosInfo = {
1188
+ id: cosmosNameOrId,
1189
+ name: cosmosNameOrId,
1190
+ ibGibAddr,
1191
+ spaces: [],
1192
+ createdAt: Date.now(),
1193
+ };
1194
+ this.cosmoses.push(restoredCosmos);
1195
+ return restoredCosmos;
1196
+ }
1197
+
1198
+ return undefined;
1199
+ }
1200
+
1201
+ public async ensureCosmos(cosmosId: string): Promise<CosmosInfo | undefined> {
1202
+ return this.findCosmos(cosmosId);
944
1203
  }
945
1204
 
946
1205
  public setZoomState(state: 'polycosmos' | 'cosmos', cosmosId?: string): void {
@@ -971,6 +1230,11 @@ export class CosmosNavigatorComponentInstance
971
1230
  }
972
1231
 
973
1232
  private renderCurrentState(): void {
1233
+ if (this.zoomState === 'cosmos' || this.cosmoses.length > 0) {
1234
+ this.hasBigBangExploded = true;
1235
+ this.starfieldFadeAlpha = 1.0;
1236
+ }
1237
+
974
1238
  if (this.zoomState === 'polycosmos') {
975
1239
  this.clearAutoDockTimer();
976
1240
  this.el.rootEl.classList.remove('zoom-cosmos');