@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
@@ -12,11 +12,13 @@ import {
12
12
  SpaceGibRouteInfo,
13
13
  PolycosmosRouteInfo,
14
14
  CosmosRouteInfo,
15
- CodeGalaxyRouteInfo,
16
- NotesGalaxyRouteInfo,
15
+ GalaxyRouteInfo,
17
16
  RawAddrRouteInfo,
18
17
  RawTjpRouteInfo,
19
18
  } from './space-gib-router-types.mjs';
19
+ import { CosmosIbGib_V1 } from '@ibgib/core-gib/dist/cosmology/cosmos/cosmos-types.mjs';
20
+ import { IbGibRouterServiceBase, IbGibCosmosRouterServiceBase } from '@ibgib/web-gib/dist/ui/router/index.mjs';
21
+ import { getSpaceGibRouterSvc, SpaceGibRouterService } from './space-gib-router-service.mjs';
20
22
 
21
23
  await respecfully(sir, 'SpaceGibRouterHelpers specs', async () => {
22
24
 
@@ -109,121 +111,230 @@ await respecfully(sir, 'SpaceGibRouterHelpers specs', async () => {
109
111
  });
110
112
  });
111
113
 
112
- await respecfully(sir, 'Code Galaxy Routes', async () => {
113
- await ifWe(sir, 'parses /my-cosmos/code/code-1 with galaxyId', async () => {
114
- const route = parseSpaceGibRoute('/my-cosmos/code/code-1');
115
- iReckon(sir, route.kind).willEqual('code-galaxy');
116
- const cg = route as CodeGalaxyRouteInfo;
117
- iReckon(sir, cg.cosmos).willEqual('my-cosmos');
118
- iReckon(sir, cg.galaxyId).willEqual('code-1');
119
- iReckon(sir, cg.branch).willEqual(undefined);
120
- iReckon(sir, cg.filePath).willEqual(undefined);
121
- });
122
-
123
- await ifWe(sir, 'parses /my-cosmos/code/code-1/main with branch', async () => {
124
- const route = parseSpaceGibRoute('/my-cosmos/code/code-1/main');
125
- iReckon(sir, route.kind).willEqual('code-galaxy');
126
- const cg = route as CodeGalaxyRouteInfo;
127
- iReckon(sir, cg.cosmos).willEqual('my-cosmos');
128
- iReckon(sir, cg.galaxyId).willEqual('code-1');
129
- iReckon(sir, cg.branch).willEqual('main');
130
- iReckon(sir, cg.filePath).willEqual(undefined);
131
- });
132
-
133
- await ifWe(sir, 'parses /my-cosmos/code/code-1/main/src/index.ts with branch and deep filePath', async () => {
134
- const route = parseSpaceGibRoute('/my-cosmos/code/code-1/main/src/index.ts');
135
- iReckon(sir, route.kind).willEqual('code-galaxy');
136
- const cg = route as CodeGalaxyRouteInfo;
137
- iReckon(sir, cg.cosmos).willEqual('my-cosmos');
138
- iReckon(sir, cg.galaxyId).willEqual('code-1');
139
- iReckon(sir, cg.branch).willEqual('main');
140
- iReckon(sir, cg.filePath).willEqual('src/index.ts');
141
- });
142
-
143
- await ifWe(sir, 'parses /@bill/my-cosmos/code/code-1/feat-x/src/deep/nested/file.mts with tenant and deep path', async () => {
144
- const route = parseSpaceGibRoute('/@bill/my-cosmos/code/code-1/feat-x/src/deep/nested/file.mts');
145
- iReckon(sir, route.kind).willEqual('code-galaxy');
146
- const cg = route as CodeGalaxyRouteInfo;
147
- const tenant = cg.tenant;
114
+ await respecfully(sir, 'Universal Galaxy Routes (Branching / Code Archetype)', async () => {
115
+ await ifWe(sir, 'parses /my-cosmos/code-1 with galaxy', async () => {
116
+ const route = parseSpaceGibRoute('/my-cosmos/code-1');
117
+ iReckon(sir, route.kind).willEqual('galaxy');
118
+ const g = route as GalaxyRouteInfo;
119
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
120
+ iReckon(sir, g.galaxy).willEqual('code-1');
121
+ iReckon(sir, g.topology).willEqual('branching');
122
+ iReckon(sir, g.branch).willEqual(undefined);
123
+ iReckon(sir, g.filePath).willEqual(undefined);
124
+ });
125
+
126
+ await ifWe(sir, 'parses /my-cosmos/code-1/main with branch', async () => {
127
+ const route = parseSpaceGibRoute('/my-cosmos/code-1/main');
128
+ iReckon(sir, route.kind).willEqual('galaxy');
129
+ const g = route as GalaxyRouteInfo;
130
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
131
+ iReckon(sir, g.galaxy).willEqual('code-1');
132
+ iReckon(sir, g.topology).willEqual('branching');
133
+ iReckon(sir, g.branch).willEqual('main');
134
+ iReckon(sir, g.filePath).willEqual(undefined);
135
+ });
136
+
137
+ await ifWe(sir, 'parses /my-cosmos/code-1/main/src/index.ts with branch and deep filePath', async () => {
138
+ const route = parseSpaceGibRoute('/my-cosmos/code-1/main/src/index.ts');
139
+ iReckon(sir, route.kind).willEqual('galaxy');
140
+ const g = route as GalaxyRouteInfo;
141
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
142
+ iReckon(sir, g.galaxy).willEqual('code-1');
143
+ iReckon(sir, g.topology).willEqual('branching');
144
+ iReckon(sir, g.branch).willEqual('main');
145
+ iReckon(sir, g.filePath).willEqual('src/index.ts');
146
+ });
147
+
148
+ await ifWe(sir, 'parses /@bill/my-cosmos/code-1/feat-x/src/deep/nested/file.mts with tenant and deep path', async () => {
149
+ const route = parseSpaceGibRoute('/@bill/my-cosmos/code-1/feat-x/src/deep/nested/file.mts');
150
+ iReckon(sir, route.kind).willEqual('galaxy');
151
+ const g = route as GalaxyRouteInfo;
152
+ const tenant = g.tenant;
148
153
  iReckon(sir, tenant?.type).willEqual('username');
149
154
  if (tenant && tenant.type === 'username') {
150
155
  iReckon(sir, tenant.siteUsername).willEqual('bill');
151
156
  }
152
- iReckon(sir, cg.cosmos).willEqual('my-cosmos');
153
- iReckon(sir, cg.galaxyId).willEqual('code-1');
154
- iReckon(sir, cg.branch).willEqual('feat-x');
155
- iReckon(sir, cg.filePath).willEqual('src/deep/nested/file.mts');
157
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
158
+ iReckon(sir, g.galaxy).willEqual('code-1');
159
+ iReckon(sir, g.topology).willEqual('branching');
160
+ iReckon(sir, g.branch).willEqual('feat-x');
161
+ iReckon(sir, g.filePath).willEqual('src/deep/nested/file.mts');
156
162
  });
157
163
  });
158
164
 
159
- await respecfully(sir, 'Notes Galaxy Routes', async () => {
160
- await ifWe(sir, 'parses /my-cosmos/notes/notes-1 with galaxyId', async () => {
161
- const route = parseSpaceGibRoute('/my-cosmos/notes/notes-1');
162
- iReckon(sir, route.kind).willEqual('notes-galaxy');
163
- const ng = route as NotesGalaxyRouteInfo;
164
- iReckon(sir, ng.cosmos).willEqual('my-cosmos');
165
- iReckon(sir, ng.galaxyId).willEqual('notes-1');
166
- iReckon(sir, ng.topicTjp).willEqual(undefined);
167
- });
168
-
169
- await ifWe(sir, 'parses /my-cosmos/notes/notes-1/topic_abc with topicTjp', async () => {
170
- const route = parseSpaceGibRoute('/my-cosmos/notes/notes-1/topic_abc');
171
- iReckon(sir, route.kind).willEqual('notes-galaxy');
172
- const ng = route as NotesGalaxyRouteInfo;
173
- iReckon(sir, ng.cosmos).willEqual('my-cosmos');
174
- iReckon(sir, ng.galaxyId).willEqual('notes-1');
175
- iReckon(sir, ng.topicTjp).willEqual('topic_abc');
176
- });
177
-
178
- await ifWe(sir, 'parses /@bill/my-cosmos/notes/notes-1/topic_abc with tenant and topicTjp', async () => {
179
- const route = parseSpaceGibRoute('/@bill/my-cosmos/notes/notes-1/topic_abc');
180
- iReckon(sir, route.kind).willEqual('notes-galaxy');
181
- const ng = route as NotesGalaxyRouteInfo;
182
- const tenant = ng.tenant;
165
+ await respecfully(sir, 'Universal Galaxy Routes (Linear / Notes Archetype)', async () => {
166
+ await ifWe(sir, 'parses /my-cosmos/notes-1 with galaxy', async () => {
167
+ const route = parseSpaceGibRoute('/my-cosmos/notes-1');
168
+ iReckon(sir, route.kind).willEqual('galaxy');
169
+ const g = route as GalaxyRouteInfo;
170
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
171
+ iReckon(sir, g.galaxy).willEqual('notes-1');
172
+ iReckon(sir, g.topology).willEqual('linear');
173
+ iReckon(sir, g.topicTjp).willEqual(undefined);
174
+ });
175
+
176
+ await ifWe(sir, 'parses /my-cosmos/notes-1/topic_abc with topicTjp shorthand', async () => {
177
+ const route = parseSpaceGibRoute('/my-cosmos/notes-1/topic_abc');
178
+ iReckon(sir, route.kind).willEqual('galaxy');
179
+ const g = route as GalaxyRouteInfo;
180
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
181
+ iReckon(sir, g.galaxy).willEqual('notes-1');
182
+ iReckon(sir, g.topology).willEqual('linear');
183
+ iReckon(sir, g.topicTjp).willEqual('topic_abc');
184
+ });
185
+
186
+ await ifWe(sir, 'parses /@bill/my-cosmos/notes-1/topic_abc with tenant and topicTjp', async () => {
187
+ const route = parseSpaceGibRoute('/@bill/my-cosmos/notes-1/topic_abc');
188
+ iReckon(sir, route.kind).willEqual('galaxy');
189
+ const g = route as GalaxyRouteInfo;
190
+ const tenant = g.tenant;
183
191
  iReckon(sir, tenant?.type).willEqual('username');
184
192
  if (tenant && tenant.type === 'username') {
185
193
  iReckon(sir, tenant.siteUsername).willEqual('bill');
186
194
  }
187
- iReckon(sir, ng.cosmos).willEqual('my-cosmos');
188
- iReckon(sir, ng.galaxyId).willEqual('notes-1');
189
- iReckon(sir, ng.topicTjp).willEqual('topic_abc');
190
- iReckon(sir, ng.trailMode).willEqual('tjp');
191
- iReckon(sir, ng.trail?.length).willEqual(1);
192
- iReckon(sir, ng.trail?.[0]).willEqual('topic_abc');
193
- });
194
-
195
- await ifWe(sir, 'parses /@bill/my-cosmos/notes/notes-1/tjp/topic_1/reply_2/reply_3 as n-depth tjp trail', async () => {
196
- const route = parseSpaceGibRoute('/@bill/my-cosmos/notes/notes-1/tjp/topic_1/reply_2/reply_3');
197
- iReckon(sir, route.kind).willEqual('notes-galaxy');
198
- const ng = route as NotesGalaxyRouteInfo;
199
- iReckon(sir, ng.cosmos).willEqual('my-cosmos');
200
- iReckon(sir, ng.galaxyId).willEqual('notes-1');
201
- iReckon(sir, ng.trailMode).willEqual('tjp');
202
- iReckon(sir, ng.trail?.length).willEqual(3);
203
- iReckon(sir, ng.trail?.[0]).willEqual('topic_1');
204
- iReckon(sir, ng.trail?.[1]).willEqual('reply_2');
205
- iReckon(sir, ng.trail?.[2]).willEqual('reply_3');
206
- iReckon(sir, ng.topicTjp).willEqual('topic_1');
207
- });
208
-
209
- await ifWe(sir, 'parses /my-cosmos/notes/notes-1/addr/hash1/hash2 as n-depth reified addr trail', async () => {
210
- const route = parseSpaceGibRoute('/my-cosmos/notes/notes-1/addr/hash1/hash2');
211
- iReckon(sir, route.kind).willEqual('notes-galaxy');
212
- const ng = route as NotesGalaxyRouteInfo;
213
- iReckon(sir, ng.cosmos).willEqual('my-cosmos');
214
- iReckon(sir, ng.galaxyId).willEqual('notes-1');
215
- iReckon(sir, ng.trailMode).willEqual('addr');
216
- iReckon(sir, ng.trail?.length).willEqual(2);
217
- iReckon(sir, ng.trail?.[0]).willEqual('hash1');
218
- iReckon(sir, ng.trail?.[1]).willEqual('hash2');
195
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
196
+ iReckon(sir, g.galaxy).willEqual('notes-1');
197
+ iReckon(sir, g.topology).willEqual('linear');
198
+ iReckon(sir, g.topicTjp).willEqual('topic_abc');
199
+ iReckon(sir, g.trailMode).willEqual('tjp');
200
+ iReckon(sir, g.trail?.length).willEqual(1);
201
+ iReckon(sir, g.trail?.[0]).willEqual('topic_abc');
202
+ });
203
+
204
+ await ifWe(sir, 'parses /@bill/my-cosmos/notes-1/tjp/topic_1/reply_2/reply_3 as n-depth tjp trail', async () => {
205
+ const route = parseSpaceGibRoute('/@bill/my-cosmos/notes-1/tjp/topic_1/reply_2/reply_3');
206
+ iReckon(sir, route.kind).willEqual('galaxy');
207
+ const g = route as GalaxyRouteInfo;
208
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
209
+ iReckon(sir, g.galaxy).willEqual('notes-1');
210
+ iReckon(sir, g.topology).willEqual('linear');
211
+ iReckon(sir, g.trailMode).willEqual('tjp');
212
+ iReckon(sir, g.trail?.length).willEqual(3);
213
+ iReckon(sir, g.trail?.[0]).willEqual('topic_1');
214
+ iReckon(sir, g.trail?.[1]).willEqual('reply_2');
215
+ iReckon(sir, g.trail?.[2]).willEqual('reply_3');
216
+ iReckon(sir, g.topicTjp).willEqual('reply_3');
217
+ });
218
+
219
+ await ifWe(sir, 'parses /my-cosmos/notes-1/addr/hash1/hash2 as n-depth reified addr trail', async () => {
220
+ const route = parseSpaceGibRoute('/my-cosmos/notes-1/addr/hash1/hash2');
221
+ iReckon(sir, route.kind).willEqual('galaxy');
222
+ const g = route as GalaxyRouteInfo;
223
+ iReckon(sir, g.cosmos).willEqual('my-cosmos');
224
+ iReckon(sir, g.galaxy).willEqual('notes-1');
225
+ iReckon(sir, g.topology).willEqual('linear');
226
+ iReckon(sir, g.trailMode).willEqual('addr');
227
+ iReckon(sir, g.trail?.length).willEqual(2);
228
+ iReckon(sir, g.trail?.[0]).willEqual('hash1');
229
+ iReckon(sir, g.trail?.[1]).willEqual('hash2');
219
230
  });
220
231
 
221
232
  await ifWe(sir, 'parses query params for right-panel inspector and lenses', async () => {
222
- const route = parseSpaceGibRoute('/@bill/my-cosmos/notes/notes-1/tjp/topic_1?inspect=src%2Findex.ts%23L10&lens=issues');
223
- iReckon(sir, route.kind).willEqual('notes-galaxy');
224
- const ng = route as NotesGalaxyRouteInfo;
225
- iReckon(sir, ng.query?.inspect).willEqual('src/index.ts#L10');
226
- iReckon(sir, ng.query?.lens).willEqual('issues');
233
+ const route = parseSpaceGibRoute('/@bill/my-cosmos/notes-1/tjp/topic_1?inspect=src%2Findex.ts%23L10&lens=issues');
234
+ iReckon(sir, route.kind).willEqual('galaxy');
235
+ const g = route as GalaxyRouteInfo;
236
+ iReckon(sir, g.query?.inspect).willEqual('src/index.ts#L10');
237
+ iReckon(sir, g.query?.lens).willEqual('issues');
238
+ });
239
+ });
240
+
241
+ await respecfully(sir, 'Fail-Fast Legacy Route Rejection', async () => {
242
+ await ifWe(sir, 'rejects obsolete /code/ intermediate segment', async () => {
243
+ let threw = false;
244
+ let errorMsg = '';
245
+ try {
246
+ parseSpaceGibRoute('/my-cosmos/code/code-1');
247
+ } catch (e: any) {
248
+ threw = true;
249
+ errorMsg = e.message;
250
+ }
251
+ iReckon(sir, threw).willEqual(true);
252
+ iReckon(sir, errorMsg.includes('Legacy route rejected')).willEqual(true);
253
+ iReckon(sir, errorMsg.includes('FAIL FAST')).willEqual(true);
254
+ });
255
+
256
+ await ifWe(sir, 'rejects obsolete /notes/ intermediate segment', async () => {
257
+ let threw = false;
258
+ let errorMsg = '';
259
+ try {
260
+ parseSpaceGibRoute('/my-cosmos/notes/notes-1');
261
+ } catch (e: any) {
262
+ threw = true;
263
+ errorMsg = e.message;
264
+ }
265
+ iReckon(sir, threw).willEqual(true);
266
+ iReckon(sir, errorMsg.includes('Legacy route rejected')).willEqual(true);
267
+ iReckon(sir, errorMsg.includes('FAIL FAST')).willEqual(true);
268
+ });
269
+
270
+ await ifWe(sir, 'rejects tenant-prefixed legacy /code/ route', async () => {
271
+ let threw = false;
272
+ let errorMsg = '';
273
+ try {
274
+ parseSpaceGibRoute('/@bill/my-cosmos/code/code-1/main');
275
+ } catch (e: any) {
276
+ threw = true;
277
+ errorMsg = e.message;
278
+ }
279
+ iReckon(sir, threw).willEqual(true);
280
+ iReckon(sir, errorMsg.includes('Legacy route rejected')).willEqual(true);
281
+ });
282
+ });
283
+
284
+ await respecfully(sir, 'Option B: Cosmos Manifest Policy Retrieval', async () => {
285
+ const mockCosmos: CosmosIbGib_V1 = {
286
+ ib: 'cosmos mock',
287
+ gib: 'gib_mock',
288
+ data: {
289
+ cosmosName: 'custom-cosmos',
290
+ uuid: 'u-1',
291
+ timestamp: '2026-09-18T00:00:00Z',
292
+ galaxies: {
293
+ 'custom-canvas': {
294
+ galaxyName: 'custom-canvas',
295
+ discriminator: 'canvas',
296
+ policy: {
297
+ role: 'intrinsic',
298
+ topology: 'branching',
299
+ storageMode: 'text',
300
+ },
301
+ },
302
+ 'custom-chat': {
303
+ galaxyName: 'custom-chat',
304
+ discriminator: 'chat',
305
+ policy: {
306
+ role: 'extrinsic',
307
+ topology: 'linear',
308
+ storageMode: 'text',
309
+ },
310
+ },
311
+ },
312
+ },
313
+ rel8ns: {},
314
+ };
315
+
316
+ await ifWe(sir, 'resolves custom branching galaxy from cosmos manifest', async () => {
317
+ const route = parseSpaceGibRoute('/custom-cosmos/custom-canvas/branchA/canvas.json', { cosmosManifest: mockCosmos });
318
+ iReckon(sir, route.kind).willEqual('galaxy');
319
+ const g = route as GalaxyRouteInfo;
320
+ iReckon(sir, g.galaxy).willEqual('custom-canvas');
321
+ iReckon(sir, g.topology).willEqual('branching');
322
+ iReckon(sir, g.discriminator).willEqual('canvas');
323
+ iReckon(sir, g.branch).willEqual('branchA');
324
+ iReckon(sir, g.filePath).willEqual('canvas.json');
325
+ });
326
+
327
+ await ifWe(sir, 'resolves custom linear galaxy from cosmos manifest', async () => {
328
+ const route = parseSpaceGibRoute('/custom-cosmos/custom-chat/tjp/topicA/msg1', { cosmosManifest: mockCosmos });
329
+ iReckon(sir, route.kind).willEqual('galaxy');
330
+ const g = route as GalaxyRouteInfo;
331
+ iReckon(sir, g.galaxy).willEqual('custom-chat');
332
+ iReckon(sir, g.topology).willEqual('linear');
333
+ iReckon(sir, g.discriminator).willEqual('chat');
334
+ iReckon(sir, g.trailMode).willEqual('tjp');
335
+ iReckon(sir, g.trail?.length).willEqual(2);
336
+ iReckon(sir, g.trail?.[0]).willEqual('topicA');
337
+ iReckon(sir, g.trail?.[1]).willEqual('msg1');
227
338
  });
228
339
  });
229
340
 
@@ -299,16 +410,16 @@ await respecfully(sir, 'SpaceGibRouterHelpers specs', async () => {
299
410
  { kind: 'polycosmos', tenant: { type: 'keystone', keystoneTjp: 'tjp_genesis' } },
300
411
  { kind: 'cosmos', cosmos: 'cosmos-alpha' },
301
412
  { kind: 'cosmos', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'cosmos-alpha' },
302
- { kind: 'code-galaxy', cosmos: 'my-cosmos', galaxyId: 'code-1' },
303
- { kind: 'code-galaxy', cosmos: 'my-cosmos', galaxyId: 'code-1', branch: 'main' },
304
- { kind: 'code-galaxy', cosmos: 'my-cosmos', galaxyId: 'code-1', branch: 'main', filePath: 'src/core/index.ts' },
305
- { kind: 'code-galaxy', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', galaxyId: 'code-1', branch: 'dev', filePath: 'lib/utils.ts' },
306
- { kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1' },
307
- { kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 'topic_welcome', trailMode: 'tjp', trail: ['topic_welcome'] },
308
- { kind: 'notes-galaxy', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 'topic_welcome', trailMode: 'tjp', trail: ['topic_welcome'] },
309
- { kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 't1', trailMode: 'tjp', trail: ['t1', 't2', 't3'] },
310
- { kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', trailMode: 'addr', trail: ['a1', 'a2'] },
311
- { kind: 'notes-galaxy', cosmos: 'my-cosmos', galaxyId: 'notes-1', topicTjp: 't1', trailMode: 'tjp', trail: ['t1'], query: { inspect: 'src/index.ts#L10', lens: 'issues' } },
413
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'code-1', topology: 'branching' },
414
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'code-1', topology: 'branching', branch: 'main' },
415
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'code-1', topology: 'branching', branch: 'main', filePath: 'src/core/index.ts' },
416
+ { kind: 'galaxy', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', galaxy: 'code-1', topology: 'branching', branch: 'dev', filePath: 'lib/utils.ts' },
417
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'notes-1', topology: 'linear' },
418
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'notes-1', topology: 'linear', topicTjp: 'topic_welcome', trailMode: 'tjp', trail: ['topic_welcome'] },
419
+ { kind: 'galaxy', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', galaxy: 'notes-1', topology: 'linear', topicTjp: 'topic_welcome', trailMode: 'tjp', trail: ['topic_welcome'] },
420
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'notes-1', topology: 'linear', topicTjp: 't3', trailMode: 'tjp', trail: ['t1', 't2', 't3'] },
421
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'notes-1', topology: 'linear', trailMode: 'addr', trail: ['a1', 'a2'] },
422
+ { kind: 'galaxy', cosmos: 'my-cosmos', galaxy: 'notes-1', topology: 'linear', topicTjp: 't1', trailMode: 'tjp', trail: ['t1'], query: { inspect: 'src/index.ts#L10', lens: 'issues' } },
312
423
  { kind: 'raw-addr', cosmos: 'my-cosmos', spaceId: 'branch_space_main', ibGibAddr: 'comment hello world^gib_1' },
313
424
  { kind: 'raw-addr', tenant: { type: 'username', siteUsername: 'bill' }, cosmos: 'my-cosmos', spaceId: 'branch_space_main', ibGibAddr: 'comment hello world^gib_1' },
314
425
  { kind: 'raw-tjp', cosmos: 'my-cosmos', spaceId: 'branch_space_main', tjpAddr: 'tjp_dna_123' },
@@ -327,15 +438,15 @@ await respecfully(sir, 'SpaceGibRouterHelpers specs', async () => {
327
438
 
328
439
  await respecfully(sir, 'Edge Cases & Robustness', async () => {
329
440
  await ifWe(sir, 'handles trailing slashes', async () => {
330
- const route = parseSpaceGibRoute('/my-cosmos/code/code-1/');
331
- iReckon(sir, route.kind).willEqual('code-galaxy');
332
- iReckon(sir, (route as CodeGalaxyRouteInfo).galaxyId).willEqual('code-1');
441
+ const route = parseSpaceGibRoute('/my-cosmos/code-1/');
442
+ iReckon(sir, route.kind).willEqual('galaxy');
443
+ iReckon(sir, (route as GalaxyRouteInfo).galaxy).willEqual('code-1');
333
444
  });
334
445
 
335
446
  await ifWe(sir, 'strips query parameters', async () => {
336
- const route = parseSpaceGibRoute('/my-cosmos/code/code-1?branch=main&debug=true');
337
- iReckon(sir, route.kind).willEqual('code-galaxy');
338
- iReckon(sir, (route as CodeGalaxyRouteInfo).galaxyId).willEqual('code-1');
447
+ const route = parseSpaceGibRoute('/my-cosmos/code-1?branch=main&debug=true');
448
+ iReckon(sir, route.kind).willEqual('galaxy');
449
+ iReckon(sir, (route as GalaxyRouteInfo).galaxy).willEqual('code-1');
339
450
  });
340
451
 
341
452
  await ifWe(sir, 'strips hash fragments', async () => {
@@ -345,9 +456,74 @@ await respecfully(sir, 'SpaceGibRouterHelpers specs', async () => {
345
456
  });
346
457
 
347
458
  await ifWe(sir, 'handles multiple consecutive slashes gracefully', async () => {
348
- const route = parseSpaceGibRoute('///my-cosmos///code///code-1///');
349
- iReckon(sir, route.kind).willEqual('code-galaxy');
350
- iReckon(sir, (route as CodeGalaxyRouteInfo).galaxyId).willEqual('code-1');
459
+ const route = parseSpaceGibRoute('///my-cosmos///code-1///');
460
+ iReckon(sir, route.kind).willEqual('galaxy');
461
+ iReckon(sir, (route as GalaxyRouteInfo).galaxy).willEqual('code-1');
462
+ });
463
+ });
464
+
465
+ await respecfully(sir, 'SpaceGibRouterService Subclass Specs', async () => {
466
+ await ifWeMight(sir, 'provides singleton subclassing IbGibCosmosRouterServiceBase and IbGibRouterServiceBase', async () => {
467
+ const router = getSpaceGibRouterSvc();
468
+ iReckon(sir, router instanceof SpaceGibRouterService).isGonnaBe(true);
469
+ iReckon(sir, router instanceof IbGibRouterServiceBase).isGonnaBe(true);
470
+ iReckon(sir, router instanceof IbGibCosmosRouterServiceBase).isGonnaBe(true);
471
+ });
472
+
473
+ await ifWeMight(sir, 'parses, formats and navigates cleanly via cosmos base class', async () => {
474
+ const router = getSpaceGibRouterSvc();
475
+ const received: SpaceGibRouteInfo[] = [];
476
+ const unsubscribe = router.subscribe(async (r) => {
477
+ received.push(r);
478
+ });
479
+
480
+ await router.navigate({
481
+ kind: 'galaxy',
482
+ cosmos: 'test-cosmos',
483
+ galaxy: 'notes-1',
484
+ topology: 'linear',
485
+ });
486
+
487
+ iReckon(sir, router.getCurrentRoute()?.kind).willEqual('galaxy');
488
+ iReckon(sir, (router.getCurrentRoute() as GalaxyRouteInfo).galaxy).willEqual('notes-1');
489
+ iReckon(sir, received.length > 0).isGonnaBe(true);
490
+
491
+ unsubscribe();
492
+ });
493
+
494
+ await ifWeMight(sir, 'auto-loads galaxy policy from manifest registered on router', async () => {
495
+ const router = getSpaceGibRouterSvc();
496
+ const mockManifest: CosmosIbGib_V1 = {
497
+ ib: 'cosmos test-auto-cosmos',
498
+ data: {
499
+ cosmosName: 'test-auto-cosmos',
500
+ galaxies: {
501
+ 'auto-canvas': {
502
+ galaxyName: 'auto-canvas',
503
+ discriminator: 'canvas',
504
+ policy: {
505
+ topology: 'branching',
506
+ role: 'intrinsic',
507
+ storageMode: 'text',
508
+ },
509
+ },
510
+ },
511
+ },
512
+ rel8ns: {},
513
+ };
514
+ router.setCosmosManifest('test-auto-cosmos', mockManifest);
515
+
516
+ const received: SpaceGibRouteInfo[] = [];
517
+ const unsubscribe = router.subscribe((r) => { received.push(r); });
518
+
519
+ await router.navigatePath('/test-auto-cosmos/auto-canvas/branchX/art.png');
520
+
521
+ const current = router.getCurrentRoute() as GalaxyRouteInfo;
522
+ iReckon(sir, current.kind).willEqual('galaxy');
523
+ iReckon(sir, current.topology).willEqual('branching');
524
+ iReckon(sir, current.discriminator).willEqual('canvas');
525
+
526
+ unsubscribe();
351
527
  });
352
528
  });
353
529
  });