@ibgib/web-gib 0.0.52 → 0.0.55

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 (150) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  3. package/dist/AUTO-GENERATED-version.mjs +1 -1
  4. package/dist/api/commands/chat/hello-world.mjs.map +1 -1
  5. package/dist/api/commands/command-constants.d.mts +4 -4
  6. package/dist/api/commands/command-constants.d.mts.map +1 -1
  7. package/dist/api/commands/command-service-v1.d.mts.map +1 -1
  8. package/dist/api/commands/command-service-v1.mjs.map +1 -1
  9. package/dist/api/commands/ibgib/get-ibgibs.d.mts.map +1 -1
  10. package/dist/api/commands/ibgib/get-ibgibs.mjs.map +1 -1
  11. package/dist/api/ibgib-api-bridge.d.mts +81 -0
  12. package/dist/api/ibgib-api-bridge.d.mts.map +1 -0
  13. package/dist/api/ibgib-api-bridge.mjs +259 -0
  14. package/dist/api/ibgib-api-bridge.mjs.map +1 -0
  15. package/dist/app-bootstrap/init-orchestration.d.mts +1 -1
  16. package/dist/app-bootstrap/init-orchestration.d.mts.map +1 -1
  17. package/dist/app-bootstrap/init-orchestration.mjs +17 -3
  18. package/dist/app-bootstrap/init-orchestration.mjs.map +1 -1
  19. package/dist/assets/fullscreen-dialog.html +18 -0
  20. package/dist/assumptions.respec.mjs.map +1 -1
  21. package/dist/common/settings/settings-constants.d.mts.map +1 -1
  22. package/dist/helpers.d.mts.map +1 -1
  23. package/dist/helpers.mjs.map +1 -1
  24. package/dist/helpers.web.d.mts.map +1 -1
  25. package/dist/helpers.web.mjs.map +1 -1
  26. package/dist/helpers.web.respec.mjs.map +1 -1
  27. package/dist/identity/keystone-sync-service.d.mts +37 -0
  28. package/dist/identity/keystone-sync-service.d.mts.map +1 -0
  29. package/dist/identity/keystone-sync-service.mjs +211 -0
  30. package/dist/identity/keystone-sync-service.mjs.map +1 -0
  31. package/dist/identity/sso/sso-custodian-service.d.mts.map +1 -1
  32. package/dist/identity/sso/sso-custodian-service.mjs.map +1 -1
  33. package/dist/identity/sso/sso-custodian-service.respec.mjs.map +1 -1
  34. package/dist/index.d.mts +17 -1
  35. package/dist/index.d.mts.map +1 -1
  36. package/dist/index.mjs +21 -26
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/storage/storage-helpers.web.mjs.map +1 -1
  39. package/dist/ui/component/common-component-styles.css +270 -0
  40. package/dist/ui/component/ibgib-component-service.d.mts.map +1 -1
  41. package/dist/ui/component/ibgib-dynamic-component-bases.d.mts.map +1 -1
  42. package/dist/ui/component/ibgib-dynamic-component-bases.mjs.map +1 -1
  43. package/dist/ui/component/identity/add-device/add-device.css +133 -0
  44. package/dist/ui/component/identity/add-device/add-device.d.mts +49 -0
  45. package/dist/ui/component/identity/add-device/add-device.d.mts.map +1 -0
  46. package/dist/ui/component/identity/add-device/add-device.html +52 -0
  47. package/dist/ui/component/identity/add-device/add-device.mjs +321 -0
  48. package/dist/ui/component/identity/add-device/add-device.mjs.map +1 -0
  49. package/dist/ui/component/identity/identity-header/identity-header.css +317 -0
  50. package/dist/ui/component/identity/identity-header/identity-header.d.mts +85 -0
  51. package/dist/ui/component/identity/identity-header/identity-header.d.mts.map +1 -0
  52. package/dist/ui/component/identity/identity-header/identity-header.html +72 -0
  53. package/dist/ui/component/identity/identity-header/identity-header.mjs +546 -0
  54. package/dist/ui/component/identity/identity-header/identity-header.mjs.map +1 -0
  55. package/dist/ui/component/identity/identity-manager/identity-manager.css +178 -0
  56. package/dist/ui/component/identity/identity-manager/identity-manager.d.mts +76 -0
  57. package/dist/ui/component/identity/identity-manager/identity-manager.d.mts.map +1 -0
  58. package/dist/ui/component/identity/identity-manager/identity-manager.html +19 -0
  59. package/dist/ui/component/identity/identity-manager/identity-manager.mjs +591 -0
  60. package/dist/ui/component/identity/identity-manager/identity-manager.mjs.map +1 -0
  61. package/dist/ui/component/identity/index.d.mts +17 -0
  62. package/dist/ui/component/identity/index.d.mts.map +1 -0
  63. package/dist/ui/component/identity/index.mjs +34 -0
  64. package/dist/ui/component/identity/index.mjs.map +1 -0
  65. package/dist/ui/component/identity/keystone-creator/keystone-creator.css +97 -0
  66. package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts +58 -0
  67. package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts.map +1 -0
  68. package/dist/ui/component/identity/keystone-creator/keystone-creator.html +51 -0
  69. package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs +410 -0
  70. package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs.map +1 -0
  71. package/dist/ui/component/identity/keystone-details/keystone-details.css +621 -0
  72. package/dist/ui/component/identity/keystone-details/keystone-details.d.mts +98 -0
  73. package/dist/ui/component/identity/keystone-details/keystone-details.d.mts.map +1 -0
  74. package/dist/ui/component/identity/keystone-details/keystone-details.html +154 -0
  75. package/dist/ui/component/identity/keystone-details/keystone-details.mjs +1377 -0
  76. package/dist/ui/component/identity/keystone-details/keystone-details.mjs.map +1 -0
  77. package/dist/ui/component/identity/keystone-scrubber/keystone-scrubber.css +46 -0
  78. package/dist/ui/component/identity/keystone-scrubber/keystone-scrubber.d.mts +64 -0
  79. package/dist/ui/component/identity/keystone-scrubber/keystone-scrubber.d.mts.map +1 -0
  80. package/dist/ui/component/identity/keystone-scrubber/keystone-scrubber.html +15 -0
  81. package/dist/ui/component/identity/keystone-scrubber/keystone-scrubber.mjs +300 -0
  82. package/dist/ui/component/identity/keystone-scrubber/keystone-scrubber.mjs.map +1 -0
  83. package/dist/ui/component/identity/remove-device/remove-device.css +118 -0
  84. package/dist/ui/component/identity/remove-device/remove-device.d.mts +50 -0
  85. package/dist/ui/component/identity/remove-device/remove-device.d.mts.map +1 -0
  86. package/dist/ui/component/identity/remove-device/remove-device.html +31 -0
  87. package/dist/ui/component/identity/remove-device/remove-device.mjs +188 -0
  88. package/dist/ui/component/identity/remove-device/remove-device.mjs.map +1 -0
  89. package/dist/ui/ui-constants.d.mts +1 -0
  90. package/dist/ui/ui-constants.d.mts.map +1 -1
  91. package/dist/ui/ui-constants.mjs +1 -0
  92. package/dist/ui/ui-constants.mjs.map +1 -1
  93. package/dist/ui/ui-types.d.mts +7 -0
  94. package/dist/ui/ui-types.d.mts.map +1 -1
  95. package/dist/witness/agent/agent-constants.d.mts.map +1 -1
  96. package/dist/witness/agent/agent-helpers.mjs.map +1 -1
  97. package/dist/witness/agent/agent-one-file.d.mts.map +1 -1
  98. package/dist/witness/agent/agent-one-file.mjs.map +1 -1
  99. package/dist/witness/agent/agents-service-v1.d.mts.map +1 -1
  100. package/dist/witness/agent/agents-service-v1.mjs.map +1 -1
  101. package/dist/witness/agent/gemini/agent-witness-gemini-v1.d.mts.map +1 -1
  102. package/dist/witness/agent/gemini/gemini-agent-factory.d.mts.map +1 -1
  103. package/dist/witness/live-proxy-ibgib/live-proxy-ibgib-one-file.d.mts.map +1 -1
  104. package/dist/witness/live-proxy-ibgib/live-proxy-ibgib-one-file.mjs.map +1 -1
  105. package/dist/witness/space/metaspace/metaspace-webspace/metaspace-webspace-helper.mjs.map +1 -1
  106. package/dist/witness/space/metaspace/metaspace-webspace/metaspace-webspace.d.mts +4 -0
  107. package/dist/witness/space/metaspace/metaspace-webspace/metaspace-webspace.d.mts.map +1 -1
  108. package/dist/witness/space/metaspace/metaspace-webspace/metaspace-webspace.mjs +40 -1
  109. package/dist/witness/space/metaspace/metaspace-webspace/metaspace-webspace.mjs.map +1 -1
  110. package/dist/witness/space/web-filesystem-space/web-filesystem-space-types.d.mts.map +1 -1
  111. package/dist/witness/space/web-filesystem-space/web-filesystem-space-v1.d.mts.map +1 -1
  112. package/package.json +2 -2
  113. package/src/AUTO-GENERATED-version.mts +1 -1
  114. package/src/api/ibgib-api-bridge.mts +292 -0
  115. package/src/app-bootstrap/init-orchestration.mts +17 -6
  116. package/src/custom.d.ts +11 -0
  117. package/src/identity/keystone-sync-service.mts +257 -0
  118. package/src/index.mts +24 -25
  119. package/src/ui/component/README.md +82 -5
  120. package/src/ui/component/common-component-styles.css +270 -0
  121. package/src/ui/component/identity/add-device/add-device.css +133 -0
  122. package/src/ui/component/identity/add-device/add-device.html +52 -0
  123. package/src/ui/component/identity/add-device/add-device.mts +397 -0
  124. package/src/ui/component/identity/identity-header/IMPLEMENTATION.md +45 -0
  125. package/src/ui/component/identity/identity-header/identity-header.css +317 -0
  126. package/src/ui/component/identity/identity-header/identity-header.html +72 -0
  127. package/src/ui/component/identity/identity-header/identity-header.mts +651 -0
  128. package/src/ui/component/identity/identity-manager/IMPLEMENTATION.md +100 -0
  129. package/src/ui/component/identity/identity-manager/identity-manager.css +178 -0
  130. package/src/ui/component/identity/identity-manager/identity-manager.html +19 -0
  131. package/src/ui/component/identity/identity-manager/identity-manager.mts +675 -0
  132. package/src/ui/component/identity/index.mts +36 -0
  133. package/src/ui/component/identity/keystone-creator/keystone-creator.css +97 -0
  134. package/src/ui/component/identity/keystone-creator/keystone-creator.html +51 -0
  135. package/src/ui/component/identity/keystone-creator/keystone-creator.mts +497 -0
  136. package/src/ui/component/identity/keystone-details/keystone-details.css +621 -0
  137. package/src/ui/component/identity/keystone-details/keystone-details.html +154 -0
  138. package/src/ui/component/identity/keystone-details/keystone-details.mts +1506 -0
  139. package/src/ui/component/identity/keystone-scrubber/SCRUBBER_IMPLEMENTATION.md +33 -0
  140. package/src/ui/component/identity/keystone-scrubber/keystone-scrubber.css +46 -0
  141. package/src/ui/component/identity/keystone-scrubber/keystone-scrubber.html +15 -0
  142. package/src/ui/component/identity/keystone-scrubber/keystone-scrubber.mts +355 -0
  143. package/src/ui/component/identity/remove-device/remove-device.css +118 -0
  144. package/src/ui/component/identity/remove-device/remove-device.html +31 -0
  145. package/src/ui/component/identity/remove-device/remove-device.mts +247 -0
  146. package/src/ui/ui-constants.mts +1 -0
  147. package/src/ui/ui-types.mts +8 -0
  148. package/src/witness/space/metaspace/metaspace-webspace/metaspace-webspace.mts +42 -1
  149. package/tools/auto-generated-agent-skills/skills/ibgib-dependency-graph/SKILL.md +209 -0
  150. package/tools/auto-generated-agent-skills/skills/ibgib-implementation-plan/SKILL.md +102 -0
