diff --git a/src/commands/context.ts b/src/commands/context.ts index ab49120..15fd094 100644 --- a/src/commands/context.ts +++ b/src/commands/context.ts @@ -16,8 +16,10 @@ export function createContextCommand(): Command { console.log('✗ Not in a Tangled repository'); console.log('\nTo use this repository with Tangled, add a tangled.org remote:'); console.log(' git remote add origin git@tangled.org:/.git'); + console.log(' # or, for repo-DID remotes: git remote add origin git@tangled.org:'); console.log('\nOr clone from tangled.org:'); console.log(' git clone git@tangled.org:/.git'); + console.log(' # or: git clone git@tangled.org:'); process.exit(1); } diff --git a/src/utils/git.ts b/src/utils/git.ts index ea52578..503f2bb 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -62,6 +62,18 @@ export function parseTangledRemote(url: string): ParsedTangledRemote | null { // Remove .git extension if present path = path.replace(/\.git$/, ''); + // Tangled's hosted knot accepts a bare repository DID as a Git remote, + // e.g. git@tangled.org:did:plc:... . This does not encode the human + // owner/repo slug, but it is still a valid Tangled repository remote. + if (isValidTangledDid(path)) { + return { + owner: path, + ownerType: 'did', + name: path, + protocol, + }; + } + // Split path into owner and repo name const parts = path.split('/'); if (parts.length < 2) { diff --git a/tests/utils/git.test.ts b/tests/utils/git.test.ts index c0cc531..e261c74 100644 --- a/tests/utils/git.test.ts +++ b/tests/utils/git.test.ts @@ -56,6 +56,16 @@ describe('Git Utilities', () => { protocol: 'ssh', }); }); + + it('should parse bare SSH repo-DID remotes', () => { + const result = parseTangledRemote('git@tangled.org:did:plc:ll5woixehdm2aq4tqr7pkgcr'); + expect(result).toEqual({ + owner: 'did:plc:ll5woixehdm2aq4tqr7pkgcr', + ownerType: 'did', + name: 'did:plc:ll5woixehdm2aq4tqr7pkgcr', + protocol: 'ssh', + }); + }); }); describe('SSH URLs with handles', () => { @@ -109,6 +119,16 @@ describe('Git Utilities', () => { protocol: 'https', }); }); + + it('should parse bare HTTPS repo-DID remotes', () => { + const result = parseTangledRemote('https://tangled.org/did:plc:ll5woixehdm2aq4tqr7pkgcr'); + expect(result).toEqual({ + owner: 'did:plc:ll5woixehdm2aq4tqr7pkgcr', + ownerType: 'did', + name: 'did:plc:ll5woixehdm2aq4tqr7pkgcr', + protocol: 'https', + }); + }); }); describe('edge cases', () => { @@ -134,8 +154,8 @@ describe('Git Utilities', () => { expect(result).toBeNull(); }); - it('should return null for missing repo name', () => { - const result = parseTangledRemote('git@tangled.org:did:plc:abc123'); + it('should return null for missing repo name when path is not a DID', () => { + const result = parseTangledRemote('git@tangled.org:not-a-valid-owner'); expect(result).toBeNull(); });