@highway1/core 0.1.41 → 0.1.43

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.
@@ -1,218 +0,0 @@
1
- /**
2
- * Semantic Search Engine
3
- *
4
- * Provides intelligent agent discovery through semantic search
5
- * with local-first strategy and network fallback
6
- */
7
-
8
- import type { AgentCard } from './agent-card-types.js';
9
- import { SearchIndex } from './search-index.js';
10
- import type { SemanticQuery, SearchResult } from './search-index.js';
11
- import { CapabilityMatcher } from './capability-matcher.js';
12
- import type { DHTOperations } from './dht.js';
13
- import { createLogger } from '../utils/logger.js';
14
-
15
- const logger = createLogger('semantic-search');
16
-
17
- /**
18
- * Semantic Search Engine
19
- */
20
- export class SemanticSearchEngine {
21
- private index: SearchIndex;
22
- private matcher: CapabilityMatcher;
23
-
24
- constructor(private dht?: DHTOperations) {
25
- this.index = new SearchIndex();
26
- this.matcher = new CapabilityMatcher();
27
- }
28
-
29
- /**
30
- * Main search interface
31
- * Local-first with network fallback
32
- */
33
- async search(query: SemanticQuery): Promise<AgentCard[]> {
34
- logger.info('Searching for agents', { query });
35
-
36
- // 1. Search local index
37
- const localResults = this.index.search(query);
38
- logger.debug('Local search results', { count: localResults.length });
39
-
40
- // 2. If insufficient results, query network
41
- const limit = query.limit || 10;
42
- if (localResults.length < limit && this.dht) {
43
- logger.debug('Insufficient local results, querying network');
44
- const networkResults = await this.searchNetwork(query);
45
- return this.mergeResults(localResults, networkResults, limit);
46
- }
47
-
48
- return localResults.map(r => r.card);
49
- }
50
-
51
- /**
52
- * Index an Agent Card for local search
53
- */
54
- indexAgentCard(card: AgentCard): void {
55
- this.index.indexAgentCard(card);
56
- }
57
-
58
- /**
59
- * Remove an Agent Card from local index
60
- */
61
- removeAgentCard(did: string): void {
62
- this.index.removeAgentCard(did);
63
- }
64
-
65
- /**
66
- * Get all indexed cards
67
- */
68
- getAllIndexedCards(): AgentCard[] {
69
- return this.index.getAllCards();
70
- }
71
-
72
- /**
73
- * Clear local index
74
- */
75
- clearIndex(): void {
76
- this.index.clear();
77
- }
78
-
79
- /**
80
- * Get index size
81
- */
82
- getIndexSize(): number {
83
- return this.index.size();
84
- }
85
-
86
- /**
87
- * Search network via DHT
88
- */
89
- private async searchNetwork(query: SemanticQuery): Promise<SearchResult[]> {
90
- if (!this.dht) {
91
- return [];
92
- }
93
-
94
- try {
95
- // For now, use capability-based DHT query
96
- // In future, implement distributed semantic search overlay
97
- const capability = query.capability || this.extractPrimaryCapability(query.text);
98
-
99
- if (!capability) {
100
- logger.debug('No capability extracted from query, skipping network search');
101
- return [];
102
- }
103
-
104
- const cards = await this.dht.queryByCapability(capability);
105
- logger.debug('Network search results', { count: cards.length });
106
-
107
- // Score network results
108
- return cards.map(card => {
109
- const score = this.scoreCard(card, query);
110
- return { card, score };
111
- });
112
- } catch (error) {
113
- logger.error('Network search failed', { error });
114
- return [];
115
- }
116
- }
117
-
118
- /**
119
- * Merge local and network results, removing duplicates
120
- */
121
- private mergeResults(
122
- local: SearchResult[],
123
- network: SearchResult[],
124
- limit: number
125
- ): AgentCard[] {
126
- const seen = new Set<string>();
127
- const merged: SearchResult[] = [];
128
-
129
- // Add local results first (they're already scored and sorted)
130
- for (const result of local) {
131
- if (!seen.has(result.card.did)) {
132
- seen.add(result.card.did);
133
- merged.push(result);
134
- }
135
- }
136
-
137
- // Add network results
138
- for (const result of network) {
139
- if (!seen.has(result.card.did)) {
140
- seen.add(result.card.did);
141
- merged.push(result);
142
-
143
- // Also index for future searches
144
- this.index.indexAgentCard(result.card);
145
- }
146
- }
147
-
148
- // Sort by score and apply limit
149
- merged.sort((a, b) => b.score - a.score);
150
- return merged.slice(0, limit).map(r => r.card);
151
- }
152
-
153
- /**
154
- * Score a card against a query
155
- */
156
- private scoreCard(card: AgentCard, query: SemanticQuery): number {
157
- let totalScore = 0;
158
- let count = 0;
159
-
160
- for (const capability of card.capabilities) {
161
- const score = this.matcher.match(query, capability);
162
- if (score > 0) {
163
- totalScore += score;
164
- count++;
165
- }
166
- }
167
-
168
- // Average score across matching capabilities
169
- const avgScore = count > 0 ? totalScore / count : 0;
170
-
171
- // Boost by trust score if available
172
- if (card.trust) {
173
- const trustBoost = card.trust.interactionScore * 0.2;
174
- return Math.min(avgScore + trustBoost, 1.0);
175
- }
176
-
177
- return avgScore;
178
- }
179
-
180
- /**
181
- * Extract primary capability from natural language text
182
- */
183
- private extractPrimaryCapability(text?: string): string | undefined {
184
- if (!text) return undefined;
185
-
186
- const keywords = this.matcher.extractKeywords(text);
187
-
188
- // Common capability keywords
189
- const capabilityKeywords = [
190
- 'translate', 'translation',
191
- 'review', 'code',
192
- 'analyze', 'analysis',
193
- 'generate', 'generation',
194
- 'search', 'query',
195
- 'compute', 'calculation',
196
- 'store', 'storage',
197
- 'message', 'messaging',
198
- 'auth', 'authentication',
199
- ];
200
-
201
- // Find first matching keyword
202
- for (const keyword of keywords) {
203
- if (capabilityKeywords.includes(keyword)) {
204
- return keyword;
205
- }
206
- }
207
-
208
- // Return first keyword as fallback
209
- return keywords[0];
210
- }
211
- }
212
-
213
- /**
214
- * Create a semantic search engine
215
- */
216
- export function createSemanticSearch(dht?: DHTOperations): SemanticSearchEngine {
217
- return new SemanticSearchEngine(dht);
218
- }
@@ -1,48 +0,0 @@
1
- import { base58btc } from 'multiformats/bases/base58';
2
- import { IdentityError } from '../utils/errors.js';
3
-
4
- /**
5
- * Derive a did:clawiverse DID from a public key
6
- * Format: did:clawiverse:<base58btc-encoded-pubkey>
7
- */
8
- export function deriveDID(publicKey: Uint8Array): string {
9
- try {
10
- const encoded = base58btc.encode(publicKey);
11
- return `did:clawiverse:${encoded}`;
12
- } catch (error) {
13
- throw new IdentityError('Failed to derive DID', error);
14
- }
15
- }
16
-
17
- /**
18
- * Extract public key from a did:clawiverse DID
19
- */
20
- export function extractPublicKey(did: string): Uint8Array {
21
- if (!did.startsWith('did:clawiverse:')) {
22
- throw new IdentityError('Invalid DID format: must start with did:clawiverse:');
23
- }
24
-
25
- try {
26
- const encoded = did.replace('did:clawiverse:', '');
27
- return base58btc.decode(encoded);
28
- } catch (error) {
29
- throw new IdentityError('Failed to extract public key from DID', error);
30
- }
31
- }
32
-
33
- /**
34
- * Validate a did:clawiverse DID format
35
- */
36
- export function validateDID(did: string): boolean {
37
- if (!did.startsWith('did:clawiverse:')) {
38
- return false;
39
- }
40
-
41
- try {
42
- const encoded = did.replace('did:clawiverse:', '');
43
- base58btc.decode(encoded);
44
- return true;
45
- } catch {
46
- return false;
47
- }
48
- }
@@ -1,77 +0,0 @@
1
- import { deriveDID } from './did.js';
2
-
3
- export interface DIDDocument {
4
- '@context': string[];
5
- id: string;
6
- verificationMethod: VerificationMethod[];
7
- authentication: string[];
8
- assertionMethod: string[];
9
- keyAgreement?: string[];
10
- service?: ServiceEndpoint[];
11
- }
12
-
13
- export interface VerificationMethod {
14
- id: string;
15
- type: string;
16
- controller: string;
17
- publicKeyMultibase: string;
18
- }
19
-
20
- export interface ServiceEndpoint {
21
- id: string;
22
- type: string;
23
- serviceEndpoint: string;
24
- }
25
-
26
- /**
27
- * Create a DID Document for a did:clawiverse identity
28
- */
29
- export function createDIDDocument(
30
- publicKey: Uint8Array,
31
- services?: ServiceEndpoint[]
32
- ): DIDDocument {
33
- const did = deriveDID(publicKey);
34
- const keyId = `${did}#key-1`;
35
- // Use base58btc encoding for multibase format
36
- const publicKeyMultibase = `z${Buffer.from(publicKey).toString('hex')}`;
37
-
38
- return {
39
- '@context': [
40
- 'https://www.w3.org/ns/did/v1',
41
- 'https://w3id.org/security/suites/ed25519-2020/v1',
42
- ],
43
- id: did,
44
- verificationMethod: [
45
- {
46
- id: keyId,
47
- type: 'Ed25519VerificationKey2020',
48
- controller: did,
49
- publicKeyMultibase,
50
- },
51
- ],
52
- authentication: [keyId],
53
- assertionMethod: [keyId],
54
- service: services,
55
- };
56
- }
57
-
58
- /**
59
- * Validate a DID Document structure
60
- */
61
- export function validateDIDDocument(doc: unknown): doc is DIDDocument {
62
- if (typeof doc !== 'object' || doc === null) {
63
- return false;
64
- }
65
-
66
- const d = doc as Partial<DIDDocument>;
67
-
68
- return (
69
- Array.isArray(d['@context']) &&
70
- typeof d.id === 'string' &&
71
- d.id.startsWith('did:clawiverse:') &&
72
- Array.isArray(d.verificationMethod) &&
73
- d.verificationMethod.length > 0 &&
74
- Array.isArray(d.authentication) &&
75
- Array.isArray(d.assertionMethod)
76
- );
77
- }
@@ -1,4 +0,0 @@
1
- export * from './keys.js';
2
- export * from './did.js';
3
- export * from './document.js';
4
- export * from './signer.js';
@@ -1,79 +0,0 @@
1
- import * as ed25519 from '@noble/ed25519';
2
- import { IdentityError } from '../utils/errors.js';
3
-
4
- export interface KeyPair {
5
- publicKey: Uint8Array;
6
- privateKey: Uint8Array;
7
- }
8
-
9
- /**
10
- * Generate a new Ed25519 key pair
11
- */
12
- export async function generateKeyPair(): Promise<KeyPair> {
13
- try {
14
- const privateKey = ed25519.utils.randomPrivateKey();
15
- const publicKey = await ed25519.getPublicKeyAsync(privateKey);
16
-
17
- return {
18
- publicKey,
19
- privateKey,
20
- };
21
- } catch (error) {
22
- throw new IdentityError('Failed to generate key pair', error);
23
- }
24
- }
25
-
26
- /**
27
- * Sign a message with a private key
28
- */
29
- export async function sign(
30
- message: Uint8Array,
31
- privateKey: Uint8Array
32
- ): Promise<Uint8Array> {
33
- try {
34
- return await ed25519.signAsync(message, privateKey);
35
- } catch (error) {
36
- throw new IdentityError('Failed to sign message', error);
37
- }
38
- }
39
-
40
- /**
41
- * Verify a signature
42
- */
43
- export async function verify(
44
- signature: Uint8Array,
45
- message: Uint8Array,
46
- publicKey: Uint8Array
47
- ): Promise<boolean> {
48
- try {
49
- return await ed25519.verifyAsync(signature, message, publicKey);
50
- } catch (error) {
51
- throw new IdentityError('Failed to verify signature', error);
52
- }
53
- }
54
-
55
- /**
56
- * Export key pair to JSON format
57
- */
58
- export function exportKeyPair(keyPair: KeyPair): {
59
- publicKey: string;
60
- privateKey: string;
61
- } {
62
- return {
63
- publicKey: Buffer.from(keyPair.publicKey).toString('hex'),
64
- privateKey: Buffer.from(keyPair.privateKey).toString('hex'),
65
- };
66
- }
67
-
68
- /**
69
- * Import key pair from JSON format
70
- */
71
- export function importKeyPair(exported: {
72
- publicKey: string;
73
- privateKey: string;
74
- }): KeyPair {
75
- return {
76
- publicKey: new Uint8Array(Buffer.from(exported.publicKey, 'hex')),
77
- privateKey: new Uint8Array(Buffer.from(exported.privateKey, 'hex')),
78
- };
79
- }
@@ -1,55 +0,0 @@
1
- import { sign, verify } from './keys.js';
2
- import { deriveDID } from './did.js';
3
- import { IdentityError } from '../utils/errors.js';
4
-
5
- export interface SignedMessage {
6
- payload: Uint8Array;
7
- signature: Uint8Array;
8
- signer: string; // DID
9
- }
10
-
11
- /**
12
- * Sign a message and return a signed message object
13
- */
14
- export async function signMessage(
15
- payload: Uint8Array,
16
- privateKey: Uint8Array,
17
- publicKey: Uint8Array
18
- ): Promise<SignedMessage> {
19
- try {
20
- const signature = await sign(payload, privateKey);
21
- const signer = deriveDID(publicKey);
22
-
23
- return {
24
- payload,
25
- signature,
26
- signer,
27
- };
28
- } catch (error) {
29
- throw new IdentityError('Failed to sign message', error);
30
- }
31
- }
32
-
33
- /**
34
- * Verify a signed message
35
- */
36
- export async function verifyMessage(
37
- signedMessage: SignedMessage,
38
- expectedPublicKey: Uint8Array
39
- ): Promise<boolean> {
40
- try {
41
- const expectedDID = deriveDID(expectedPublicKey);
42
-
43
- if (signedMessage.signer !== expectedDID) {
44
- return false;
45
- }
46
-
47
- return await verify(
48
- signedMessage.signature,
49
- signedMessage.payload,
50
- expectedPublicKey
51
- );
52
- } catch (error) {
53
- throw new IdentityError('Failed to verify message', error);
54
- }
55
- }
package/src/index.ts DELETED
@@ -1,33 +0,0 @@
1
- /**
2
- * Clawiverse Core - Main Export
3
- */
4
-
5
- // Identity
6
- export * from './identity/keys.js';
7
- export * from './identity/did.js';
8
- export * from './identity/signer.js';
9
-
10
- // Transport
11
- export * from './transport/node.js';
12
-
13
- // Discovery
14
- export * from './discovery/agent-card.js';
15
- export * from './discovery/agent-card-types.js';
16
- export * from './discovery/agent-card-schema.js';
17
- export * from './discovery/agent-card-encoder.js';
18
- export * from './discovery/dht.js';
19
- export * from './discovery/search-index.js';
20
- export * from './discovery/capability-matcher.js';
21
- export * from './discovery/semantic-search.js';
22
-
23
- // Messaging
24
- export * from './messaging/envelope.js';
25
- export * from './messaging/codec.js';
26
- export * from './messaging/router.js';
27
-
28
- // Trust (Phase 2)
29
- export * from './trust/index.js';
30
-
31
- // Utils
32
- export * from './utils/logger.js';
33
- export * from './utils/errors.js';
@@ -1,47 +0,0 @@
1
- import { encode, decode } from 'cbor-x';
2
- import type { MessageEnvelope } from './envelope.js';
3
- import { MessagingError } from '../utils/errors.js';
4
-
5
- /**
6
- * Encode a message envelope to CBOR
7
- */
8
- export function encodeMessage(envelope: MessageEnvelope): Uint8Array {
9
- try {
10
- return encode(envelope);
11
- } catch (error) {
12
- throw new MessagingError('Failed to encode message', error);
13
- }
14
- }
15
-
16
- /**
17
- * Decode a CBOR message to envelope
18
- */
19
- export function decodeMessage(data: Uint8Array): MessageEnvelope {
20
- try {
21
- return decode(data) as MessageEnvelope;
22
- } catch (error) {
23
- throw new MessagingError('Failed to decode message', error);
24
- }
25
- }
26
-
27
- /**
28
- * Encode message to JSON (for debugging/logging)
29
- */
30
- export function encodeMessageJSON(envelope: MessageEnvelope): string {
31
- try {
32
- return JSON.stringify(envelope, null, 2);
33
- } catch (error) {
34
- throw new MessagingError('Failed to encode message to JSON', error);
35
- }
36
- }
37
-
38
- /**
39
- * Decode JSON message to envelope
40
- */
41
- export function decodeMessageJSON(json: string): MessageEnvelope {
42
- try {
43
- return JSON.parse(json) as MessageEnvelope;
44
- } catch (error) {
45
- throw new MessagingError('Failed to decode message from JSON', error);
46
- }
47
- }
@@ -1,107 +0,0 @@
1
- import { MessagingError } from '../utils/errors.js';
2
-
3
- export interface MessageEnvelope {
4
- id: string;
5
- from: string; // DID
6
- to: string; // DID
7
- type: 'request' | 'response' | 'notification';
8
- protocol: string;
9
- payload: unknown;
10
- timestamp: number;
11
- signature: string;
12
- replyTo?: string; // For responses, the ID of the request
13
- }
14
-
15
- /**
16
- * Create a message envelope
17
- */
18
- export function createEnvelope(
19
- from: string,
20
- to: string,
21
- type: 'request' | 'response' | 'notification',
22
- protocol: string,
23
- payload: unknown,
24
- replyTo?: string
25
- ): Omit<MessageEnvelope, 'signature'> {
26
- return {
27
- id: generateMessageId(),
28
- from,
29
- to,
30
- type,
31
- protocol,
32
- payload,
33
- timestamp: Date.now(),
34
- replyTo,
35
- };
36
- }
37
-
38
- /**
39
- * Sign a message envelope
40
- */
41
- export async function signEnvelope(
42
- envelope: Omit<MessageEnvelope, 'signature'>,
43
- signFn: (data: Uint8Array) => Promise<Uint8Array>
44
- ): Promise<MessageEnvelope> {
45
- try {
46
- const envelopeJson = JSON.stringify(envelope);
47
- const envelopeBytes = new TextEncoder().encode(envelopeJson);
48
- const signature = await signFn(envelopeBytes);
49
-
50
- return {
51
- ...envelope,
52
- signature: Buffer.from(signature).toString('hex'),
53
- };
54
- } catch (error) {
55
- throw new MessagingError('Failed to sign envelope', error);
56
- }
57
- }
58
-
59
- /**
60
- * Verify a message envelope signature
61
- */
62
- export async function verifyEnvelope(
63
- envelope: MessageEnvelope,
64
- verifyFn: (signature: Uint8Array, data: Uint8Array) => Promise<boolean>
65
- ): Promise<boolean> {
66
- try {
67
- const { signature, ...envelopeWithoutSig } = envelope;
68
- const envelopeJson = JSON.stringify(envelopeWithoutSig);
69
- const envelopeBytes = new TextEncoder().encode(envelopeJson);
70
- const signatureBytes = Buffer.from(signature, 'hex');
71
-
72
- return await verifyFn(signatureBytes, envelopeBytes);
73
- } catch (error) {
74
- throw new MessagingError('Failed to verify envelope', error);
75
- }
76
- }
77
-
78
- /**
79
- * Validate message envelope structure
80
- */
81
- export function validateEnvelope(msg: unknown): msg is MessageEnvelope {
82
- if (typeof msg !== 'object' || msg === null) {
83
- return false;
84
- }
85
-
86
- const m = msg as Partial<MessageEnvelope>;
87
-
88
- return (
89
- typeof m.id === 'string' &&
90
- typeof m.from === 'string' &&
91
- m.from.startsWith('did:clawiverse:') &&
92
- typeof m.to === 'string' &&
93
- m.to.startsWith('did:clawiverse:') &&
94
- (m.type === 'request' || m.type === 'response' || m.type === 'notification') &&
95
- typeof m.protocol === 'string' &&
96
- m.payload !== undefined &&
97
- typeof m.timestamp === 'number' &&
98
- typeof m.signature === 'string'
99
- );
100
- }
101
-
102
- /**
103
- * Generate a unique message ID
104
- */
105
- function generateMessageId(): string {
106
- return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
107
- }
@@ -1,3 +0,0 @@
1
- export * from './envelope.js';
2
- export * from './codec.js';
3
- export * from './router.js';