@@ -0,0 +1,397 @@
1
+ import thisCss from "./add-device.css";
2
+ import thisHtml from "./add-device.html";
3
+ import commonComponentStylesCss from "../../common-component-styles.css";
4
+
5
+ import { delay, extractErrorMsg, getUUID } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
6
+ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
7
+ import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
8
+ import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
9
+ import { getGibInfo } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
10
+ import { KeystoneService_V1 } from "@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs";
11
+ import { KeystoneProfileBuilder } from "@ibgib/core-gib/dist/keystone/policy/keystone-profile-builder.mjs";
12
+ import { KeystoneIbGib_V1 } from "@ibgib/core-gib/dist/keystone/keystone-types.mjs";
13
+ import { KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT, KEYSTONE_USERNAME_REGEXP } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
14
+ import { deriveDelegateSecret } from "@ibgib/core-gib/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs";
15
+ import { getTimelinesGroupedByTjp, toDto } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
16
+ import { updateSpecialIndex } from "@ibgib/core-gib/dist/timeline/timeline-api.mjs";
17
+ import { getApiBridge } from "../../../../api/ibgib-api-bridge.mjs";
18
+
19
+ import { getGlobalMetaspace_waitIfNeeded } from "../../../../helpers.mjs";
20
+ import {
21
+ IbGibDynamicComponentMetaBase, IbGibFormInstanceBase,
22
+ } from "../../ibgib-dynamic-component-bases.mjs";
23
+ import {
24
+ ElementsBase, IbGibDynamicComponentInstance,
25
+ IbGibDynamicComponentInstanceInitOpts,
26
+ } from "../../component-types.mjs";
27
+ import { getComponentCtorArg } from "../../../../app-bootstrap/init-orchestration.mjs";
28
+ import { EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, EVENT_IBGIB_UI_MESSAGE } from "../../../ui-constants.mjs";
29
+
30
+ export const ADD_DEVICE_COMPONENT_NAME = 'ibgib-add-device';
31
+
32
+ /**
33
+ * Metadata for the Add Device / Pairing component.
34
+ */
35
+ export class AddDeviceComponentMeta extends IbGibDynamicComponentMetaBase {
36
+ protected lc: string = `[AddDeviceComponentMeta]`;
37
+
38
+ routeRegExp?: RegExp = new RegExp(`^${ADD_DEVICE_COMPONENT_NAME}$`);
39
+ componentName = ADD_DEVICE_COMPONENT_NAME;
40
+
41
+ constructor() {
42
+ super(getComponentCtorArg());
43
+ if (!customElements.get(this.componentName)) {
44
+ customElements.define(this.componentName, AddDeviceComponentInstance);
45
+ }
46
+ }
47
+
48
+ async createInstance({
49
+ path,
50
+ ibGibAddr
51
+ }: {
52
+ path: string;
53
+ ibGibAddr: IbGibAddr;
54
+ }): Promise<IbGibDynamicComponentInstance> {
55
+ const component = document.createElement(this.componentName) as AddDeviceComponentInstance;
56
+ await component.initialize({
57
+ ibGibAddr,
58
+ meta: this,
59
+ html: thisHtml,
60
+ css: [commonComponentStylesCss, thisCss],
61
+ });
62
+ return component;
63
+ }
64
+ }
65
+
66
+ interface AddDeviceElements extends ElementsBase {
67
+ containerEl: HTMLDivElement;
68
+ titleEl: HTMLHeadingElement;
69
+ inputIdentifier: HTMLInputElement;
70
+ inputDeviceTag: HTMLInputElement;
71
+ inputPassphrase: HTMLInputElement;
72
+ checkboxMakeActive: HTMLInputElement;
73
+ btnAddDeviceEl: HTMLButtonElement;
74
+ statusArea: HTMLDivElement;
75
+ statusText: HTMLParagraphElement;
76
+ resultAreaEl: HTMLDivElement;
77
+ delegateAddrEl: HTMLElement;
78
+ }
79
+
80
+ /**
81
+ * Concrete implementation of the Add Device / Pairing component.
82
+ */
83
+ export class AddDeviceComponentInstance
84
+ extends IbGibFormInstanceBase<IbGib_V1, AddDeviceElements>
85
+ implements IbGibDynamicComponentInstance<IbGib_V1, AddDeviceElements> {
86
+
87
+ protected lc: string = `[AddDeviceComponentInstance]`;
88
+
89
+ constructor() {
90
+ super();
91
+ }
92
+
93
+ override async initialize(opts: IbGibDynamicComponentInstanceInitOpts): Promise<void> {
94
+ await super.initialize(opts);
95
+ }
96
+
97
+ override async created(): Promise<void> {
98
+ this.elements = {} as AddDeviceElements;
99
+
100
+ this.elements.containerEl = this.shadowRoot!.getElementById('container') as HTMLDivElement;
101
+ this.elements.titleEl = this.shadowRoot!.getElementById('title') as HTMLHeadingElement;
102
+ this.elements.inputIdentifier = this.shadowRoot!.getElementById('input-identifier') as HTMLInputElement;
103
+ this.elements.inputDeviceTag = (this.shadowRoot!.getElementById('input-device-tag') || this.shadowRoot!.getElementById('input-device-name')) as HTMLInputElement;
104
+ this.elements.inputPassphrase = this.shadowRoot!.getElementById('input-passphrase') as HTMLInputElement;
105
+ this.elements.checkboxMakeActive = this.shadowRoot!.getElementById('checkbox-make-active') as HTMLInputElement;
106
+ this.elements.btnAddDeviceEl = this.shadowRoot!.getElementById('btn-add-device') as HTMLButtonElement;
107
+ this.elements.statusArea = this.shadowRoot!.getElementById('status-area') as HTMLDivElement;
108
+ this.elements.statusText = this.shadowRoot!.getElementById('status-text') as HTMLParagraphElement;
109
+ this.elements.resultAreaEl = this.shadowRoot!.getElementById('result-area') as HTMLDivElement;
110
+ this.elements.delegateAddrEl = this.shadowRoot!.getElementById('delegate-addr') as HTMLElement;
111
+
112
+ this.elements.contentEl = this.elements.containerEl;
113
+
114
+ this.initHandlers();
115
+ await this.renderUI();
116
+ }
117
+
118
+ override async disconnected(): Promise<void> {
119
+ // cleanup if needed
120
+ }
121
+
122
+ private initHandlers() {
123
+ this.elements!.btnAddDeviceEl.addEventListener('click', () => this.handleAddDevice());
124
+
125
+ this.shadowRoot!.getElementById('btn-switch-create-account')?.addEventListener('click', (e) => {
126
+ e.preventDefault();
127
+ window.dispatchEvent(new CustomEvent(EVENT_IBGIB_UI_MESSAGE, {
128
+ detail: { action: 'show-keystone-creator' },
129
+ bubbles: true,
130
+ composed: true
131
+ }));
132
+ });
133
+
134
+ this.elements!.inputIdentifier.addEventListener('input', () => {
135
+ this.elements!.inputIdentifier.classList.remove('invalid');
136
+ });
137
+ this.elements!.inputDeviceTag.addEventListener('input', () => {
138
+ this.elements!.inputDeviceTag.classList.remove('invalid');
139
+ });
140
+ this.elements!.inputPassphrase.addEventListener('input', () => {
141
+ this.elements!.inputPassphrase.classList.remove('invalid');
142
+ });
143
+ }
144
+
145
+ private setButtonLoading(isLoading: boolean) {
146
+ if (this.elements?.btnAddDeviceEl) {
147
+ this.elements.btnAddDeviceEl.disabled = isLoading;
148
+ this.elements.btnAddDeviceEl.textContent = isLoading ? 'Pairing...' : 'Pair & Add Device';
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Executes the Phase 1 Add-Device pairing orchestration flow.
154
+ */
155
+ protected async handleAddDevice() {
156
+ const lc = `${this.lc}[${this.handleAddDevice.name}]`;
157
+ try {
158
+ const humanEyeDelay = 500;
159
+ this.setStatus("Initializing device pairing...", "info");
160
+
161
+ const identifier = this.elements!.inputIdentifier.value.trim();
162
+ this.elements!.inputIdentifier.value = identifier;
163
+ if (!identifier) {
164
+ this.elements!.inputIdentifier.classList.add('invalid');
165
+ this.setStatus("Please enter a registered username or email.", "error");
166
+ return;
167
+ }
168
+
169
+ const deviceTag = this.elements!.inputDeviceTag.value.trim();
170
+ this.elements!.inputDeviceTag.value = deviceTag;
171
+ if (!deviceTag || !KEYSTONE_USERNAME_REGEXP.test(deviceTag)) {
172
+ this.elements!.inputDeviceTag.classList.add('invalid');
173
+ this.setStatus("Please enter a valid Device Tag / Name (e.g. 'work-laptop').", "error");
174
+ return;
175
+ }
176
+
177
+ const masterSecret = this.elements!.inputPassphrase.value.trim();
178
+ this.elements!.inputPassphrase.value = masterSecret;
179
+ if (!masterSecret) {
180
+ this.elements!.inputPassphrase.classList.add('invalid');
181
+ this.setStatus("Please enter your master passphrase.", "error");
182
+ return;
183
+ }
184
+
185
+ this.setButtonLoading(true);
186
+ this.showBusy({
187
+ isBusy: true,
188
+ title: 'Locating Identity...',
189
+ msg: 'Searching for primary identity...',
190
+ animationEmoji: '🔍'
191
+ });
192
+
193
+ const metaspace = await getGlobalMetaspace_waitIfNeeded();
194
+ const space = await metaspace.getLocalUserSpace({});
195
+ if (!space) { throw new Error("No default space found in metaspace."); }
196
+
197
+ const keystoneService = new KeystoneService_V1();
198
+
199
+ // 1a. First attempt to locate primary identity keystone locally in space
200
+ const keystonesIndex = await metaspace.getSpecialIbGib({
201
+ type: "keystones",
202
+ space,
203
+ initialize: true,
204
+ });
205
+ const registeredAddrs: string[] = keystonesIndex?.rel8ns?.keystone ?? [];
206
+
207
+ let primaryKeystone: KeystoneIbGib_V1 | undefined;
208
+ for (const addr of registeredAddrs) {
209
+ const res = await metaspace.get({ addrs: [addr], space });
210
+ const found = res?.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
211
+ if (found && found.data) {
212
+ const username = found.data.frameDetails?.username ?? '';
213
+ const emails = found.data.emails ?? found.data.frameDetails?.emails ?? [];
214
+ if (username.toLowerCase() === identifier.toLowerCase() || emails.some((e: string) => e.toLowerCase() === identifier.toLowerCase())) {
215
+ primaryKeystone = found;
216
+ break;
217
+ }
218
+ }
219
+ }
220
+
221
+ // 1b. If not found locally, query server identity index
222
+ if (!primaryKeystone) {
223
+ this.setStatus("Locating identity on server...", "info");
224
+ const resLookup = await getApiBridge().lookupPrimaryKeystone({ identifier });
225
+ if (resLookup.success && resLookup.primaryKeystoneIbGib) {
226
+ const fetchedKeystone = resLookup.primaryKeystoneIbGib as KeystoneIbGib_V1;
227
+ const domainAddr = resLookup.tjpAddr || getIbGibAddr({ ibGib: fetchedKeystone });
228
+
229
+ // Fetch full domain graph from server so local space has all historical keystone frames
230
+ const resGraph = await getApiBridge().getKeystoneGraph(domainAddr);
231
+ if (resGraph.success && resGraph.graph) {
232
+ const graphIbGibs = Object.values(resGraph.graph);
233
+ await metaspace.put({ ibGibs: graphIbGibs, space });
234
+
235
+ // Order timelines by TJP and register each frame in ascending order
236
+ const timelinesMap = getTimelinesGroupedByTjp({ ibGibs: graphIbGibs });
237
+ for (const tjpKey of Object.keys(timelinesMap)) {
238
+ const timeline = timelinesMap[tjpKey];
239
+ for (const frame of timeline) {
240
+ await metaspace.registerNewIbGib({ ibGib: frame, space });
241
+ }
242
+ }
243
+
244
+ // Set primaryKeystone to the latest frame in the domain timeline
245
+ const domainTimeline = timelinesMap[domainAddr] || timelinesMap[Object.keys(timelinesMap)[0]];
246
+ if (domainTimeline && domainTimeline.length > 0) {
247
+ primaryKeystone = domainTimeline[domainTimeline.length - 1] as KeystoneIbGib_V1;
248
+ } else {
249
+ primaryKeystone = fetchedKeystone;
250
+ }
251
+ } else {
252
+ await metaspace.put({ ibGibs: [fetchedKeystone], space });
253
+ await metaspace.registerNewIbGib({ ibGib: fetchedKeystone, space });
254
+ primaryKeystone = fetchedKeystone;
255
+ }
256
+ }
257
+ }
258
+
259
+ if (!primaryKeystone) {
260
+ const msg = `No registered identity found for '${identifier}'. Please check your username/email or create a new account.`;
261
+ console.error(`${lc} ${msg}`);
262
+ this.setStatus(msg, "error");
263
+ this.showBusy({ isBusy: false });
264
+ this.setButtonLoading(false);
265
+ return;
266
+ }
267
+
268
+ const primaryUsername = primaryKeystone.data?.frameDetails?.username ?? 'user';
269
+
270
+ // 2. Generate local device delegate keystone
271
+ this.setStatus("Generating local device delegate...", "info");
272
+ this.showBusy({
273
+ isBusy: true,
274
+ title: 'Generating Keys...',
275
+ msg: 'Generating cryptographic delegate keys for this device...',
276
+ animationEmoji: '🔑'
277
+ });
278
+
279
+ const delegateSecret = await deriveDelegateSecret({ masterSecret });
280
+ const delegateBuilder = KeystoneProfileBuilder.buildKeystone('sync')
281
+ .withUsername(`${primaryUsername}-sync-${deviceTag}`)
282
+ .withDescription(`Sync Delegate for ${primaryUsername} on ${deviceTag}`)
283
+ .withDetails({
284
+ client: 'space-gib-web',
285
+ role: 'sync-delegate',
286
+ deviceTag
287
+ });
288
+ const delegateConfigs = await delegateBuilder.compileConfigs();
289
+
290
+ const delegateKeystone = await keystoneService.genesis({
291
+ masterSecret: delegateSecret,
292
+ configs: delegateConfigs,
293
+ metaspace,
294
+ space,
295
+ frameDetails: delegateBuilder.getFrameDetails()
296
+ });
297
+
298
+ const delegateAddr = getIbGibAddr({ ibGib: delegateKeystone });
299
+ console.log(`${lc} Local device delegate generated: ${delegateAddr}`);
300
+ await delay(humanEyeDelay);
301
+
302
+ // 3. Evolve parent primary keystone to register delegate
303
+ this.setStatus("Registering device on primary identity...", "info");
304
+ this.showBusy({
305
+ isBusy: true,
306
+ title: 'Registering Device...',
307
+ msg: 'Updating primary identity with new device delegate...',
308
+ animationEmoji: '📝'
309
+ });
310
+
311
+ const evolvedPrimaryKeystone = await keystoneService.registerDelegate({
312
+ parentKeystone: primaryKeystone,
313
+ delegateKeystone,
314
+ masterSecret,
315
+ metaspace,
316
+ space,
317
+ allowedVerbs: [KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT],
318
+ deviceName: deviceTag,
319
+ });
320
+
321
+ const evolvedPrimaryAddr = getIbGibAddr({ ibGib: evolvedPrimaryKeystone });
322
+ console.log(`${lc} Primary identity evolved with delegate: ${evolvedPrimaryAddr}`);
323
+ await delay(humanEyeDelay);
324
+
325
+ // 4. Post evolved primary keystone + delegate to server
326
+ this.setStatus("Syncing device pairing to server...", "info");
327
+ this.showBusy({
328
+ isBusy: true,
329
+ title: 'Syncing to Server...',
330
+ msg: 'Posting device pairing to server sync node...',
331
+ animationEmoji: '🔄'
332
+ });
333
+
334
+ const primaryTjpAddr = getGibInfo({ ibGibAddr: getIbGibAddr({ ibGib: primaryKeystone }) }).tjpGib;
335
+ const domainAddr = primaryTjpAddr ? getIbGibAddr({ ibGib: primaryKeystone }) : getIbGibAddr({ ibGib: primaryKeystone });
336
+
337
+ const resEvolve = await getApiBridge().putEvolveKeystone({
338
+ domainAddr,
339
+ keystoneIbGib: evolvedPrimaryKeystone,
340
+ relatedKeystoneIbGibs: [delegateKeystone]
341
+ });
342
+
343
+ if (!resEvolve.success) {
344
+ const msg = `Server rejected device pairing: ${resEvolve.message}`;
345
+ console.error(`${lc} ${msg}`);
346
+ this.setStatus(msg, "error");
347
+ this.showBusy({ isBusy: false });
348
+ this.setButtonLoading(false);
349
+ return;
350
+ }
351
+
352
+ // 5. Update local keystones index
353
+ this.showBusy({
354
+ isBusy: true,
355
+ title: 'Updating Local Indexes...',
356
+ msg: 'Registering new device in local index...',
357
+ animationEmoji: '💾'
358
+ });
359
+
360
+ await updateSpecialIndex({
361
+ type: "keystones",
362
+ rel8nInfos: [
363
+ {
364
+ rel8nName: "keystone",
365
+ ibGibs: [
366
+ toDto({ ibGib: evolvedPrimaryKeystone }),
367
+ toDto({ ibGib: delegateKeystone })
368
+ ],
369
+ },
370
+ ],
371
+ metaspace,
372
+ space,
373
+ });
374
+
375
+ // 6. Set as active identity if checked
376
+ if (this.elements!.checkboxMakeActive.checked) {
377
+ window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
378
+ detail: { activeIdentityAddr: evolvedPrimaryAddr },
379
+ bubbles: true,
380
+ composed: true
381
+ }));
382
+ }
383
+
384
+ this.showBusy({ isBusy: false });
385
+ this.setButtonLoading(false);
386
+ this.elements!.delegateAddrEl.innerText = delegateAddr;
387
+ this.elements!.resultAreaEl.classList.remove('collapsed');
388
+ this.setStatus("Device successfully paired!", "success");
389
+
390
+ } catch (error) {
391
+ console.error(`${lc} ${extractErrorMsg(error)}`, error);
392
+ this.setStatus(`Pairing failed: ${extractErrorMsg(error)}`, "error");
393
+ this.showBusy({ isBusy: false });
394
+ this.setButtonLoading(false);
395
+ }
396
+ }
397
+ }
@@ -0,0 +1,45 @@
1
+ # Identity Header Component - Implementation Spec
2
+
3
+ This document details the layout, styling, and behavior for the `identity-header` component (`ibgib-identity-header`). It is rendered inside the app shell's header and acts as a status indicator and shortcut route for the user's active identity.
4
+
5
+ ## Requirements
6
+
7
+ 1. **State-Driven Display**:
8
+ - **Active Identity Mode**: If an active Domain Identity (Keystone) address exists in settings and is resolved in the local space, the component displays an identity pill showing a truncated version of the address.
9
+ - **Inactive/Default Mode**: If no identity is resolved, the component renders a prominent "Create Identity" button.
10
+ 2. **Interactive Routing**:
11
+ - Clicking either the identity pill or the fallback "Create Identity" button calls `SpaceGibShellService.showIdentityManager()` to load the full `<ibgib-identity-manager>` component in the center view panel.
12
+ 3. **Agent-Themeable Styles**:
13
+ - The layout must be highly compact to fit inside a standard horizontal header panel.
14
+ - All styling must prioritize valid theme CSS variables (e.g., `--button-background-color-base`, `--tab-text-color-active`) to remain dynamic and styleable by runtime agents.
15
+ 4. **Shared Settings Scope**:
16
+ - It is initialized with the virtual `ROOT_ADDR` and manually binds to the `"keystones"` index `ibgib`.
17
+ - It initializes its coupled settings via `this.initSettings()`. Since both this component and the manager share the `"keystones"` index backing model, they automatically resolve the exact same coupled settings `ibgib` and settings timeline, reactively syncing active identity selection changes.
18
+ - For detailed data schema, see [identity-manager IMPLEMENTATION.md](../identity-manager/IMPLEMENTATION.md).
19
+
20
+ ---
21
+
22
+ ## Component Structure
23
+
24
+ * **[identity-header.mts](file:///c:/Users/billm/antigravity/ibgib/apps/space-gib/src/client/components/identity-header/identity-header.mts)**: Element definition, lifecycle events, active identity resolution, shell service navigation call.
25
+ * **[identity-header.html](file:///c:/Users/billm/antigravity/ibgib/apps/space-gib/src/client/components/identity-header/identity-header.html)**: Compact HTML structures for the pill and fallback button.
26
+ * **[identity-header.css](file:///c:/Users/billm/antigravity/ibgib/apps/space-gib/src/client/components/identity-header/identity-header.css)**: Glassmorphic pill styling matching current themes.
27
+
28
+ ---
29
+
30
+ ## Implementation Checklist
31
+
32
+ ### Phase 1: Basic Scaffolding & Setup
33
+ - [x] Scaffold `identity-header.mts`, `.html`, and `.css` files.
34
+ - [x] Register `IdentityHeaderComponentMeta` with `IbGibComponentService`.
35
+ - [x] Mount `<ibgib-identity-header>` inside the header panel in `SpaceGibShellService`.
36
+
37
+ ### Phase 2: Navigation & Identity State
38
+ - [x] Wire up click handlers to trigger center-panel navigation to `ibgib-identity-manager`.
39
+ - [x] Resolve settings and check the `"keystones"` index to render the appropriate active/inactive view mode.
40
+
41
+ ### Phase 3: Visual Polish & Bugs
42
+ - [ ] Ensure the header component has an initial size/button and is visible while the page is initializing.
43
+
44
+ ### Testing Note
45
+ - [ ] **Manual Testing Only**: Visual integration and navigation behavior will be verified manually by the developer to limit token consumption.