@ibgib/web-gib 0.0.62 → 0.0.64

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 (98) hide show
  1. package/README.md +4 -0
  2. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  3. package/dist/AUTO-GENERATED-version.mjs +1 -1
  4. package/dist/helpers.web.d.mts +17 -2
  5. package/dist/helpers.web.d.mts.map +1 -1
  6. package/dist/helpers.web.mjs +67 -2
  7. package/dist/helpers.web.mjs.map +1 -1
  8. package/dist/helpers.web.respec.mjs +37 -10
  9. package/dist/helpers.web.respec.mjs.map +1 -1
  10. package/dist/identity/passkey-helper.d.mts +7 -2
  11. package/dist/identity/passkey-helper.d.mts.map +1 -1
  12. package/dist/identity/passkey-helper.mjs +33 -12
  13. package/dist/identity/passkey-helper.mjs.map +1 -1
  14. package/dist/index.d.mts +3 -0
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +4 -0
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/ui/component/identity/keystone-creator/keystone-creator.css +26 -0
  19. package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts.map +1 -1
  20. package/dist/ui/component/identity/keystone-creator/keystone-creator.html +18 -1
  21. package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs +10 -2
  22. package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs.map +1 -1
  23. package/dist/ui/component/identity/keystone-details/keystone-details.d.mts +12 -0
  24. package/dist/ui/component/identity/keystone-details/keystone-details.d.mts.map +1 -1
  25. package/dist/ui/component/identity/keystone-details/keystone-details.html +8 -0
  26. package/dist/ui/component/identity/keystone-details/keystone-details.mjs +419 -305
  27. package/dist/ui/component/identity/keystone-details/keystone-details.mjs.map +1 -1
  28. package/dist/ui/ui-helpers.d.mts.map +1 -1
  29. package/dist/ui/ui-helpers.mjs +7 -2
  30. package/dist/ui/ui-helpers.mjs.map +1 -1
  31. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-constants.d.mts +7 -0
  32. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-constants.d.mts.map +1 -0
  33. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-constants.mjs +7 -0
  34. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-constants.mjs.map +1 -0
  35. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-types.d.mts +24 -0
  36. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-types.d.mts.map +1 -0
  37. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-types.mjs +23 -0
  38. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-types.mjs.map +1 -0
  39. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.d.mts +85 -0
  40. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.d.mts.map +1 -0
  41. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.mjs +343 -0
  42. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.mjs.map +1 -0
  43. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.respec.d.mts +8 -0
  44. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.respec.d.mts.map +1 -0
  45. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.respec.mjs +249 -0
  46. package/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.respec.mjs.map +1 -0
  47. package/package.json +2 -2
  48. package/src/AUTO-GENERATED-version.mts +1 -1
  49. package/src/helpers.mts +1 -1
  50. package/src/helpers.web.mts +95 -5
  51. package/src/helpers.web.respec.mts +41 -10
  52. package/src/identity/passkey-helper.mts +43 -10
  53. package/src/index.mts +5 -0
  54. package/src/ui/component/identity/keystone-creator/keystone-creator.css +26 -0
  55. package/src/ui/component/identity/keystone-creator/keystone-creator.html +18 -1
  56. package/src/ui/component/identity/keystone-creator/keystone-creator.mts +12 -2
  57. package/src/ui/component/identity/keystone-details/keystone-details.html +8 -0
  58. package/src/ui/component/identity/keystone-details/keystone-details.mts +474 -339
  59. package/src/ui/ui-helpers.mts +6 -2
  60. package/src/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-constants.mts +8 -0
  61. package/src/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-types.mts +53 -0
  62. package/src/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.mts +424 -0
  63. package/src/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.respec.mts +304 -0
  64. package/tools/auto-generated-agent-skills/skills/ibgib-create-app/SKILL.md +65 -39
  65. package/tools/auto-generated-agent-skills/skills/ibgib-create-client-app/SKILL.md +51 -0
  66. package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/SKILL.md +26 -22
  67. package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-witness → ibgib-create-client-app-witness}/SKILL.md +11 -7
  68. package/tools/auto-generated-agent-skills/skills/ibgib-create-client-identity/SKILL.md +78 -0
  69. package/tools/auto-generated-agent-skills/skills/ibgib-create-client-shell/SKILL.md +42 -0
  70. package/tools/auto-generated-agent-skills/skills/ibgib-create-server-app/SKILL.md +50 -0
  71. package/tools/auto-generated-agent-skills/skills/ibgib-create-server-app/templates/Dockerfile.template +14 -0
  72. package/tools/auto-generated-agent-skills/skills/ibgib-create-server-app/templates/docker-compose.yml.template +33 -0
  73. package/tools/auto-generated-agent-skills/skills/ibgib-create-server-app/templates/server.mts.template +97 -0
  74. package/tools/auto-generated-agent-skills/skills/ibgib-create-server-app/templates/tsconfig.server.json.template +29 -0
  75. package/tools/auto-generated-agent-skills/skills/ibgib-implementation-plan/SKILL.md +4 -1
  76. package/src/identity/custodian-delegate-helper.mts.bak +0 -7
  77. package/src/identity/sso/sso-config-helper.mts.bak +0 -52
  78. package/src/identity/sso/sso-custodian-service.mts.bak +0 -566
  79. package/src/identity/sso/sso-custodian-service.respec.mts.bak +0 -298
  80. package/tools/auto-generated-agent-skills/skills/ibgib-create-shell/SKILL.md +0 -40
  81. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/generate-id.js +0 -0
  82. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/generate-version-file.js +0 -0
  83. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/bootstrap.mts.template +0 -0
  84. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/constants.mts.template +0 -0
  85. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/declarations.d.ts.template +0 -0
  86. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/helpers.web.mts.template +0 -0
  87. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/index.html.template +0 -0
  88. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/index.mts.template +0 -0
  89. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/script.mts.template +0 -0
  90. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-core → ibgib-create-client-app-core}/templates/types.mts.template +0 -0
  91. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-witness → ibgib-create-client-app-witness}/templates/api/function-infos.web.mts.template +0 -0
  92. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-witness → ibgib-create-client-app-witness}/templates/witness/app/app-v1.mts.template +0 -0
  93. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-witness → ibgib-create-client-app-witness}/templates/witness/app/constants.mts.template +0 -0
  94. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-witness → ibgib-create-client-app-witness}/templates/witness/app/helper.mts.template +0 -0
  95. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-app-witness → ibgib-create-client-app-witness}/templates/witness/app/types.mts.template +0 -0
  96. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-shell → ibgib-create-client-shell}/templates/ui/shell/shell-constants.mts.template +0 -0
  97. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-shell → ibgib-create-client-shell}/templates/ui/shell/shell-service.mts.template +0 -0
  98. /package/tools/auto-generated-agent-skills/skills/{ibgib-create-shell → ibgib-create-client-shell}/templates/ui/shell/shell-types.mts.template +0 -0
