@ibgib/space-gib 0.0.21 → 0.0.23
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.
- package/README.md +4 -0
- package/dist/client/PRIVACY_POLICY.md +144 -0
- package/dist/client/bootstrap.mjs +36 -43
- package/dist/client/chunk-7LVERIWN.mjs +8 -0
- package/dist/client/chunk-JT6UUKP5.mjs +27 -0
- package/dist/client/{chunk-7YXHRAEW.mjs → chunk-PJDAAEMZ.mjs} +333 -46
- package/dist/client/index.html +15 -1
- package/dist/client/index.mjs +46 -13
- package/dist/client/privacy.html +29 -29
- package/dist/client/script.mjs +1 -1
- package/dist/server/server.mjs +107 -96
- package/generate-privacy-html.js +6 -1
- package/package.json +6 -6
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/PRIVACY_POLICY.md +144 -0
- package/src/client/bootstrap.mts +1 -1
- package/src/client/dev-tools/vcs-workspace.mts +342 -0
- package/src/client/dev-tools.mts +13 -1
- package/src/client/index.html +15 -1
- package/src/client/privacy.html +29 -29
- package/src/client/ui/shell/space-gib-shell-service.mts +61 -11
- package/src/server/server.mts +1 -1
- package/dist/client/chunk-M2IO3EMM.mjs +0 -22
package/generate-privacy-html.js
CHANGED
|
@@ -21,9 +21,14 @@ console.log(`${lc} starting...`);
|
|
|
21
21
|
|
|
22
22
|
const privacyMdPath = pathUtils.resolve(__dirname, '../../docs/PRIVACY_POLICY.md');
|
|
23
23
|
const outputHtmlPath = pathUtils.resolve(__dirname, './src/client/privacy.html');
|
|
24
|
+
const outputMdPath = pathUtils.resolve(__dirname, './src/client/PRIVACY_POLICY.md');
|
|
24
25
|
|
|
25
26
|
const mdContent = await readFile(privacyMdPath, { encoding: 'utf8' });
|
|
26
27
|
|
|
28
|
+
// Ensure PRIVACY_POLICY.md is copied to src/client for runtime fetching by <ibgib-privacy-policy>
|
|
29
|
+
await writeFile(outputMdPath, mdContent, { encoding: 'utf8' });
|
|
30
|
+
console.log(`${lc} wrote ${outputMdPath}`);
|
|
31
|
+
|
|
27
32
|
const bodyHtml = convertMarkdownToHtml(mdContent, { linkTarget: '_blank', linkRel: 'noopener' });
|
|
28
33
|
|
|
29
34
|
const fullHtml = `<!DOCTYPE html>
|
|
@@ -198,7 +203,7 @@ const fullHtml = `<!DOCTYPE html>
|
|
|
198
203
|
|
|
199
204
|
<footer class="footer-bar">
|
|
200
205
|
<span>© ibgib contributors</span>
|
|
201
|
-
<span><a href="https://ibgib.space">ibgib.space</a
|
|
206
|
+
<span><a href="https://ibgib.space">ibgib.space</a></span>
|
|
202
207
|
</footer>
|
|
203
208
|
</div>
|
|
204
209
|
</body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibgib/space-gib",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "ibgib storage and provider service — SaaS at ibgib.space",
|
|
6
6
|
"scripts": {
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"build:test": "tsc -p tsconfig.test.json"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@ibgib/core-gib": "^0.1.
|
|
16
|
-
"@ibgib/helper-gib": "^0.0.
|
|
17
|
-
"@ibgib/ts-gib": "^0.5.
|
|
18
|
-
"@ibgib/web-gib": "^0.0.
|
|
19
|
-
"@ibgib/node-gib": "^0.0.
|
|
15
|
+
"@ibgib/core-gib": "^0.1.79",
|
|
16
|
+
"@ibgib/helper-gib": "^0.0.38",
|
|
17
|
+
"@ibgib/ts-gib": "^0.5.35",
|
|
18
|
+
"@ibgib/web-gib": "^0.0.65",
|
|
19
|
+
"@ibgib/node-gib": "^0.0.24"
|
|
20
20
|
},
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20.0.0"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Privacy Policy
|
|
2
|
+
|
|
3
|
+
**Status**: DRAFT (Active Development)
|
|
4
|
+
**Effective Date**: August 21, 2026
|
|
5
|
+
**Last Updated**: August 21, 2026
|
|
6
|
+
|
|
7
|
+
> [!WARNING]
|
|
8
|
+
> **Draft Notice & Active Development Disclaimer**:
|
|
9
|
+
> This Privacy Policy is currently in **draft status**. The `ibGib` platform, underlying cryptographic keystone engine, and decentralized data graph architecture are under **active research and development**. This document expresses our architectural intent, privacy commitments, and operational principles; however, as the technology is actively evolving, certain features, administrative tooling, and data workflows described herein may be experimental, partially implemented, or subject to change.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Introduction & Overview
|
|
14
|
+
|
|
15
|
+
Welcome to **ibGib**. We are committed to transparency, cryptographic self-sovereignty, and user privacy.
|
|
16
|
+
|
|
17
|
+
This Privacy Policy explains how `ibGib` (including `ibgib.space`, `ibgib.com`, and related open-source applications in this monorepo) collects, uses, stores, and protects your information when you interact with our network, services, and applications.
|
|
18
|
+
|
|
19
|
+
> [!IMPORTANT]
|
|
20
|
+
> **Summary for Everyone**:
|
|
21
|
+
> * **Public Directory**: Just like a public PGP key or public DNS record, your chosen **username**, **registered email address**, and **identity keystone** are part of the public graph so people and your devices can find and authenticate you.
|
|
22
|
+
> * **No Passwords on the Wire**: Your master passphrase, biometric data (Touch ID / Face ID / Windows Hello), and physical security keys (YubiKeys) **never** leave your local device.
|
|
23
|
+
> * **No Data Selling**: We do **not** sell, rent, monetize, or share your personal data with third-party advertisers or data brokers.
|
|
24
|
+
> * **Standard Transport Security**: All communications between your devices and our servers operate over industry-standard **TLS 1.3 / HTTPS** encryption.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Categories of Information We Collect
|
|
29
|
+
|
|
30
|
+
### A. Identity & Public Directory Data
|
|
31
|
+
When you create an account or link authentication methods, the following information is recorded in your identity keystone:
|
|
32
|
+
* **Chosen Username**: A human-readable identifier (e.g. `alice`).
|
|
33
|
+
* **Registered Email Address**: Provided during account creation or SSO linking to enable account discovery, verification, and recovery.
|
|
34
|
+
* **Public Keystone DAG Addresses & Challenge Hashes**: Cryptographic addresses and mathematical challenge hashes ($H = \text{Hash}(S)$) that define your identity's evolution timeline.
|
|
35
|
+
* **Registered Device Delegate Tags**: Public labels for devices authorized to sync on your behalf (e.g. `pwd-alice-desk-a9a0`, `passkey-mobile-b4c1`).
|
|
36
|
+
|
|
37
|
+
### B. Technical, Connection & Log Data
|
|
38
|
+
When accessing our hosted web nodes, standard operational connection data may be logged:
|
|
39
|
+
* **Internet Protocol (IP) Address** and approximate geographic origin.
|
|
40
|
+
* **HTTP/TLS Request Metadata**: Date/time of request, HTTP status code, URL path, and TLS cipher suite.
|
|
41
|
+
* **User-Agent Strings**: Browser type, operating system, and client application version.
|
|
42
|
+
* **Retention**: Operational and access logs are retained for a bounded window (typically **30 to 90 days**) strictly for system reliability, rate limiting, intrusion detection, and security forensics, after which they are automatically rotated and deleted.
|
|
43
|
+
|
|
44
|
+
### C. Workspace & Application Data
|
|
45
|
+
* **User-Created Content**: Notes, comments, graph nodes, and files stored within your tenant workspace.
|
|
46
|
+
* **Storage Status**: Workspace data is stored in tenant-isolated domain spaces. Data in transit is encrypted via TLS 1.3. Data at rest on the server is currently stored unencrypted within your isolated space directory (client-side data encryption is planned as a future capability).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 3. Public Directory Nature of Identity Keystones
|
|
51
|
+
|
|
52
|
+
> [!WARNING]
|
|
53
|
+
> **Experimental Architecture Notice**:
|
|
54
|
+
> Identity Keystones are built on an innovative Zero-Knowledge Proof (ZKP) Distributed Ledger Technology (DLT) architecture. While designed to eliminate reliance on central certificate authorities, this technology is experimental. See [Section 7](#7securityarchitectur) for detailed security context.
|
|
55
|
+
|
|
56
|
+
### Innovative ZKP DLT vs. Conventional PKI
|
|
57
|
+
`ibGib` is built upon public-key cryptographic principles, but **is not conventional Public Key Infrastructure (PKI)**:
|
|
58
|
+
* Instead of relying on asymmetric digital signatures (RSA, ECDSA) and centralized X.509 Certificate Authorities (CAs), `ibGib` identities utilize a **Zero-Knowledge Proof (ZKP) Distributed Ledger Technology (DLT)** architecture with symmetric hash-reveal challenge-response pools.
|
|
59
|
+
* **Public by Design**: Identity Keystones function as public directory records. Anyone on the network who knows your username or email address can query the server to retrieve your public keystone.
|
|
60
|
+
* **Zero Secret Exposure**: Public keystones contain only public challenge hashes ($H$). Revealing a challenge hash gives an observer zero ability to compute your private secret pre-image ($S$) or act on your behalf.
|
|
61
|
+
* **Biometric & Password Isolation**:
|
|
62
|
+
* Passwords, PINs, and passphrase pre-images are processed strictly inside your local browser memory and discarded.
|
|
63
|
+
* Hardware biometrics (fingerprints, facial recognition) and security keys operate exclusively within your device's hardware Secure Enclave / TPM via the W3C WebAuthn standard. Raw biometric data is never transmitted over the network or accessible to our servers.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 4. How We Use Your Information
|
|
68
|
+
|
|
69
|
+
We process personal and cryptographic data solely for the following legitimate purposes:
|
|
70
|
+
1. **Identity Resolution & Discovery**: Matching incoming authentication requests and email lookups to the correct tenant domain space.
|
|
71
|
+
2. **Cryptographic Multi-Device Authorization**: Permitting your devices to authorize scoped synchronization claims via local device sync delegates ($D_{\text{device}}$), while the native ibGib sync engine executes graph synchronization.
|
|
72
|
+
3. **Account Verification & Sign-In**: Sending one-time 6-digit verification codes (OTP) to confirm email ownership and authenticate sign-ins.
|
|
73
|
+
4. **Security & Abuse Prevention**: Enforcing rate limits, detecting brute-force attacks, and preventing server abuse.
|
|
74
|
+
|
|
75
|
+
We do **not** use your data for profiling, automated decision-making, or third-party targeted advertising.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 5. Third-Party Service Providers
|
|
80
|
+
|
|
81
|
+
We utilize minimal third-party services essential to core platform functionality:
|
|
82
|
+
|
|
83
|
+
* **Single Sign-On (SSO) Authentication (Optional)**:
|
|
84
|
+
* **Google OAuth2**: Currently supported for single-tap passwordless account creation and sign-in. When linking Google, we receive verified identity tokens (such as your verified email address and provider user ID) to authenticate your identity. We do not receive or store your Google password.
|
|
85
|
+
* **Future Providers**: We plan to introduce additional OAuth2 providers (such as GitHub and others) in future updates.
|
|
86
|
+
* **Transactional Email & Hosting Infrastructure**:
|
|
87
|
+
* **Transactional Email**: We send emails strictly for transactional account confirmation, sign-in verification codes, and security notices. We never send marketing, newsletter, or promotional spam emails.
|
|
88
|
+
* **Cloud Server & Storage Nodes**: Web nodes, domain space storage, and network routing are hosted on secure cloud infrastructure located in the United States.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 6. Immutable Timeline Integrity, Revocations & Data Deletion
|
|
93
|
+
|
|
94
|
+
### Cryptographic Timeline Integrity
|
|
95
|
+
`ibGib` is built on an **append-only, directed acyclic graph (DAG) architecture**. Similar to version control systems (like Git) and cryptographic ledgers (like Bitcoin), timeline records are mathematically linked using cryptographic hashes to ensure data integrity and tamper-evidence. Just as past blocks in a blockchain cannot be modified without destroying cryptographic integrity, historical keystone frames remain part of the verifiable audit chain.
|
|
96
|
+
|
|
97
|
+
### Revocations & Tombstones
|
|
98
|
+
When you modify your identity permissions—such as unlinking a Google SSO provider or revoking a lost device passkey:
|
|
99
|
+
* The system publishes a cryptographically signed **tombstone evolution frame** ($n \to n+1$).
|
|
100
|
+
* This frame officially revokes that authority and unlinks the provider from server-side reverse lookup indices.
|
|
101
|
+
|
|
102
|
+
### Content Takedowns & Full Account Erasure
|
|
103
|
+
1. **Content & Asset Takedowns**: Standalone content nodes and binary file payloads can be unlinked, de-indexed, or removed from server storage upon authorized request or valid legal takedown without compromising structural timeline history.
|
|
104
|
+
2. **Complete Tenant Erasure**: If you request complete account deletion, your entire tenant domain space (including all hosted keystones, delegate frames, and stored data) and reverse email index entries will be permanently purged and removed from server storage.
|
|
105
|
+
3. **Local Device Data Control**: You maintain full control over all data stored locally on your physical devices. You may clear your local cryptographic tokens, delegates, and cached workspace data at any time via the application settings or by clearing your browser's IndexedDB / local storage.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 7. Security Architecture & Experimental Protocol Notice
|
|
110
|
+
|
|
111
|
+
### Innovative & Experimental Nature
|
|
112
|
+
Identity Keystones, multi-pool challenge-response mechanisms, and decentralized sync delegates represent innovative, experimental cryptographic protocols. While we apply diligent best efforts in cryptanalysis and utilize industry-standard, proven cryptographic primitives (such as SHA-256, SHA-512, AES, and WebAuthn PRF), the composite architecture is actively evolving. Users should evaluate this platform understanding its experimental research nature.
|
|
113
|
+
|
|
114
|
+
### Conventional Security Foundations
|
|
115
|
+
All communications, API endpoints, and authentication exchanges between your client devices and our server infrastructure operate strictly over industry-standard **TLS 1.3 / HTTPS** encryption. Server-side data isolation, atomic file indexing, and timing side-channel protections are implemented following standard enterprise security practices.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 8. Your Privacy Rights (Texas TDPSA & US State Privacy Laws)
|
|
120
|
+
|
|
121
|
+
If you are a resident of Texas (governed by the **Texas Data Privacy and Security Act - TDPSA**) or other jurisdictions with applicable privacy legislation, you have the following rights regarding your personal data:
|
|
122
|
+
|
|
123
|
+
* **Right to Know / Access**: You have the right to confirm whether we process your personal data and to access such data.
|
|
124
|
+
* **Right to Correct**: You have the right to correct inaccuracies in your personal data.
|
|
125
|
+
* **Right to Delete**: You have the right to request deletion of personal data provided by or obtained about you.
|
|
126
|
+
* **Right to Data Portability**: You have the right to obtain a copy of your personal data in a portable and readily usable format.
|
|
127
|
+
* **Right to Opt-Out of Sale / Targeted Advertising**: We do **not** sell your personal data or process it for targeted advertising, so no opt-out is necessary.
|
|
128
|
+
* **Right to Non-Discrimination**: We will never discriminate against you, deny services, or alter pricing for exercising your privacy rights.
|
|
129
|
+
|
|
130
|
+
### How to Exercise Your Rights
|
|
131
|
+
To submit a privacy inquiry, request data export, or request permanent deletion of your tenant domain space, please contact us using the information in Section 9 below. We will verify your identity (using your registered email or cryptographic keystone proof) and respond within the statutory timeframe (typically 45 days).
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 9. Contact Information & Policy Updates
|
|
136
|
+
|
|
137
|
+
### Contact Us
|
|
138
|
+
If you have questions, comments, or requests regarding this Privacy Policy or our data handling practices, please reach out to us:
|
|
139
|
+
|
|
140
|
+
* **Open-Source Packages**: Published on **npm** under the `@ibgib` scope.
|
|
141
|
+
* **Email / Privacy Inquiries**: `ibgib.info@gmail.com`
|
|
142
|
+
|
|
143
|
+
### Updates to This Policy
|
|
144
|
+
We may update this Privacy Policy from time to time to reflect architectural advancements, legal requirements, or operational changes. When changes are made, the "Last Updated" date at the top of this document will be updated. We encourage you to review this policy periodically.
|
package/src/client/bootstrap.mts
CHANGED
|
@@ -45,7 +45,7 @@ const hasDevProfile = clientProfiles.some(p => p.endsWith('.dev'));
|
|
|
45
45
|
const hasStagingProfile = clientProfiles.some(p => p.endsWith('.staging'));
|
|
46
46
|
|
|
47
47
|
if (isProdEnv && (hasDevProfile || hasStagingProfile)) {
|
|
48
|
-
throw new Error(`Security Violation: Non-production keystone profiles are prohibited when NODE_ENV=production. Active client profiles: ${clientProfiles.join(', ')}. (E:
|
|
48
|
+
throw new Error(`Security Violation: Non-production keystone profiles are prohibited when NODE_ENV=production. Active client profiles: ${clientProfiles.join(', ')}. (E: genuuid)`);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
if (hasDevProfile) {
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module client/dev-tools/vcs-workspace
|
|
3
|
+
*
|
|
4
|
+
* Dev Tools panel button handlers for in-memory VCS Workspace Projection testing in space-gib.
|
|
5
|
+
* Utilizes the isomorphic VcsRepository facade and WebInMemoryWorkspaceProjectionSpace_V1.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
9
|
+
import { getGlobalMetaspace_waitIfNeeded } from '@ibgib/web-gib/dist/helpers.mjs';
|
|
10
|
+
import { WebInMemoryWorkspaceProjectionSpace_V1 } from '@ibgib/web-gib/dist/witness/space/web-in-memory-workspace-projection-space/web-in-memory-workspace-projection-space-v1.mjs';
|
|
11
|
+
import { InnerSpace_V1 } from '@ibgib/core-gib/dist/witness/space/inner-space/inner-space-v1.mjs';
|
|
12
|
+
import { DEFAULT_INNER_SPACE_DATA_V1 } from '@ibgib/core-gib/dist/witness/space/inner-space/inner-space-types.mjs';
|
|
13
|
+
import { getB2tFSBranchSpaceName } from '@ibgib/core-gib/dist/vcs/branch/branch-helper.mjs';
|
|
14
|
+
import { VcsRepository } from '@ibgib/core-gib/dist/vcs/vcs-repository.mjs';
|
|
15
|
+
import { VCS_DEFAULT_FOLDER_NAME } from '@ibgib/core-gib/dist/vcs/vcs-core-constants.mjs';
|
|
16
|
+
|
|
17
|
+
import { devLog, lc } from './common.mjs';
|
|
18
|
+
import { B2TFS_BRANCH_DEFAULT_NAME } from '@ibgib/core-gib/dist/vcs/branch/branch-constants.mjs';
|
|
19
|
+
|
|
20
|
+
interface VcsDevState {
|
|
21
|
+
backingSpace?: InnerSpace_V1;
|
|
22
|
+
wsSpace?: WebInMemoryWorkspaceProjectionSpace_V1;
|
|
23
|
+
repo?: VcsRepository;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const vcsDevState: VcsDevState = {};
|
|
27
|
+
(window as any).vcsDevState = vcsDevState;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 1. Initialize in-memory branch CAS space, VcsRepository session, and seed sample files.
|
|
31
|
+
*/
|
|
32
|
+
export function initVcsInitButton(): void {
|
|
33
|
+
const btn = document.getElementById('btn-vcs-init') as HTMLButtonElement | null;
|
|
34
|
+
if (!btn) { return; }
|
|
35
|
+
|
|
36
|
+
btn.addEventListener('click', async () => {
|
|
37
|
+
const lc_fn = `${lc}[btn-vcs-init]`;
|
|
38
|
+
try {
|
|
39
|
+
btn.disabled = true;
|
|
40
|
+
devLog('⏳ Initializing in-memory branch space & sample repo via VcsRepository...');
|
|
41
|
+
|
|
42
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
43
|
+
|
|
44
|
+
// 1. Create dedicated in-memory branch space
|
|
45
|
+
const branchSpaceName = getB2tFSBranchSpaceName('main');
|
|
46
|
+
const backingSpace = new InnerSpace_V1({
|
|
47
|
+
...DEFAULT_INNER_SPACE_DATA_V1,
|
|
48
|
+
name: branchSpaceName,
|
|
49
|
+
spaceSubPath: branchSpaceName,
|
|
50
|
+
uuid: 'ws_backing_cas_space_uuid',
|
|
51
|
+
});
|
|
52
|
+
await backingSpace.initialized;
|
|
53
|
+
vcsDevState.backingSpace = backingSpace;
|
|
54
|
+
|
|
55
|
+
// Register backingSpace in metaspace local user spaces
|
|
56
|
+
try {
|
|
57
|
+
if ((metaspace as any).localUserSpaces && !(metaspace as any).localUserSpaces.includes(backingSpace)) {
|
|
58
|
+
(metaspace as any).localUserSpaces.push(backingSpace);
|
|
59
|
+
}
|
|
60
|
+
if ((metaspace as any).spaces && !(metaspace as any).spaces.includes(backingSpace)) {
|
|
61
|
+
(metaspace as any).spaces.push(backingSpace);
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// Ignore
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 2. Instantiate WebInMemoryWorkspaceProjectionSpace_V1
|
|
68
|
+
const wsSpace = new WebInMemoryWorkspaceProjectionSpace_V1({
|
|
69
|
+
initialData: {
|
|
70
|
+
name: 'web_ws_space_main',
|
|
71
|
+
uuid: 'web_ws_uuid',
|
|
72
|
+
workspaceRoot: '/',
|
|
73
|
+
vcsFolderName: VCS_DEFAULT_FOLDER_NAME,
|
|
74
|
+
},
|
|
75
|
+
backingSpace,
|
|
76
|
+
});
|
|
77
|
+
await wsSpace.initialized;
|
|
78
|
+
vcsDevState.wsSpace = wsSpace;
|
|
79
|
+
|
|
80
|
+
// 3. Create VcsRepository session
|
|
81
|
+
const repo = new VcsRepository({
|
|
82
|
+
metaspace,
|
|
83
|
+
workspaceSpace: wsSpace,
|
|
84
|
+
localSpace: backingSpace,
|
|
85
|
+
vcsFolderName: VCS_DEFAULT_FOLDER_NAME,
|
|
86
|
+
repoRoot: undefined,
|
|
87
|
+
enableBranchLocking: true,
|
|
88
|
+
});
|
|
89
|
+
vcsDevState.repo = repo;
|
|
90
|
+
|
|
91
|
+
// 4. Initialize repository
|
|
92
|
+
await repo.init({
|
|
93
|
+
rootFolderName: 'my-app',
|
|
94
|
+
branchName: B2TFS_BRANCH_DEFAULT_NAME,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// 5. Seed initial files into virtual workspace
|
|
98
|
+
wsSpace.setVirtualFile('README.md', '# Space-Gib In-Memory Repo\n\nThis entire repository is projected in memory inside the browser.');
|
|
99
|
+
wsSpace.setVirtualFile('src/index.ts', 'export const app = "space-gib in-memory demo";\nconsole.log(app);');
|
|
100
|
+
wsSpace.setVirtualFile('src/helper.ts', 'export function add(a: number, b: number): number {\n return a + b;\n}');
|
|
101
|
+
wsSpace.setVirtualFile('.ibgibignore', 'node_modules/\n*.log\n');
|
|
102
|
+
|
|
103
|
+
// 6. Initial stage & commit
|
|
104
|
+
const indexIbGib = await repo.getIndexIbGib();
|
|
105
|
+
const activeBranchSpace = await repo.getActiveBranchSpace(indexIbGib);
|
|
106
|
+
await repo.add([], {
|
|
107
|
+
all: true,
|
|
108
|
+
indexIbGib,
|
|
109
|
+
activeBranchSpace,
|
|
110
|
+
repoRoot: repo.repoRoot!,
|
|
111
|
+
paths: undefined,
|
|
112
|
+
targetDir: undefined,
|
|
113
|
+
});
|
|
114
|
+
const commitRes = await repo.commit({ message: 'Initial repository commit' });
|
|
115
|
+
|
|
116
|
+
devLog(`✅ In-Memory Repo initialized via VcsRepository!\n Commit: ${commitRes.commitAddr.slice(0, 8)}\n Files: ${wsSpace.listVirtualPaths().join(', ')}`);
|
|
117
|
+
|
|
118
|
+
// Enable action buttons
|
|
119
|
+
setBtnDisabled('btn-vcs-list', false);
|
|
120
|
+
setBtnDisabled('btn-vcs-status', false);
|
|
121
|
+
setBtnDisabled('btn-vcs-modify', false);
|
|
122
|
+
setBtnDisabled('btn-vcs-reset', false);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
devLog(`❌ Init failed: ${extractErrorMsg(error)}`);
|
|
125
|
+
console.error(`${lc_fn}`, error);
|
|
126
|
+
} finally {
|
|
127
|
+
btn.disabled = true;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 2. List virtual files in in-memory projection space in a single formatted card.
|
|
134
|
+
*/
|
|
135
|
+
export function initVcsListButton(): void {
|
|
136
|
+
const btn = document.getElementById('btn-vcs-list') as HTMLButtonElement | null;
|
|
137
|
+
if (!btn) { return; }
|
|
138
|
+
|
|
139
|
+
btn.addEventListener('click', () => {
|
|
140
|
+
try {
|
|
141
|
+
const wsSpace = vcsDevState.wsSpace;
|
|
142
|
+
if (!wsSpace) {
|
|
143
|
+
devLog('⚠️ Repo not initialized yet. Click (1) first.');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const paths = wsSpace.listVirtualPaths();
|
|
148
|
+
const lines: string[] = [
|
|
149
|
+
`📁 --- IN-MEMORY VIRTUAL FILES (${paths.length} entries) ---`
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
for (const p of paths) {
|
|
153
|
+
const text = wsSpace.getVirtualText(p);
|
|
154
|
+
const isDir = text === undefined || wsSpace.getVirtualFile(p)?.length === 0;
|
|
155
|
+
if (isDir) {
|
|
156
|
+
lines.push(` 📁 [DIR] ${p}`);
|
|
157
|
+
} else {
|
|
158
|
+
const preview = (text || '').replace(/\n/g, ' ').slice(0, 40);
|
|
159
|
+
lines.push(` 📄 [FILE] ${p.padEnd(22)} (${String(text?.length || 0).padStart(3)} chars) -> "${preview}..."`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
devLog(lines.join('\n'));
|
|
164
|
+
} catch (error) {
|
|
165
|
+
devLog(`❌ List failed: ${extractErrorMsg(error)}`);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 3. Inspect repository status via VcsRepository in a single formatted card.
|
|
172
|
+
*/
|
|
173
|
+
export function initVcsStatusButton(): void {
|
|
174
|
+
const btn = document.getElementById('btn-vcs-status') as HTMLButtonElement | null;
|
|
175
|
+
if (!btn) { return; }
|
|
176
|
+
|
|
177
|
+
btn.addEventListener('click', async () => {
|
|
178
|
+
try {
|
|
179
|
+
const repo = vcsDevState.repo;
|
|
180
|
+
if (!repo) {
|
|
181
|
+
devLog('⚠️ Repo not initialized yet.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const status = await repo.status();
|
|
186
|
+
const lines: string[] = [
|
|
187
|
+
`📋 --- VCS STATUS (Branch: ${status.branchName}) ---`
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
if (status.staged.length === 0 && status.modified.length === 0 && status.deleted.length === 0 && status.untracked.length === 0 && status.pendingComments.length === 0) {
|
|
191
|
+
lines.push(' ✨ Working tree clean (no changes)');
|
|
192
|
+
} else {
|
|
193
|
+
if (status.staged.length > 0) {
|
|
194
|
+
lines.push(` 🟢 Staged changes (${status.staged.length}):`);
|
|
195
|
+
for (const s of status.staged) { lines.push(` staged: ${s.path}`); }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (status.modified.length > 0) {
|
|
199
|
+
lines.push(` 🟡 Changes not staged for commit (${status.modified.length}):`);
|
|
200
|
+
for (const m of status.modified) { lines.push(` modified: ${m.path}`); }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (status.deleted.length > 0) {
|
|
204
|
+
lines.push(` 🔴 Deleted files (${status.deleted.length}):`);
|
|
205
|
+
for (const d of status.deleted) { lines.push(` deleted: ${d.path}`); }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (status.untracked.length > 0) {
|
|
209
|
+
lines.push(` ⚪ Untracked files (${status.untracked.length}):`);
|
|
210
|
+
for (const u of status.untracked) { lines.push(` untracked: ${u.path}`); }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (status.pendingComments.length > 0) {
|
|
214
|
+
lines.push(` 💬 Pending companion comments (${status.pendingComments.length}):`);
|
|
215
|
+
for (const c of status.pendingComments) { lines.push(` note for: ${c.targetRelPath} (${c.commentRelPath})`); }
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
devLog(lines.join('\n'));
|
|
220
|
+
} catch (error) {
|
|
221
|
+
devLog(`❌ Status check failed: ${extractErrorMsg(error)}`);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 4. Modify virtual file and add an untracked file directly in memory.
|
|
228
|
+
*/
|
|
229
|
+
export function initVcsModifyButton(): void {
|
|
230
|
+
const btn = document.getElementById('btn-vcs-modify') as HTMLButtonElement | null;
|
|
231
|
+
if (!btn) { return; }
|
|
232
|
+
|
|
233
|
+
btn.addEventListener('click', () => {
|
|
234
|
+
try {
|
|
235
|
+
const wsSpace = vcsDevState.wsSpace;
|
|
236
|
+
if (!wsSpace) {
|
|
237
|
+
devLog('⚠️ Repo not initialized yet.');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const lines: string[] = [
|
|
242
|
+
'✏️ Simulating user edits in in-browser editor...'
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
// Modify existing file
|
|
246
|
+
const newContent = 'export const app = "space-gib (EDITED LIVE IN BROWSER!)";\nconsole.log(app);\nexport const timestamp = ' + Date.now() + ';';
|
|
247
|
+
wsSpace.setVirtualFile('src/index.ts', newContent);
|
|
248
|
+
lines.push(' ✏️ Updated "src/index.ts" with new code content.');
|
|
249
|
+
|
|
250
|
+
// Add an untracked file
|
|
251
|
+
wsSpace.setVirtualFile('src/new-component.ts', 'export const Component = () => "<div>New UI</div>";');
|
|
252
|
+
lines.push(' ➕ Created untracked file "src/new-component.ts".');
|
|
253
|
+
|
|
254
|
+
// Add a companion comment file
|
|
255
|
+
wsSpace.setVirtualFile('src/.ib.index.ts.md', '# Architectural Note on index.ts\nEdited live from Dev Tools!');
|
|
256
|
+
lines.push(' 💬 Added companion comment file "src/.ib.index.ts.md".');
|
|
257
|
+
lines.push('👉 Click (3) VCS Status to view detected changes, or (5) to commit!');
|
|
258
|
+
|
|
259
|
+
devLog(lines.join('\n'));
|
|
260
|
+
setBtnDisabled('btn-vcs-commit', false);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
devLog(`❌ Modify failed: ${extractErrorMsg(error)}`);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* 5. Stage and commit modified files using VcsRepository.
|
|
269
|
+
*/
|
|
270
|
+
export function initVcsCommitButton(): void {
|
|
271
|
+
const btn = document.getElementById('btn-vcs-commit') as HTMLButtonElement | null;
|
|
272
|
+
if (!btn) { return; }
|
|
273
|
+
|
|
274
|
+
btn.addEventListener('click', async () => {
|
|
275
|
+
try {
|
|
276
|
+
btn.disabled = true;
|
|
277
|
+
const repo = vcsDevState.repo;
|
|
278
|
+
if (!repo) {
|
|
279
|
+
devLog('⚠️ Repo not initialized yet.');
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
devLog('💾 Staging and committing changes via VcsRepository...');
|
|
284
|
+
|
|
285
|
+
// Stage all modified and new files
|
|
286
|
+
const addRes = await repo.add([], { all: true });
|
|
287
|
+
|
|
288
|
+
// Commit with message
|
|
289
|
+
const commitRes = await repo.commit({
|
|
290
|
+
message: 'Update index.ts and add new component with companion comment',
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const lines: string[] = [
|
|
294
|
+
`🎉 Committed successfully via VcsRepository!`,
|
|
295
|
+
` Commit: ${commitRes.commitAddr.slice(0, 8)}`,
|
|
296
|
+
` Files Changed: ${commitRes.committedPaths.join(', ')}`,
|
|
297
|
+
` Companion Comments Attached: ${commitRes.ingestedCommentsCount}`,
|
|
298
|
+
`👉 Click (3) VCS Status to verify clean working tree.`
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
devLog(lines.join('\n'));
|
|
302
|
+
} catch (error) {
|
|
303
|
+
devLog(`❌ Commit failed: ${extractErrorMsg(error)}`);
|
|
304
|
+
console.error(`${lc}[btn-vcs-commit]`, error);
|
|
305
|
+
} finally {
|
|
306
|
+
btn.disabled = false;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* 6. Discard working tree changes by restoring from snapshot via VcsRepository.
|
|
313
|
+
*/
|
|
314
|
+
export function initVcsResetButton(): void {
|
|
315
|
+
const btn = document.getElementById('btn-vcs-reset') as HTMLButtonElement | null;
|
|
316
|
+
if (!btn) { return; }
|
|
317
|
+
|
|
318
|
+
btn.addEventListener('click', async () => {
|
|
319
|
+
try {
|
|
320
|
+
const { wsSpace, repo } = vcsDevState;
|
|
321
|
+
if (!wsSpace || !repo) {
|
|
322
|
+
devLog('⚠️ Repo not initialized yet.');
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
devLog('🔄 Resetting virtual working tree from branch snapshot via VcsRepository...');
|
|
327
|
+
await repo.restore({ all: true });
|
|
328
|
+
|
|
329
|
+
// Keep .ibgibignore in place
|
|
330
|
+
wsSpace.setVirtualFile('.ibgibignore', 'node_modules/\n*.log\n');
|
|
331
|
+
|
|
332
|
+
devLog('✅ Working tree restored! All uncommitted edits discarded.\n👉 Click (3) VCS Status to confirm clean state.');
|
|
333
|
+
} catch (error) {
|
|
334
|
+
devLog(`❌ Reset failed: ${extractErrorMsg(error)}`);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function setBtnDisabled(id: string, disabled: boolean): void {
|
|
340
|
+
const el = document.getElementById(id) as HTMLButtonElement | null;
|
|
341
|
+
if (el) { el.disabled = disabled; }
|
|
342
|
+
}
|
package/src/client/dev-tools.mts
CHANGED
|
@@ -25,8 +25,13 @@ import { init4_7bSetupButton, init4_7bSyncButton, init4_7bCheckButton } from './
|
|
|
25
25
|
import { init4_8bSetupButton, init4_8bSyncButton, init4_8bCheckButton } from './dev-tools/phase-4-8.mjs';
|
|
26
26
|
import { init4_9bSetupButton, init4_9bSyncButton, init4_9bCheckButton } from './dev-tools/phase-4-9.mjs';
|
|
27
27
|
import { init4_10bSetupButton, init4_10bSyncButton, init4_10bCheckButton } from './dev-tools/phase-4-10.mjs';
|
|
28
|
+
import {
|
|
29
|
+
initVcsInitButton, initVcsListButton, initVcsStatusButton,
|
|
30
|
+
initVcsModifyButton, initVcsCommitButton, initVcsResetButton,
|
|
31
|
+
vcsDevState
|
|
32
|
+
} from './dev-tools/vcs-workspace.mjs';
|
|
28
33
|
|
|
29
|
-
export { devLog, debugState };
|
|
34
|
+
export { devLog, debugState, vcsDevState };
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
37
|
* Call once inside DOMContentLoaded to wire up all dev-tool buttons.
|
|
@@ -96,6 +101,13 @@ export function initDevTools(): void {
|
|
|
96
101
|
init4_10bSetupButton();
|
|
97
102
|
init4_10bSyncButton();
|
|
98
103
|
init4_10bCheckButton();
|
|
104
|
+
|
|
105
|
+
initVcsInitButton();
|
|
106
|
+
initVcsListButton();
|
|
107
|
+
initVcsStatusButton();
|
|
108
|
+
initVcsModifyButton();
|
|
109
|
+
initVcsCommitButton();
|
|
110
|
+
initVcsResetButton();
|
|
99
111
|
} catch (error) {
|
|
100
112
|
console.error(`${lc_fn} ${extractErrorMsg(error)}`);
|
|
101
113
|
}
|
package/src/client/index.html
CHANGED
|
@@ -123,6 +123,7 @@
|
|
|
123
123
|
<option value="4.8B">Row 4.8B (Phase 4.8B)</option>
|
|
124
124
|
<option value="4.9B">Row 4.9B (Phase 4.9B)</option>
|
|
125
125
|
<option value="4.10B">Row 4.10B (Phase 4.10B)</option>
|
|
126
|
+
<option value="VCS">Row VCS (In-Memory Workspace)</option>
|
|
126
127
|
</select>
|
|
127
128
|
</div>
|
|
128
129
|
|
|
@@ -270,6 +271,19 @@
|
|
|
270
271
|
</div>
|
|
271
272
|
</div>
|
|
272
273
|
|
|
274
|
+
<!-- Row VCS: In-Memory Workspace Projection & VCS Engine -->
|
|
275
|
+
<div class="dev-panel-row-container" data-row-id="VCS">
|
|
276
|
+
<span class="dev-panel-row-label">VCS</span>
|
|
277
|
+
<div class="dev-panel-row">
|
|
278
|
+
<button id="btn-vcs-init" class="dev-btn">1. Init In-Memory Repo</button>
|
|
279
|
+
<button id="btn-vcs-list" class="dev-btn" disabled>2. List Virtual Files</button>
|
|
280
|
+
<button id="btn-vcs-status" class="dev-btn" disabled>3. VCS Status</button>
|
|
281
|
+
<button id="btn-vcs-modify" class="dev-btn" disabled>4. Edit app.ts</button>
|
|
282
|
+
<button id="btn-vcs-commit" class="dev-btn" disabled>5. Commit Edits</button>
|
|
283
|
+
<button id="btn-vcs-reset" class="dev-btn" disabled>6. Reset / Restore</button>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
|
|
273
287
|
<pre id="dev-panel-log" class="dev-panel-log" aria-live="polite" aria-label="Dev log"></pre>
|
|
274
288
|
</section>
|
|
275
289
|
</div>
|
|
@@ -294,7 +308,7 @@
|
|
|
294
308
|
<p class="footer-text">
|
|
295
309
|
<span>© ibgib contributors</span> ·
|
|
296
310
|
<a href="https://ibgib.space" class="footer-link">ibgib.space</a> ·
|
|
297
|
-
<a href="
|
|
311
|
+
<a href="#" id="link-privacy-policy" class="footer-link">Privacy Policy</a>
|
|
298
312
|
</p>
|
|
299
313
|
</footer>
|
|
300
314
|
|