vibeiao 0.1.8 → 0.1.10
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/package.json +2 -2
- package/src/index.js +538 -13
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "vibeiao",
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.10",
|
|
6
6
|
"description": "VIBEIAO CLI for agent onboarding and multisig revenue setup.",
|
|
7
7
|
"bin": {
|
|
8
8
|
"vibeiao": "src/index.js"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@coral-xyz/anchor": "^0.30.1",
|
|
19
19
|
"@solana/web3.js": "^1.98.0",
|
|
20
20
|
"@sqds/sdk": "^2.0.4",
|
|
21
|
-
"@vibeiao/sdk": "
|
|
21
|
+
"@vibeiao/sdk": "workspace:*",
|
|
22
22
|
"bn.js": "^5.2.1",
|
|
23
23
|
"bs58": "^6.0.0",
|
|
24
24
|
"tweetnacl": "^1.0.3"
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,17 @@ import Squads from '@sqds/sdk';
|
|
|
12
12
|
import bs58 from 'bs58';
|
|
13
13
|
import nacl from 'tweetnacl';
|
|
14
14
|
import BN from 'bn.js';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
createTreasuryPolicy,
|
|
17
|
+
validateTreasuryPolicy,
|
|
18
|
+
evaluateTopupRequest,
|
|
19
|
+
} from '@vibeiao/sdk';
|
|
20
|
+
import { formatOnboardedSurvivalTime } from '@vibeiao/sdk/social-profile';
|
|
21
|
+
import {
|
|
22
|
+
createAgentBuilderProfile,
|
|
23
|
+
createPrivacyPolicy,
|
|
24
|
+
exchangeAgentInfo,
|
|
25
|
+
} from '@vibeiao/sdk/social-protocol';
|
|
16
26
|
|
|
17
27
|
const DEFAULT_API_BASE = 'https://api.vibeiao.com';
|
|
18
28
|
const DEFAULT_RPC = 'https://api.mainnet-beta.solana.com';
|
|
@@ -34,6 +44,8 @@ const LISTING_NAME_MAX_LENGTH = 64;
|
|
|
34
44
|
const LISTING_TAGLINE_MAX_LENGTH = 160;
|
|
35
45
|
const LISTING_NAME_RECOMMENDED_MAX = 32;
|
|
36
46
|
const LISTING_TAGLINE_RECOMMENDED_MAX = 90;
|
|
47
|
+
const SOCIAL_INTENT_NOTE_MIN_LEN = 12;
|
|
48
|
+
const SOCIAL_INTENT_NOTE_MAX_LEN = 1200;
|
|
37
49
|
const HUMAN_LISTING_CATEGORIES = ['SaaS', 'Games'];
|
|
38
50
|
const DEFAULT_HUMAN_PRODUCT_URL = 'https://vibeiao.com';
|
|
39
51
|
const CONTROL_CHAR_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
@@ -121,6 +133,7 @@ const compareVersions = (left, right) => {
|
|
|
121
133
|
return comparePrerelease(l.prerelease, r.prerelease);
|
|
122
134
|
};
|
|
123
135
|
|
|
136
|
+
|
|
124
137
|
const normalizeBooleanEnv = (value) => {
|
|
125
138
|
if (value === undefined || value === null) return false;
|
|
126
139
|
const normalized = String(value).trim().toLowerCase();
|
|
@@ -534,13 +547,20 @@ const resolveContentType = (filePath) => {
|
|
|
534
547
|
const ext = path.extname(filePath).toLowerCase();
|
|
535
548
|
switch (ext) {
|
|
536
549
|
case '.html':
|
|
537
|
-
return 'text/html';
|
|
550
|
+
return 'text/html; charset=utf-8';
|
|
538
551
|
case '.js':
|
|
539
|
-
|
|
552
|
+
case '.mjs':
|
|
553
|
+
case '.cjs':
|
|
554
|
+
return 'application/javascript; charset=utf-8';
|
|
540
555
|
case '.css':
|
|
541
|
-
return 'text/css';
|
|
556
|
+
return 'text/css; charset=utf-8';
|
|
542
557
|
case '.json':
|
|
543
|
-
|
|
558
|
+
case '.map':
|
|
559
|
+
return 'application/json; charset=utf-8';
|
|
560
|
+
case '.txt':
|
|
561
|
+
return 'text/plain; charset=utf-8';
|
|
562
|
+
case '.wasm':
|
|
563
|
+
return 'application/wasm';
|
|
544
564
|
case '.svg':
|
|
545
565
|
return 'image/svg+xml';
|
|
546
566
|
case '.png':
|
|
@@ -554,8 +574,6 @@ const resolveContentType = (filePath) => {
|
|
|
554
574
|
return 'image/gif';
|
|
555
575
|
case '.ico':
|
|
556
576
|
return 'image/x-icon';
|
|
557
|
-
case '.map':
|
|
558
|
-
return 'application/json';
|
|
559
577
|
default:
|
|
560
578
|
return 'application/octet-stream';
|
|
561
579
|
}
|
|
@@ -568,6 +586,7 @@ const uploadSignedFile = async (signedUrl, absPath, contentType) => {
|
|
|
568
586
|
headers: {
|
|
569
587
|
'content-type': contentType,
|
|
570
588
|
'cache-control': 'max-age=3600',
|
|
589
|
+
'x-upsert': 'true',
|
|
571
590
|
},
|
|
572
591
|
body,
|
|
573
592
|
});
|
|
@@ -748,6 +767,72 @@ const buildQuery = (params) => {
|
|
|
748
767
|
return `?${query}`;
|
|
749
768
|
};
|
|
750
769
|
|
|
770
|
+
const stableStringify = (value) => {
|
|
771
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value);
|
|
772
|
+
if (Array.isArray(value)) return `[${value.map((entry) => stableStringify(entry)).join(',')}]`;
|
|
773
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
774
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(',')}}`;
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
const buildSocialAuthMessage = (action, agentId, context, timestamp) => {
|
|
778
|
+
const contextHash = crypto
|
|
779
|
+
.createHash('sha256')
|
|
780
|
+
.update(stableStringify(context))
|
|
781
|
+
.digest('hex')
|
|
782
|
+
.slice(0, 32);
|
|
783
|
+
return `VIBEIAO-SOCIAL:${action}:${agentId}:${contextHash}:${timestamp}`;
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
const signSocialAuth = (flags, { agentId, action, context }) => {
|
|
787
|
+
if (!agentId) throw new Error('missing_agent_id');
|
|
788
|
+
const keypairInput = flags.keypair || process.env.VIBEIAO_KEYPAIR || DEFAULT_KEYPAIR_PATH;
|
|
789
|
+
const keypair = loadKeypair(keypairInput);
|
|
790
|
+
if (!keypair) throw new Error('missing_keypair');
|
|
791
|
+
const timestamp = Date.now();
|
|
792
|
+
const message = buildSocialAuthMessage(action, agentId, context, timestamp);
|
|
793
|
+
const signature = bs58.encode(
|
|
794
|
+
nacl.sign.detached(new TextEncoder().encode(message), keypair.secretKey)
|
|
795
|
+
);
|
|
796
|
+
return {
|
|
797
|
+
wallet: keypair.publicKey.toBase58(),
|
|
798
|
+
signature,
|
|
799
|
+
timestamp,
|
|
800
|
+
};
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
const normalizeSocialText = (value) => String(value || '').replace(/\s+/g, ' ').trim();
|
|
804
|
+
|
|
805
|
+
const normalizePurpose = (value) => normalizeSocialText(value);
|
|
806
|
+
|
|
807
|
+
const hashSocialValue = (value) => (
|
|
808
|
+
`h${crypto.createHash('sha256').update(String(value || '')).digest('hex').slice(0, 16)}`
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
const computePurposeHash = (purpose) => hashSocialValue(normalizePurpose(purpose));
|
|
812
|
+
|
|
813
|
+
const computeIntentAlignmentHash = ({
|
|
814
|
+
proposalType,
|
|
815
|
+
channelId,
|
|
816
|
+
purposeVersion,
|
|
817
|
+
purposeHash,
|
|
818
|
+
targetAgentId,
|
|
819
|
+
intentAlignmentNote,
|
|
820
|
+
proposedPurpose,
|
|
821
|
+
}) => hashSocialValue(stableStringify({
|
|
822
|
+
proposalType,
|
|
823
|
+
channelId,
|
|
824
|
+
purposeVersion,
|
|
825
|
+
purposeHash,
|
|
826
|
+
targetAgentId,
|
|
827
|
+
intentAlignmentNote: normalizeSocialText(intentAlignmentNote),
|
|
828
|
+
proposedPurpose: proposedPurpose ? normalizePurpose(proposedPurpose) : null,
|
|
829
|
+
}));
|
|
830
|
+
|
|
831
|
+
const fetchSocialGroupInfo = async (apiBase, channelId) => {
|
|
832
|
+
const payload = await fetchJson(`${apiBase}/v1/social/groups/${encodeURIComponent(channelId)}`);
|
|
833
|
+
return payload?.data || null;
|
|
834
|
+
};
|
|
835
|
+
|
|
751
836
|
const ask = async (rl, label, fallback) => {
|
|
752
837
|
const suffix = fallback !== undefined && fallback !== null ? ` (${fallback})` : '';
|
|
753
838
|
const answer = (await rl.question(`${label}${suffix}: `)).trim();
|
|
@@ -861,9 +946,13 @@ const buildListingInput = async (flags) => {
|
|
|
861
946
|
);
|
|
862
947
|
const endpointUrl =
|
|
863
948
|
flags.endpoint || (await ask(rl, 'Endpoint URL', listingType === 'agent' ? '' : ''));
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
949
|
+
if (listingType === 'human' && flags.manifest) {
|
|
950
|
+
console.warn('⚠️ Human listing ignores --manifest. Manifest is agent-only.');
|
|
951
|
+
}
|
|
952
|
+
const manifestUrl =
|
|
953
|
+
listingType === 'agent'
|
|
954
|
+
? flags.manifest || (await ask(rl, 'Manifest URL (required)', ''))
|
|
955
|
+
: '';
|
|
867
956
|
const imageUrl = flags.image || (await ask(rl, 'Image URL (optional)', ''));
|
|
868
957
|
const priceUsdc = Number(
|
|
869
958
|
flags['price-usdc'] || flags.usdc || (await ask(rl, 'Ticket price (USDC)', '1'))
|
|
@@ -915,6 +1004,9 @@ const buildListingFromFlags = (flags) => {
|
|
|
915
1004
|
const listingType = explicitListingType
|
|
916
1005
|
? (explicitListingType === 'human' ? 'human' : 'agent')
|
|
917
1006
|
: (inferredHuman ? 'human' : 'agent');
|
|
1007
|
+
if (listingType === 'human' && flags.manifest) {
|
|
1008
|
+
console.warn('⚠️ Human listing ignores --manifest. Manifest is agent-only.');
|
|
1009
|
+
}
|
|
918
1010
|
|
|
919
1011
|
return {
|
|
920
1012
|
listingType,
|
|
@@ -931,7 +1023,7 @@ const buildListingFromFlags = (flags) => {
|
|
|
931
1023
|
imageUrl: flags.image,
|
|
932
1024
|
productUrl: normalizeProductUrl(listingType, flags.product),
|
|
933
1025
|
endpointUrl: flags.endpoint,
|
|
934
|
-
manifestUrl: flags.manifest,
|
|
1026
|
+
manifestUrl: listingType === 'agent' ? flags.manifest : '',
|
|
935
1027
|
runtime: flags.runtime,
|
|
936
1028
|
runtimeConfig: flags['runtime-config']
|
|
937
1029
|
? readJson(path.resolve(flags['runtime-config']))
|
|
@@ -962,7 +1054,8 @@ const normalizeListing = (listing) => ({
|
|
|
962
1054
|
imageUrl: listing.imageUrl?.trim() || '',
|
|
963
1055
|
productUrl: normalizeProductUrl(listing.listingType || 'agent', listing.productUrl),
|
|
964
1056
|
endpointUrl: listing.endpointUrl?.trim() || '',
|
|
965
|
-
manifestUrl:
|
|
1057
|
+
manifestUrl:
|
|
1058
|
+
(listing.listingType || 'agent') === 'agent' ? listing.manifestUrl?.trim() || '' : '',
|
|
966
1059
|
runtime: listing.runtime || '',
|
|
967
1060
|
runtimeConfig: listing.runtimeConfig || listing.runtime_config || undefined,
|
|
968
1061
|
walletMode: listing.walletMode ? listing.walletMode.toLowerCase() : undefined,
|
|
@@ -1574,7 +1667,7 @@ const handleDeploy = async (flags) => {
|
|
|
1574
1667
|
if (!signed?.signedUrl) {
|
|
1575
1668
|
throw new Error(`missing_signed_url:${file.path}`);
|
|
1576
1669
|
}
|
|
1577
|
-
const contentType = resolveContentType(file.path);
|
|
1670
|
+
const contentType = signed.contentType || resolveContentType(file.path);
|
|
1578
1671
|
await uploadSignedFile(signed.signedUrl, file.absPath, contentType);
|
|
1579
1672
|
}
|
|
1580
1673
|
|
|
@@ -1745,6 +1838,412 @@ const handleList = async (flags) => {
|
|
|
1745
1838
|
});
|
|
1746
1839
|
};
|
|
1747
1840
|
|
|
1841
|
+
const handleSocial = async (flags, positional) => {
|
|
1842
|
+
const apiBase = flags.api || process.env.VIBEIAO_API_BASE || DEFAULT_API_BASE;
|
|
1843
|
+
const sub = positional[1] || 'list';
|
|
1844
|
+
|
|
1845
|
+
if (sub === 'list') {
|
|
1846
|
+
const limit = Number.isFinite(Number(flags.limit)) ? Number(flags.limit) : 100;
|
|
1847
|
+
const offset = Number.isFinite(Number(flags.offset)) ? Number(flags.offset) : 0;
|
|
1848
|
+
const q = String(flags.q || flags.query || '').trim().toLowerCase();
|
|
1849
|
+
const payload = await fetchJson(
|
|
1850
|
+
`${apiBase}/v1/social/agents${buildQuery({ limit, offset, q: q || undefined })}`
|
|
1851
|
+
);
|
|
1852
|
+
const rows = (Array.isArray(payload?.data) ? payload.data : []).map((agent) => {
|
|
1853
|
+
const profile = createAgentBuilderProfile({
|
|
1854
|
+
agentId: agent.agentId || agent.listingId,
|
|
1855
|
+
name: agent.name,
|
|
1856
|
+
capabilityTags: Array.isArray(agent.capabilityTags) ? agent.capabilityTags : ['general'],
|
|
1857
|
+
reliabilityScore: Number.isFinite(Number(agent.reliabilityScore)) ? Number(agent.reliabilityScore) : 60,
|
|
1858
|
+
onboardedAt: agent.onboardedAt,
|
|
1859
|
+
});
|
|
1860
|
+
return {
|
|
1861
|
+
agentId: profile.agentId,
|
|
1862
|
+
name: profile.name,
|
|
1863
|
+
role: String(agent.role || 'Agent Builder'),
|
|
1864
|
+
profileSummary: String(agent.profileSummary || '').trim(),
|
|
1865
|
+
capabilities: profile.capabilityTags,
|
|
1866
|
+
reliabilityScore: profile.reliabilityScore,
|
|
1867
|
+
onboardedAt: profile.onboardedAt || null,
|
|
1868
|
+
profileVersion: Number.isFinite(Number(agent.profileVersion)) ? Number(agent.profileVersion) : 1,
|
|
1869
|
+
profileSource: String(agent.source || 'unknown'),
|
|
1870
|
+
survivalTime: formatOnboardedSurvivalTime(profile.onboardedAt),
|
|
1871
|
+
};
|
|
1872
|
+
});
|
|
1873
|
+
|
|
1874
|
+
if (flags.json) {
|
|
1875
|
+
console.log(JSON.stringify({ data: rows, total: payload?.total ?? rows.length }, null, 2));
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
console.log(`\nALL AGENTS (${rows.length})`);
|
|
1880
|
+
rows.forEach((row, idx) => {
|
|
1881
|
+
console.log(`${idx + 1}. ${row.name}`);
|
|
1882
|
+
console.log(` id: ${row.agentId}`);
|
|
1883
|
+
console.log(` role: ${row.role}`);
|
|
1884
|
+
console.log(` capabilities: ${row.capabilities.join(', ') || '—'}`);
|
|
1885
|
+
console.log(` reliability: ${row.reliabilityScore}`);
|
|
1886
|
+
console.log(` onboarded: ${row.survivalTime}`);
|
|
1887
|
+
if (row.profileSummary) {
|
|
1888
|
+
console.log(` profile: ${row.profileSummary}`);
|
|
1889
|
+
}
|
|
1890
|
+
console.log(` profileVersion: ${row.profileVersion} (${row.profileSource})`);
|
|
1891
|
+
if (idx < rows.length - 1) console.log('');
|
|
1892
|
+
});
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
if (sub === 'exchange-test') {
|
|
1897
|
+
const fromId = flags.from || flags['from-id'];
|
|
1898
|
+
const toId = flags.to || flags['to-id'];
|
|
1899
|
+
if (!fromId || !toId) throw new Error('missing_from_or_to');
|
|
1900
|
+
const scope = String(flags.scope || 'partner');
|
|
1901
|
+
if (!['public', 'partner', 'owner'].includes(scope)) throw new Error('invalid_scope');
|
|
1902
|
+
|
|
1903
|
+
const all = await fetchJson(`${apiBase}/v1/listings${buildQuery({ type: 'agent', limit: 500, offset: 0 })}`);
|
|
1904
|
+
const listings = Array.isArray(all?.data) ? all.data : [];
|
|
1905
|
+
const fromListing = listings.find((item) => item.id === fromId);
|
|
1906
|
+
const toListing = listings.find((item) => item.id === toId);
|
|
1907
|
+
if (!fromListing || !toListing) throw new Error('agent_not_found');
|
|
1908
|
+
|
|
1909
|
+
const from = createAgentBuilderProfile({
|
|
1910
|
+
agentId: fromListing.id,
|
|
1911
|
+
name: fromListing.name,
|
|
1912
|
+
capabilityTags: [fromListing.category || 'general'],
|
|
1913
|
+
reliabilityScore: String(fromListing.memory_status || '').toLowerCase() === 'healthy' ? 90 : 70,
|
|
1914
|
+
onboardedAt: fromListing.onboarded_at || fromListing.registered_at || fromListing.created_at,
|
|
1915
|
+
});
|
|
1916
|
+
const to = createAgentBuilderProfile({
|
|
1917
|
+
agentId: toListing.id,
|
|
1918
|
+
name: toListing.name,
|
|
1919
|
+
capabilityTags: [toListing.category || 'general'],
|
|
1920
|
+
reliabilityScore: String(toListing.memory_status || '').toLowerCase() === 'healthy' ? 90 : 70,
|
|
1921
|
+
onboardedAt: toListing.onboarded_at || toListing.registered_at || toListing.created_at,
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1924
|
+
const policy = createPrivacyPolicy({
|
|
1925
|
+
allowScopes: ['public', 'partner'],
|
|
1926
|
+
blockedKeys: ['ownerSecret', 'pii', 'humanOwnerId'],
|
|
1927
|
+
});
|
|
1928
|
+
|
|
1929
|
+
const payloadRaw = String(flags.payload || '').trim();
|
|
1930
|
+
let payloadObj = { summary: `${from.name} -> ${to.name}`, pii: 'redacted', ownerSecret: 'redacted' };
|
|
1931
|
+
if (payloadRaw) {
|
|
1932
|
+
try { payloadObj = JSON.parse(payloadRaw); } catch { throw new Error('invalid_payload_json'); }
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
const result = exchangeAgentInfo(
|
|
1936
|
+
from,
|
|
1937
|
+
to,
|
|
1938
|
+
{
|
|
1939
|
+
fromAgentId: from.agentId,
|
|
1940
|
+
toAgentId: to.agentId,
|
|
1941
|
+
scope,
|
|
1942
|
+
topic: String(flags.topic || 'social-sync'),
|
|
1943
|
+
payload: payloadObj,
|
|
1944
|
+
sentAtIso: new Date().toISOString(),
|
|
1945
|
+
},
|
|
1946
|
+
policy
|
|
1947
|
+
);
|
|
1948
|
+
|
|
1949
|
+
console.log(JSON.stringify({ from: from.agentId, to: to.agentId, scope, result }, null, 2));
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
if (sub === 'exchange-live') {
|
|
1954
|
+
const fromAgentId = flags.from || flags['from-id'];
|
|
1955
|
+
const toAgentId = flags.to || flags['to-id'];
|
|
1956
|
+
if (!fromAgentId || !toAgentId) throw new Error('missing_from_or_to');
|
|
1957
|
+
const scope = String(flags.scope || 'partner');
|
|
1958
|
+
if (!['public', 'partner', 'owner'].includes(scope)) throw new Error('invalid_scope');
|
|
1959
|
+
const topic = String(flags.topic || 'social-sync');
|
|
1960
|
+
const policyVersion = String(flags['policy-version'] || 'v1');
|
|
1961
|
+
const idempotencyKey = flags['idempotency-key'] || flags.idempotencyKey;
|
|
1962
|
+
|
|
1963
|
+
const payloadRaw = String(flags.payload || '').trim();
|
|
1964
|
+
let payloadObj = { summary: `live exchange ${fromAgentId} -> ${toAgentId}`, pii: 'redacted', ownerSecret: 'redacted' };
|
|
1965
|
+
if (payloadRaw) {
|
|
1966
|
+
try { payloadObj = JSON.parse(payloadRaw); } catch { throw new Error('invalid_payload_json'); }
|
|
1967
|
+
}
|
|
1968
|
+
const auth = signSocialAuth(flags, {
|
|
1969
|
+
agentId: fromAgentId,
|
|
1970
|
+
action: 'exchange',
|
|
1971
|
+
context: {
|
|
1972
|
+
toAgentId,
|
|
1973
|
+
scope,
|
|
1974
|
+
topic,
|
|
1975
|
+
payload: payloadObj,
|
|
1976
|
+
idempotencyKey: idempotencyKey || null,
|
|
1977
|
+
policyVersion,
|
|
1978
|
+
},
|
|
1979
|
+
});
|
|
1980
|
+
|
|
1981
|
+
const response = await fetchJson(`${apiBase}/v1/social/exchange`, {
|
|
1982
|
+
method: 'POST',
|
|
1983
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1984
|
+
body: JSON.stringify({
|
|
1985
|
+
fromAgentId,
|
|
1986
|
+
toAgentId,
|
|
1987
|
+
scope,
|
|
1988
|
+
topic,
|
|
1989
|
+
idempotencyKey,
|
|
1990
|
+
payload: payloadObj,
|
|
1991
|
+
policy: {
|
|
1992
|
+
policyVersion,
|
|
1993
|
+
allowScopes: ['public', 'partner'],
|
|
1994
|
+
blockedKeys: ['ownerSecret', 'pii', 'humanOwnerId'],
|
|
1995
|
+
},
|
|
1996
|
+
auth,
|
|
1997
|
+
}),
|
|
1998
|
+
});
|
|
1999
|
+
|
|
2000
|
+
console.log(JSON.stringify({ from: fromAgentId, to: toAgentId, scope, result: response?.data || response }, null, 2));
|
|
2001
|
+
return;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
if (sub === 'ack') {
|
|
2005
|
+
const evidence = String(flags.evidence || flags['evidence-hash'] || '').trim();
|
|
2006
|
+
const agentId = String(flags.agent || flags['agent-id'] || '').trim();
|
|
2007
|
+
if (!evidence) throw new Error('missing_evidence_hash');
|
|
2008
|
+
if (!agentId) throw new Error('missing_agent_id');
|
|
2009
|
+
const auth = signSocialAuth(flags, {
|
|
2010
|
+
agentId,
|
|
2011
|
+
action: 'exchange_ack',
|
|
2012
|
+
context: { evidenceHash: evidence },
|
|
2013
|
+
});
|
|
2014
|
+
const response = await fetchJson(`${apiBase}/v1/social/exchange/${encodeURIComponent(evidence)}/ack`, {
|
|
2015
|
+
method: 'POST',
|
|
2016
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2017
|
+
body: JSON.stringify({
|
|
2018
|
+
agentId,
|
|
2019
|
+
auth,
|
|
2020
|
+
}),
|
|
2021
|
+
});
|
|
2022
|
+
console.log(JSON.stringify(response?.data || response, null, 2));
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
if (sub === 'audit') {
|
|
2027
|
+
const limit = Number.isFinite(Number(flags.limit)) ? Number(flags.limit) : 20;
|
|
2028
|
+
const agentId = String(flags.agent || flags['agent-id'] || '').trim();
|
|
2029
|
+
const fromAgentId = flags.from || flags['from-id'];
|
|
2030
|
+
const toAgentId = flags.to || flags['to-id'];
|
|
2031
|
+
const evidenceHash = flags.evidence || flags['evidence-hash'];
|
|
2032
|
+
const idempotencyKey = flags['idempotency-key'] || flags.idempotencyKey;
|
|
2033
|
+
if (!agentId) throw new Error('missing_agent_id');
|
|
2034
|
+
const auth = signSocialAuth(flags, {
|
|
2035
|
+
agentId,
|
|
2036
|
+
action: 'audit_read',
|
|
2037
|
+
context: {
|
|
2038
|
+
fromAgentId: fromAgentId || null,
|
|
2039
|
+
toAgentId: toAgentId || null,
|
|
2040
|
+
evidenceHash: evidenceHash || null,
|
|
2041
|
+
idempotencyKey: idempotencyKey || null,
|
|
2042
|
+
limit,
|
|
2043
|
+
},
|
|
2044
|
+
});
|
|
2045
|
+
const response = await fetchJson(`${apiBase}/v1/social/audit${buildQuery({
|
|
2046
|
+
agentId,
|
|
2047
|
+
fromAgentId,
|
|
2048
|
+
toAgentId,
|
|
2049
|
+
evidenceHash,
|
|
2050
|
+
idempotencyKey,
|
|
2051
|
+
limit,
|
|
2052
|
+
wallet: auth.wallet,
|
|
2053
|
+
signature: auth.signature,
|
|
2054
|
+
timestamp: auth.timestamp,
|
|
2055
|
+
})}`);
|
|
2056
|
+
if (flags.json) {
|
|
2057
|
+
console.log(JSON.stringify(response, null, 2));
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
const rows = Array.isArray(response?.data) ? response.data : [];
|
|
2061
|
+
console.log(`\nSOCIAL AUDIT (${rows.length})`);
|
|
2062
|
+
rows.forEach((row, idx) => {
|
|
2063
|
+
const md = row?.metadata || {};
|
|
2064
|
+
console.log(`${idx + 1}. ${row.action} | ${md.fromAgentId || row.listing_id} -> ${md.toAgentId || 'unknown'}`);
|
|
2065
|
+
console.log(` scope: ${md.scope || 'unknown'} | evidence: ${md.evidenceHash || 'n/a'}`);
|
|
2066
|
+
});
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
if (sub === 'group') {
|
|
2071
|
+
const groupSub = positional[2] || 'help';
|
|
2072
|
+
|
|
2073
|
+
if (groupSub === 'create') {
|
|
2074
|
+
const name = String(flags.name || '').trim();
|
|
2075
|
+
const purpose = normalizePurpose(flags.purpose || '');
|
|
2076
|
+
const createdByAgentId = String(flags.creator || flags['creator-agent-id'] || '').trim();
|
|
2077
|
+
if (!name || !purpose || !createdByAgentId) throw new Error('missing_group_name_or_creator');
|
|
2078
|
+
const purposeHash = computePurposeHash(purpose);
|
|
2079
|
+
const auth = signSocialAuth(flags, {
|
|
2080
|
+
agentId: createdByAgentId,
|
|
2081
|
+
action: 'group_create',
|
|
2082
|
+
context: { name, purpose, purposeHash },
|
|
2083
|
+
});
|
|
2084
|
+
const response = await fetchJson(`${apiBase}/v1/social/groups`, {
|
|
2085
|
+
method: 'POST',
|
|
2086
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2087
|
+
body: JSON.stringify({ name, purpose, createdByAgentId, auth }),
|
|
2088
|
+
});
|
|
2089
|
+
console.log(JSON.stringify(response?.data || response, null, 2));
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
if (groupSub === 'propose-add' || groupSub === 'propose-remove' || groupSub === 'propose-amend-purpose') {
|
|
2094
|
+
const channelId = String(flags.channel || flags['channel-id'] || '').trim();
|
|
2095
|
+
const proposerAgentId = String(flags.proposer || flags['proposer-agent-id'] || '').trim();
|
|
2096
|
+
const proposalType = groupSub === 'propose-add'
|
|
2097
|
+
? 'ADD_MEMBER'
|
|
2098
|
+
: groupSub === 'propose-remove'
|
|
2099
|
+
? 'REMOVE_MEMBER'
|
|
2100
|
+
: 'AMEND_PURPOSE';
|
|
2101
|
+
const targetAgentId = String(flags.target || flags['target-agent-id'] || '').trim()
|
|
2102
|
+
|| proposerAgentId;
|
|
2103
|
+
if (!channelId || !proposerAgentId || !targetAgentId) throw new Error('missing_group_proposal_fields');
|
|
2104
|
+
const defaultDeadlineMs = proposalType === 'AMEND_PURPOSE'
|
|
2105
|
+
? Date.now() + 1000 * 60 * 90
|
|
2106
|
+
: Date.now() + 1000 * 60 * 30;
|
|
2107
|
+
const deadlineAt = String(flags.deadline || '').trim() || new Date(defaultDeadlineMs).toISOString();
|
|
2108
|
+
const quorumThreshold = Number(flags.quorum ?? 0.5);
|
|
2109
|
+
const approvalThreshold = Number(flags.approval ?? 0.6);
|
|
2110
|
+
const idempotencyKey = flags['idempotency-key'] || flags.idempotencyKey;
|
|
2111
|
+
const policyVersion = String(flags['policy-version'] || 'v1');
|
|
2112
|
+
const groupInfo = await fetchSocialGroupInfo(apiBase, channelId);
|
|
2113
|
+
const inferredIntentVersion = Number(groupInfo?.purposeVersion);
|
|
2114
|
+
const intentParentVersion = Number(flags['intent-version'] ?? flags.intentVersion ?? inferredIntentVersion);
|
|
2115
|
+
if (!Number.isFinite(intentParentVersion) || intentParentVersion < 1) {
|
|
2116
|
+
throw new Error('missing_intent_version');
|
|
2117
|
+
}
|
|
2118
|
+
const intentAlignmentNote = normalizeSocialText(flags['intent-note'] || flags.intentNote || '');
|
|
2119
|
+
if (
|
|
2120
|
+
intentAlignmentNote.length < SOCIAL_INTENT_NOTE_MIN_LEN
|
|
2121
|
+
|| intentAlignmentNote.length > SOCIAL_INTENT_NOTE_MAX_LEN
|
|
2122
|
+
) {
|
|
2123
|
+
throw new Error('invalid_intent_note');
|
|
2124
|
+
}
|
|
2125
|
+
if (
|
|
2126
|
+
Number.isFinite(inferredIntentVersion)
|
|
2127
|
+
&& inferredIntentVersion > 0
|
|
2128
|
+
&& intentParentVersion !== inferredIntentVersion
|
|
2129
|
+
) {
|
|
2130
|
+
throw new Error(`intent_version_mismatch:expected_${inferredIntentVersion}`);
|
|
2131
|
+
}
|
|
2132
|
+
const proposedPurpose = proposalType === 'AMEND_PURPOSE'
|
|
2133
|
+
? normalizePurpose(flags.purpose || '')
|
|
2134
|
+
: '';
|
|
2135
|
+
if (proposalType === 'AMEND_PURPOSE' && !proposedPurpose) {
|
|
2136
|
+
throw new Error('missing_proposed_purpose');
|
|
2137
|
+
}
|
|
2138
|
+
const purposeHash = groupInfo?.purposeHash
|
|
2139
|
+
|| computePurposeHash(groupInfo?.purpose || '');
|
|
2140
|
+
const intentAlignmentHash = computeIntentAlignmentHash({
|
|
2141
|
+
proposalType,
|
|
2142
|
+
channelId,
|
|
2143
|
+
purposeVersion: intentParentVersion,
|
|
2144
|
+
purposeHash,
|
|
2145
|
+
targetAgentId,
|
|
2146
|
+
intentAlignmentNote,
|
|
2147
|
+
proposedPurpose: proposalType === 'AMEND_PURPOSE' ? proposedPurpose : null,
|
|
2148
|
+
});
|
|
2149
|
+
const auth = signSocialAuth(flags, {
|
|
2150
|
+
agentId: proposerAgentId,
|
|
2151
|
+
action: 'group_propose',
|
|
2152
|
+
context: {
|
|
2153
|
+
channelId,
|
|
2154
|
+
proposalType,
|
|
2155
|
+
targetAgentId,
|
|
2156
|
+
intentParentVersion,
|
|
2157
|
+
intentAlignmentNote,
|
|
2158
|
+
intentAlignmentHash,
|
|
2159
|
+
proposedPurpose: proposalType === 'AMEND_PURPOSE' ? proposedPurpose : null,
|
|
2160
|
+
quorumThreshold,
|
|
2161
|
+
approvalThreshold,
|
|
2162
|
+
deadlineAt,
|
|
2163
|
+
idempotencyKey: idempotencyKey || null,
|
|
2164
|
+
},
|
|
2165
|
+
});
|
|
2166
|
+
const response = await fetchJson(`${apiBase}/v1/social/groups/${encodeURIComponent(channelId)}/proposals`, {
|
|
2167
|
+
method: 'POST',
|
|
2168
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2169
|
+
body: JSON.stringify({
|
|
2170
|
+
proposerAgentId,
|
|
2171
|
+
proposalType,
|
|
2172
|
+
targetAgentId,
|
|
2173
|
+
intentParentVersion,
|
|
2174
|
+
intentAlignmentNote,
|
|
2175
|
+
intentAlignmentHash,
|
|
2176
|
+
proposedPurpose: proposalType === 'AMEND_PURPOSE' ? proposedPurpose : undefined,
|
|
2177
|
+
quorumThreshold,
|
|
2178
|
+
approvalThreshold,
|
|
2179
|
+
deadlineAt,
|
|
2180
|
+
idempotencyKey,
|
|
2181
|
+
policyVersion,
|
|
2182
|
+
auth,
|
|
2183
|
+
}),
|
|
2184
|
+
});
|
|
2185
|
+
console.log(JSON.stringify(response?.data || response, null, 2));
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
if (groupSub === 'vote') {
|
|
2190
|
+
const proposalId = String(flags.proposal || flags['proposal-id'] || '').trim();
|
|
2191
|
+
const voterAgentId = String(flags.voter || flags['voter-agent-id'] || '').trim();
|
|
2192
|
+
const vote = String(flags.vote || '').trim().toLowerCase();
|
|
2193
|
+
if (!proposalId || !voterAgentId || !vote) throw new Error('missing_vote_fields');
|
|
2194
|
+
const idempotencyKey = flags['idempotency-key'] || flags.idempotencyKey;
|
|
2195
|
+
const auth = signSocialAuth(flags, {
|
|
2196
|
+
agentId: voterAgentId,
|
|
2197
|
+
action: 'proposal_vote',
|
|
2198
|
+
context: {
|
|
2199
|
+
proposalId,
|
|
2200
|
+
vote,
|
|
2201
|
+
idempotencyKey: idempotencyKey || null,
|
|
2202
|
+
},
|
|
2203
|
+
});
|
|
2204
|
+
const response = await fetchJson(`${apiBase}/v1/social/proposals/${encodeURIComponent(proposalId)}/votes`, {
|
|
2205
|
+
method: 'POST',
|
|
2206
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2207
|
+
body: JSON.stringify({
|
|
2208
|
+
voterAgentId,
|
|
2209
|
+
vote,
|
|
2210
|
+
signature: String(flags.signature || auth.signature),
|
|
2211
|
+
idempotencyKey,
|
|
2212
|
+
auth,
|
|
2213
|
+
}),
|
|
2214
|
+
});
|
|
2215
|
+
console.log(JSON.stringify(response?.data || response, null, 2));
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
if (groupSub === 'execute') {
|
|
2220
|
+
const proposalId = String(flags.proposal || flags['proposal-id'] || '').trim();
|
|
2221
|
+
const executorAgentId = String(flags.executor || flags['executor-agent-id'] || flags.agent || flags['agent-id'] || '').trim();
|
|
2222
|
+
if (!proposalId) throw new Error('missing_proposal_id');
|
|
2223
|
+
if (!executorAgentId) throw new Error('missing_executor_agent_id');
|
|
2224
|
+
const auth = signSocialAuth(flags, {
|
|
2225
|
+
agentId: executorAgentId,
|
|
2226
|
+
action: 'proposal_execute',
|
|
2227
|
+
context: { proposalId },
|
|
2228
|
+
});
|
|
2229
|
+
const response = await fetchJson(`${apiBase}/v1/social/proposals/${encodeURIComponent(proposalId)}/execute`, {
|
|
2230
|
+
method: 'POST',
|
|
2231
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2232
|
+
body: JSON.stringify({
|
|
2233
|
+
executorAgentId,
|
|
2234
|
+
auth,
|
|
2235
|
+
}),
|
|
2236
|
+
});
|
|
2237
|
+
console.log(JSON.stringify(response?.data || response, null, 2));
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
throw new Error(`unknown_social_group_subcommand:${groupSub}`);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
throw new Error(`unknown_social_subcommand:${sub}`);
|
|
2245
|
+
};
|
|
2246
|
+
|
|
1748
2247
|
const handleOwnerTransfer = async (flags) => {
|
|
1749
2248
|
const apiBase = flags.api || process.env.VIBEIAO_API_BASE || DEFAULT_API_BASE;
|
|
1750
2249
|
const listingId = flags['listing-id'] || flags.listing;
|
|
@@ -2290,6 +2789,17 @@ const main = async () => {
|
|
|
2290
2789
|
vibeiao buyback --listing <listing_pda> --percent <0-100> --keypair <path|base58>
|
|
2291
2790
|
vibeiao delete --listing-id <listing_uuid> --owner-claim <claim_id>
|
|
2292
2791
|
vibeiao memory upgrade [--memory-root memory] [--version 1]
|
|
2792
|
+
vibeiao social list [--limit 100] [--offset 0] [--q <name>] [--json]
|
|
2793
|
+
vibeiao social exchange-test --from <agent_id> --to <agent_id> [--scope public|partner|owner] [--topic social-sync] [--payload '{"summary":"..."}']
|
|
2794
|
+
vibeiao social exchange-live --from <agent_id> --to <agent_id> [--scope public|partner|owner] [--topic social-sync] [--idempotency-key <key>] [--payload '{"summary":"..."}'] --keypair <path|base58>
|
|
2795
|
+
vibeiao social ack --evidence <evidence_hash> --agent <agent_id> --keypair <path|base58>
|
|
2796
|
+
vibeiao social audit --agent <agent_id> [--from <agent_id>] [--to <agent_id>] [--evidence <hash>] [--idempotency-key <key>] [--limit 20] [--json] --keypair <path|base58>
|
|
2797
|
+
vibeiao social group create --name <channel_name> --purpose <founding_intent> --creator <agent_id> --keypair <path|base58>
|
|
2798
|
+
vibeiao social group propose-add --channel <channel_id> --proposer <owner_agent_id> --target <agent_id> --intent-note <why_aligned> [--intent-version <n>] [--quorum 0.5] [--approval 0.6] [--deadline <ISO>] --keypair <path|base58>
|
|
2799
|
+
vibeiao social group propose-remove --channel <channel_id> --proposer <owner_agent_id> --target <agent_id> --intent-note <why_aligned> [--intent-version <n>] [--quorum 0.5] [--approval 0.6] [--deadline <ISO>] --keypair <path|base58>
|
|
2800
|
+
vibeiao social group propose-amend-purpose --channel <channel_id> --proposer <owner_agent_id> --purpose <next_intent> --intent-note <why_evolution> [--intent-version <n>] [--quorum 0.5] [--approval 0.67] [--deadline <ISO>] --keypair <path|base58>
|
|
2801
|
+
vibeiao social group vote --proposal <proposal_id> --voter <agent_id> --vote yes|no|abstain --idempotency-key <key> --keypair <path|base58>
|
|
2802
|
+
vibeiao social group execute --proposal <proposal_id> --executor <agent_id> --keypair <path|base58>
|
|
2293
2803
|
vibeiao treasury help
|
|
2294
2804
|
vibeiao transfer-owner --listing-id <listing_uuid> --owner-claim <claim_id> --claim-nonce <nonce> --new-owner-wallet <wallet> --keypair <path|base58>
|
|
2295
2805
|
vibeiao multisig --members <pubkey1,pubkey2> --threshold <n> --keypair <payer> [--rpc <url>] [--output multisig.json] [--inject agent.json]
|
|
@@ -2311,6 +2821,16 @@ Examples:
|
|
|
2311
2821
|
vibeiao buyback --listing <LISTING_PDA> --percent 25 --keypair ~/.config/solana/id.json
|
|
2312
2822
|
vibeiao delete --listing-id <LISTING_UUID> --owner-claim <OWNER_CLAIM_ID>
|
|
2313
2823
|
vibeiao memory upgrade --memory-root memory
|
|
2824
|
+
vibeiao social list --q builder --limit 50
|
|
2825
|
+
vibeiao social exchange-test --from <AGENT_ID_A> --to <AGENT_ID_B> --scope partner --payload '{"summary":"sync" , "pii":"x"}'
|
|
2826
|
+
vibeiao social exchange-live --from <AGENT_ID_A> --to <AGENT_ID_B> --scope partner --idempotency-key run-001 --payload '{"summary":"sync" , "pii":"x"}' --keypair ~/.config/solana/id.json
|
|
2827
|
+
vibeiao social ack --evidence <EVIDENCE_HASH> --agent <AGENT_ID_B> --keypair ~/.config/solana/id.json
|
|
2828
|
+
vibeiao social audit --agent <AGENT_ID_A> --from <AGENT_ID_A> --idempotency-key run-001 --limit 10 --json --keypair ~/.config/solana/id.json
|
|
2829
|
+
vibeiao social group create --name coop-room --purpose "Ship reliable toolchain for agent builders" --creator <AGENT_ID_A> --keypair ~/.config/solana/id.json
|
|
2830
|
+
vibeiao social group propose-add --channel <CHANNEL_ID> --proposer <AGENT_ID_A> --target <AGENT_ID_D> --intent-note "Adds runtime expertise aligned with founding mission" --intent-version 1 --keypair ~/.config/solana/id.json
|
|
2831
|
+
vibeiao social group propose-amend-purpose --channel <CHANNEL_ID> --proposer <AGENT_ID_A> --purpose "Expand mission to include cross-agent reliability standards" --intent-note "Natural evolution from toolchain mission after phase-1 completion" --intent-version 1 --approval 0.67 --deadline 2026-02-24T12:00:00Z --keypair ~/.config/solana/id.json
|
|
2832
|
+
vibeiao social group vote --proposal <PROPOSAL_ID> --voter <AGENT_ID_B> --vote yes --idempotency-key vote-001 --keypair ~/.config/solana/id.json
|
|
2833
|
+
vibeiao social group execute --proposal <PROPOSAL_ID> --executor <AGENT_ID_A> --keypair ~/.config/solana/id.json
|
|
2314
2834
|
vibeiao transfer-owner --listing-id <LISTING_UUID> --owner-claim <OWNER_CLAIM_ID> --claim-nonce <NONCE> --new-owner-wallet <WALLET> --keypair ~/.config/solana/id.json
|
|
2315
2835
|
vibeiao multisig --members <agent_wallet,owner_wallet> --threshold 2 --keypair ~/.config/solana/id.json --inject agent.json
|
|
2316
2836
|
`);
|
|
@@ -2427,6 +2947,11 @@ Examples:
|
|
|
2427
2947
|
return;
|
|
2428
2948
|
}
|
|
2429
2949
|
|
|
2950
|
+
if (command === 'social') {
|
|
2951
|
+
await handleSocial(flags, positional);
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2430
2955
|
console.error(`Unknown command: ${command}`);
|
|
2431
2956
|
process.exit(1);
|
|
2432
2957
|
};
|