@@ -334,7 +334,11 @@ export async function showFullscreenDialog({
334
334
  true.toString();
335
335
  if (promptInput) { promptInput.value = ''; } // Clear input for next time
336
336
  dialog.close(result);
337
- resolve(result);
337
+ if (validPasskeys.length > 0) {
338
+ resolve({ secret: result, poolId: 'manage' });
339
+ } else {
340
+ resolve(result);
341
+ }
338
342
  };
339
343
 
340
344
  /** user clicks Passkey button */
@@ -353,7 +357,7 @@ export async function showFullscreenDialog({
353
357
  removeEventListeners();
354
358
  if (promptInput) { promptInput.value = ''; }
355
359
  dialog.close(passkeySecret);
356
- resolve(passkeySecret);
360
+ resolve({ secret: passkeySecret, poolId: selectedPasskey.poolId || 'passkey-manage' });
357
361
  } else {
358
362
  btnPasskey!.disabled = false;
359
363
  btnPasskey!.textContent = passkeyButtonTitle || '🛡️ Touch ID / Security Key';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @module web-in-memory-workspace-projection-space-constants
3
+ *
4
+ * Constants for in-memory web workspace projection spaces.
5
+ */
6
+
7
+ export const DEFAULT_WEB_IN_MEMORY_WORKSPACE_PROJECTION_SPACE_DESCRIPTION =
8
+ 'Web in-memory space witness for projecting and observing virtual workspace hierarchies in browser environments.';
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @module web-in-memory-workspace-projection-space-types
3
+ *
4
+ * Types for in-memory web workspace projection spaces.
5
+ */
6
+
7
+ import {
8
+ WorkspaceProjectionSpaceData_V1,
9
+ WorkspaceProjectionSpaceRel8ns_V1
10
+ } from '@ibgib/core-gib/dist/witness/space/workspace-projection-space/workspace-projection-space-types.mjs';
11
+ import {
12
+ DEFAULT_LOCAL_SPACE_POLLING_INTERVAL_MS,
13
+ IBGIB_SPACE_NAME_DEFAULT,
14
+ ZERO_SPACE_ID
15
+ } from '@ibgib/core-gib/dist/witness/space/space-constants.mjs';
16
+ import {
17
+ DEFAULT_WEB_IN_MEMORY_WORKSPACE_PROJECTION_SPACE_DESCRIPTION
18
+ } from './web-in-memory-workspace-projection-space-constants.mjs';
19
+
20
+ /**
21
+ * In-memory virtual file entry.
22
+ */
23
+ export interface VirtualFileEntry {
24
+ relPath: string;
25
+ content: Uint8Array;
26
+ isDirectory: boolean;
27
+ modifiedAt?: number;
28
+ }
29
+
30
+ /**
31
+ * Data payload for WebInMemoryWorkspaceProjectionSpace_V1.
32
+ */
33
+ export interface WebInMemoryWorkspaceProjectionSpaceData_V1 extends WorkspaceProjectionSpaceData_V1 {
34
+ }
35
+
36
+ export const DEFAULT_WEB_IN_MEMORY_WORKSPACE_PROJECTION_SPACE_DATA_V1: WebInMemoryWorkspaceProjectionSpaceData_V1 = {
37
+ version: '1',
38
+ uuid: ZERO_SPACE_ID,
39
+ name: IBGIB_SPACE_NAME_DEFAULT,
40
+ classname: 'WebInMemoryWorkspaceProjectionSpace_V1',
41
+ workspaceRoot: '/',
42
+ vcsFolderName: '.vcsgib',
43
+ persistOptsAndResultIbGibs: false,
44
+ validateIbGibAddrsMatchIbGibs: false,
45
+ longPollingIntervalMs: DEFAULT_LOCAL_SPACE_POLLING_INTERVAL_MS,
46
+ allowPrimitiveArgs: false,
47
+ catchAllErrors: true,
48
+ description: DEFAULT_WEB_IN_MEMORY_WORKSPACE_PROJECTION_SPACE_DESCRIPTION,
49
+ trace: false,
50
+ };
51
+
52
+ export interface WebInMemoryWorkspaceProjectionSpaceRel8ns_V1 extends WorkspaceProjectionSpaceRel8ns_V1 {
53
+ }
@@ -0,0 +1,424 @@
1
+ /**
2
+ * @module web-in-memory-workspace-projection-space-v1
3
+ *
4
+ * Concrete in-memory Web workspace projection space implementation.
5
+ * Projects B2tFS item DAGs into an in-memory virtual file tree and scans/observes
6
+ * virtual files for status and diff operations in browser environments.
7
+ */
8
+
9
+ import { clone, extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
10
+ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
11
+ import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
12
+ import { GLOBAL_LOG_A_LOT } from '@ibgib/core-gib/dist/core-constants.mjs';
13
+ import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
14
+ import { getFromSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
15
+ import { WorkspaceProjectionSpaceBase_V1 } from '@ibgib/core-gib/dist/witness/space/workspace-projection-space/workspace-projection-space-base-v1.mjs';
16
+ import {
17
+ WorkspaceScanResultData,
18
+ WorkspaceFileObservation,
19
+ PendingCommentObservation,
20
+ } from '@ibgib/core-gib/dist/witness/space/workspace-projection-space/workspace-projection-space-types.mjs';
21
+ import { B2tFSItemIbGib_V1 } from '@ibgib/core-gib/dist/vcs/item/item-types.mjs';
22
+ import { isPathFiltered, parseFilterFileContent } from '@ibgib/core-gib/dist/vcs/filter/glob-helper.mjs';
23
+
24
+ import {
25
+ WebInMemoryWorkspaceProjectionSpaceData_V1,
26
+ WebInMemoryWorkspaceProjectionSpaceRel8ns_V1,
27
+ DEFAULT_WEB_IN_MEMORY_WORKSPACE_PROJECTION_SPACE_DATA_V1,
28
+ VirtualFileEntry,
29
+ } from './web-in-memory-workspace-projection-space-types.mjs';
30
+
31
+ const logalot = GLOBAL_LOG_A_LOT;
32
+
33
+ export interface WebInMemoryWorkspaceProjectionSpaceOpts {
34
+ initialData?: WebInMemoryWorkspaceProjectionSpaceData_V1;
35
+ initialRel8ns?: WebInMemoryWorkspaceProjectionSpaceRel8ns_V1;
36
+ backingSpace?: IbGibSpaceAny;
37
+ }
38
+
39
+ /**
40
+ * In-Memory Web Workspace Projection Space that projects B2tFS item DAGs into
41
+ * an in-memory virtual file tree for browser code browsing, editing, and staging.
42
+ */
43
+ export class WebInMemoryWorkspaceProjectionSpace_V1 extends WorkspaceProjectionSpaceBase_V1<
44
+ WebInMemoryWorkspaceProjectionSpaceData_V1,
45
+ WebInMemoryWorkspaceProjectionSpaceRel8ns_V1
46
+ > {
47
+ protected override lc: string = `[${WebInMemoryWorkspaceProjectionSpace_V1.name}]`;
48
+
49
+ /** Backing CAS space where source BinIbGibs and child items reside */
50
+ backingSpace?: IbGibSpaceAny;
51
+
52
+ /** Map of normalized relative paths -> virtual file entries */
53
+ private _virtualFiles: Map<string, VirtualFileEntry> = new Map();
54
+
55
+ constructor(
56
+ initialDataOrOpts?: WebInMemoryWorkspaceProjectionSpaceData_V1 | WebInMemoryWorkspaceProjectionSpaceOpts,
57
+ initialRel8ns?: WebInMemoryWorkspaceProjectionSpaceRel8ns_V1,
58
+ ) {
59
+ let data: WebInMemoryWorkspaceProjectionSpaceData_V1 | undefined;
60
+ let rel8ns: WebInMemoryWorkspaceProjectionSpaceRel8ns_V1 | undefined = initialRel8ns;
61
+ let backingSpace: IbGibSpaceAny | undefined;
62
+
63
+ if (initialDataOrOpts && ('workspaceRoot' in initialDataOrOpts || 'name' in initialDataOrOpts)) {
64
+ data = initialDataOrOpts as WebInMemoryWorkspaceProjectionSpaceData_V1;
65
+ } else if (initialDataOrOpts && typeof initialDataOrOpts === 'object') {
66
+ const opts = initialDataOrOpts as WebInMemoryWorkspaceProjectionSpaceOpts;
67
+ data = opts.initialData;
68
+ rel8ns = opts.initialRel8ns ?? initialRel8ns;
69
+ backingSpace = opts.backingSpace;
70
+ }
71
+
72
+ super(data ?? (clone(DEFAULT_WEB_IN_MEMORY_WORKSPACE_PROJECTION_SPACE_DATA_V1) as WebInMemoryWorkspaceProjectionSpaceData_V1), rel8ns);
73
+ this.backingSpace = backingSpace;
74
+ }
75
+
76
+ // #region Implementation of Abstract Extension Hooks
77
+
78
+ /**
79
+ * Projects an item (and its recursive child hierarchy or binary payload) onto the in-memory virtual tree.
80
+ */
81
+ protected override async putItemToWorkspaceImpl({
82
+ item,
83
+ subPath,
84
+ }: {
85
+ item: B2tFSItemIbGib_V1;
86
+ subPath?: string;
87
+ }): Promise<void> {
88
+ const lc = `${this.lc}[${this.putItemToWorkspaceImpl.name}]`;
89
+ try {
90
+ if (logalot) { console.log(`${lc} projecting item to virtual workspace...`); }
91
+
92
+ if (!item || !item.data) {
93
+ throw new Error(`${lc} item and item.data are required (E: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6)`);
94
+ }
95
+
96
+ const { fsType, name } = item.data;
97
+
98
+ let itemRelPath: string;
99
+ if (subPath === undefined) {
100
+ itemRelPath = fsType === 'folder' ? '' : (name || '');
101
+ } else {
102
+ itemRelPath = name ? (subPath ? `${subPath}/${name}` : name) : subPath;
103
+ }
104
+ itemRelPath = this.normalizePath(itemRelPath);
105
+
106
+ if (fsType === 'folder') {
107
+ if (itemRelPath) {
108
+ this._virtualFiles.set(itemRelPath, {
109
+ relPath: itemRelPath,
110
+ content: new Uint8Array(0),
111
+ isDirectory: true,
112
+ modifiedAt: Date.now(),
113
+ });
114
+ }
115
+
116
+ const childAddrs = item.rel8ns?.b2tFS_child || item.rel8ns?.b2tfs_child || [];
117
+ for (const childAddr of childAddrs) {
118
+ const childItem = (await this.fetchIbGib(childAddr)) as B2tFSItemIbGib_V1;
119
+ await this.putItemToWorkspaceImpl({
120
+ item: childItem,
121
+ subPath: itemRelPath,
122
+ });
123
+ }
124
+ } else if (fsType === 'file') {
125
+ if (!item.rel8ns) {
126
+ throw new Error(`${lc} item.rel8ns required for file item (E: b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7)`);
127
+ }
128
+
129
+ const binAddrs = item.rel8ns.bin;
130
+ if (!binAddrs || binAddrs.length === 0) {
131
+ throw new Error(`${lc} item.rel8ns.bin required for file item ${name} (E: c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8)`);
132
+ }
133
+
134
+ const latestBinAddr = binAddrs.at(-1)!;
135
+ const binIbGib = await this.fetchIbGib(latestBinAddr);
136
+
137
+ if (binIbGib.data === undefined) {
138
+ throw new Error(`${lc} BinIbGib at addr ${latestBinAddr} has undefined data (E: d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9)`);
139
+ }
140
+
141
+ let fileData: Uint8Array;
142
+ if (binIbGib.data instanceof Uint8Array) {
143
+ fileData = binIbGib.data;
144
+ } else if (typeof binIbGib.data === 'string') {
145
+ fileData = new TextEncoder().encode(binIbGib.data);
146
+ } else if (typeof binIbGib.data === 'object') {
147
+ const vals = Object.values(binIbGib.data as object);
148
+ fileData = new Uint8Array(vals);
149
+ } else {
150
+ fileData = new Uint8Array(0);
151
+ }
152
+
153
+ this._virtualFiles.set(itemRelPath, {
154
+ relPath: itemRelPath,
155
+ content: fileData,
156
+ isDirectory: false,
157
+ modifiedAt: Date.now(),
158
+ });
159
+ }
160
+ } catch (error) {
161
+ console.error(`${lc} ${extractErrorMsg(error)} (E: e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0)`);
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Scans the in-memory virtual workspace and returns file observations and pending companion notes.
168
+ */
169
+ protected override async scanWorkspaceImpl({
170
+ subPath,
171
+ filterPatterns,
172
+ }: {
173
+ subPath?: string;
174
+ filterPatterns?: string[];
175
+ }): Promise<WorkspaceScanResultData> {
176
+ const lc = `${this.lc}[${this.scanWorkspaceImpl.name}]`;
177
+ try {
178
+ if (logalot) { console.log(`${lc} starting in-memory virtual scan...`); }
179
+
180
+ const vcsFolderName = this.data?.vcsFolderName || '.vcsgib';
181
+ let patterns = filterPatterns ?? this.data?.filterPatterns;
182
+
183
+ if (!patterns || patterns.length === 0) {
184
+ const ignoreEntry = this._virtualFiles.get('.ibgibignore');
185
+ if (ignoreEntry && !ignoreEntry.isDirectory) {
186
+ const ignoreContent = new TextDecoder('utf8').decode(ignoreEntry.content);
187
+ patterns = parseFilterFileContent(ignoreContent);
188
+ } else {
189
+ patterns = [];
190
+ }
191
+ }
192
+
193
+ const normalizedSubPath = subPath ? this.normalizePath(subPath) : '';
194
+ const files = new Map<string, WorkspaceFileObservation>();
195
+ const pendingComments: PendingCommentObservation[] = [];
196
+
197
+ for (const [relPath, entry] of this._virtualFiles.entries()) {
198
+ if (normalizedSubPath && !relPath.startsWith(normalizedSubPath)) {
199
+ continue;
200
+ }
201
+
202
+ // Exclude VCS metadata folders, .git, and worktrees folder 'b'
203
+ if (
204
+ relPath === vcsFolderName || relPath.startsWith(vcsFolderName + '/') ||
205
+ relPath === '.git' || relPath.startsWith('.git/') ||
206
+ relPath === 'b' || relPath.startsWith('b/')
207
+ ) {
208
+ continue;
209
+ }
210
+
211
+ if (isPathFiltered({ relativePath: relPath, isDirectory: entry.isDirectory, filterPatterns: patterns })) {
212
+ continue;
213
+ }
214
+
215
+ const filename = relPath.split('/').pop() || relPath;
216
+
217
+ if (entry.isDirectory) {
218
+ files.set(relPath, {
219
+ relPath,
220
+ fullPath: relPath,
221
+ isDirectory: true,
222
+ });
223
+ } else {
224
+ if (this.isCommentMetadataFilename(filename)) {
225
+ const pathParts = relPath.split('/');
226
+ pathParts.pop();
227
+ const parentRelPath = pathParts.join('/');
228
+ const content = new TextDecoder('utf8').decode(entry.content);
229
+ const topicName = this.extractCommentTopicName(filename);
230
+ const targetRelPath = parentRelPath ? `${parentRelPath}/${topicName}` : topicName;
231
+
232
+ pendingComments.push({
233
+ commentRelPath: relPath,
234
+ commentFullPath: relPath,
235
+ targetRelPath,
236
+ targetType: filename.startsWith('.ib.') ? 'file' : 'folder',
237
+ topicName,
238
+ content,
239
+ });
240
+ } else {
241
+ const digestBuf = await crypto.subtle.digest('SHA-256', entry.content as any);
242
+ const digestBytes = new Uint8Array(digestBuf);
243
+ let fileHash = '';
244
+ for (let i = 0; i < digestBytes.length; i++) {
245
+ fileHash += digestBytes[i].toString(16).padStart(2, '0');
246
+ }
247
+
248
+ files.set(relPath, {
249
+ relPath,
250
+ fullPath: relPath,
251
+ isDirectory: false,
252
+ fileHash,
253
+ size: entry.content.length,
254
+ });
255
+ }
256
+ }
257
+ }
258
+
259
+ return {
260
+ files,
261
+ pendingComments,
262
+ };
263
+ } catch (error) {
264
+ console.error(`${lc} ${extractErrorMsg(error)} (E: f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1)`);
265
+ throw error;
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Deletes a virtual file, folder, or comment entry from the in-memory tree.
271
+ */
272
+ protected override async deleteFromWorkspaceImpl({
273
+ relPath,
274
+ ibGib,
275
+ }: {
276
+ relPath?: string;
277
+ ibGib?: IbGib_V1;
278
+ }): Promise<void> {
279
+ const lc = `${this.lc}[${this.deleteFromWorkspaceImpl.name}]`;
280
+ try {
281
+ if (logalot) { console.log(`${lc} deleting from virtual workspace...`); }
282
+
283
+ const targetRelPath = this.normalizePath(relPath || (ibGib?.data as any)?.name);
284
+ if (!targetRelPath) {
285
+ throw new Error(`${lc} relPath or item name required for deletion (E: a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2)`);
286
+ }
287
+
288
+ // Remove target path and any nested children
289
+ const keysToDelete: string[] = [];
290
+ for (const key of this._virtualFiles.keys()) {
291
+ if (key === targetRelPath || key.startsWith(`${targetRelPath}/`)) {
292
+ keysToDelete.push(key);
293
+ }
294
+ }
295
+
296
+ for (const key of keysToDelete) {
297
+ this._virtualFiles.delete(key);
298
+ }
299
+ } catch (error) {
300
+ console.error(`${lc} ${extractErrorMsg(error)} (E: b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3)`);
301
+ throw error;
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Reads raw bytes of a virtual file from in-memory map.
307
+ */
308
+ protected override async getFileBytesImpl({
309
+ relPath,
310
+ }: {
311
+ relPath: string;
312
+ }): Promise<Uint8Array | undefined> {
313
+ return this.getVirtualFile(relPath);
314
+ }
315
+
316
+ // #endregion
317
+
318
+ // #region In-Memory Virtual File Accessors
319
+
320
+ /**
321
+ * Gets raw byte content for a virtual file.
322
+ */
323
+ public getVirtualFile(relPath: string): Uint8Array | undefined {
324
+ const normalized = this.normalizePath(relPath);
325
+ const entry = this._virtualFiles.get(normalized);
326
+ if (!entry || entry.isDirectory) { return undefined; }
327
+ return entry.content;
328
+ }
329
+
330
+ /**
331
+ * Gets UTF-8 text content for a virtual file.
332
+ */
333
+ public getVirtualText(relPath: string): string | undefined {
334
+ const bytes = this.getVirtualFile(relPath);
335
+ if (bytes === undefined) { return undefined; }
336
+ return new TextDecoder('utf8').decode(bytes);
337
+ }
338
+
339
+ /**
340
+ * Sets or updates a virtual file's content directly in memory.
341
+ */
342
+ public setVirtualFile(relPath: string, content: Uint8Array | string): void {
343
+ const normalized = this.normalizePath(relPath);
344
+ const data = typeof content === 'string' ? new TextEncoder().encode(content) : content;
345
+
346
+ // Ensure parent directories exist
347
+ const parts = normalized.split('/');
348
+ for (let i = 1; i < parts.length; i++) {
349
+ const parentPath = parts.slice(0, i).join('/');
350
+ if (!this._virtualFiles.has(parentPath)) {
351
+ this._virtualFiles.set(parentPath, {
352
+ relPath: parentPath,
353
+ content: new Uint8Array(0),
354
+ isDirectory: true,
355
+ modifiedAt: Date.now(),
356
+ });
357
+ }
358
+ }
359
+
360
+ this._virtualFiles.set(normalized, {
361
+ relPath: normalized,
362
+ content: data,
363
+ isDirectory: false,
364
+ modifiedAt: Date.now(),
365
+ });
366
+ }
367
+
368
+ /**
369
+ * Lists all virtual file and folder paths currently stored in memory.
370
+ */
371
+ public listVirtualPaths(): string[] {
372
+ return Array.from(this._virtualFiles.keys()).sort();
373
+ }
374
+
375
+ /**
376
+ * Clears all virtual files from memory.
377
+ */
378
+ public clearVirtualFiles(): void {
379
+ this._virtualFiles.clear();
380
+ }
381
+
382
+ // #endregion
383
+
384
+ // #region Private Helpers
385
+
386
+ private normalizePath(p: string): string {
387
+ return p.replace(/\\/g, '/').replace(/^\/+/, '').replace(/\/+$/, '');
388
+ }
389
+
390
+ private isCommentMetadataFilename(filename: string): boolean {
391
+ return filename.startsWith('.ib.') && filename.endsWith('.md') && filename.length > '.ib..md'.length;
392
+ }
393
+
394
+ private extractCommentTopicName(filename: string): string {
395
+ if (!this.isCommentMetadataFilename(filename)) { return ''; }
396
+ return filename.slice(4, -3);
397
+ }
398
+
399
+ /**
400
+ * Helper to fetch an IbGib strictly from backingSpace with fail-fast validation.
401
+ */
402
+ private async fetchIbGib(addr: IbGibAddr): Promise<IbGib_V1> {
403
+ const lc = `${this.lc}[${this.fetchIbGib.name}]`;
404
+ try {
405
+ if (!this.backingSpace) {
406
+ throw new Error(`${lc} backingSpace required to fetch IbGib at ${addr} (E: c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4)`);
407
+ }
408
+
409
+ const resGet = await getFromSpace({ space: this.backingSpace, addrs: [addr] });
410
+ if (!resGet.success || !resGet.ibGibs || resGet.ibGibs.length === 0) {
411
+ const resIbGib = resGet.rawResultIbGib as any;
412
+ const addrsNotFound = resIbGib?.data?.addrsNotFound ?? 'unknown';
413
+ throw new Error(`${lc} couldn't find addr ${addr} in backingSpace. addrsNotFound: ${addrsNotFound} (E: d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5)`);
414
+ }
415
+
416
+ return resGet.ibGibs[0];
417
+ } catch (error) {
418
+ console.error(`${lc} ${extractErrorMsg(error)} (E: e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6)`);
419
+ throw error;
420
+ }
421
+ }
422
+
423
+ // #endregion
424
+ }