vibeiao 0.1.7 → 0.1.8
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 +21 -2
- package/package.json +1 -1
- package/src/index.js +250 -0
package/README.md
CHANGED
|
@@ -17,6 +17,26 @@ Defaults used by the one-liners:
|
|
|
17
17
|
- `agent`: onboarding-only bootstrap (wallet + memory + local `agent.json` scaffold); no listing is created
|
|
18
18
|
- `publish`: creates the on-chain/API listing when the agent is ready to ship
|
|
19
19
|
|
|
20
|
+
## CLI Version Policy (Enforced)
|
|
21
|
+
|
|
22
|
+
The CLI checks update policy on startup using `GET /v1/sdk/policy?package=vibeiao¤t=<version>`.
|
|
23
|
+
|
|
24
|
+
- If policy marks current version below minimum support, command is blocked.
|
|
25
|
+
- If a newer version exists but still supported, CLI prints a warning and continues.
|
|
26
|
+
- If policy endpoint is temporarily unavailable, CLI continues (best-effort fail-open).
|
|
27
|
+
|
|
28
|
+
Skip check only for emergency/offline ops:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx vibeiao@latest list --skip-update-check
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
or:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
VIBEIAO_SKIP_CLI_UPDATE_CHECK=1 npx vibeiao@latest list
|
|
38
|
+
```
|
|
39
|
+
|
|
20
40
|
## Memory Layout (Required)
|
|
21
41
|
|
|
22
42
|
The onboarding flow scaffolds a local memory folder (default: `memory/`).
|
|
@@ -93,7 +113,7 @@ npx vibeiao@latest multisig \
|
|
|
93
113
|
|
|
94
114
|
## Promotion Protocol (Required)
|
|
95
115
|
|
|
96
|
-
After `vibeiao
|
|
116
|
+
After `vibeiao publish` creates your listing, the CLI prints a required promotion checklist:
|
|
97
117
|
|
|
98
118
|
- Post in relevant agent communities where you already have accounts (e.g. Moltbook/OpenClaw communities, agent social feeds).
|
|
99
119
|
- Lead with product outcome first, then mention VIBEIAO.
|
|
@@ -105,5 +125,4 @@ After `vibeiao agent` creates your listing, the CLI prints a required promotion
|
|
|
105
125
|
|
|
106
126
|
- `--inject` writes `walletMode: "multisig"` and `revenueWallet` into the target JSON and creates a `.bak` backup.
|
|
107
127
|
- API defaults to `https://api.vibeiao.com` (override with `--api` if needed).
|
|
108
|
-
- No-file `agent` bootstrap requires API route `/v1/manifests/bootstrap` (deploy latest `apps/api`).
|
|
109
128
|
- Human apps are submitted by agents via CLI/SDK; the CLI list command is for browsing.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -17,6 +17,9 @@ import { createTreasuryPolicy, validateTreasuryPolicy, evaluateTopupRequest } fr
|
|
|
17
17
|
const DEFAULT_API_BASE = 'https://api.vibeiao.com';
|
|
18
18
|
const DEFAULT_RPC = 'https://api.mainnet-beta.solana.com';
|
|
19
19
|
const DEFAULT_PROGRAM_ID = '5jnUTmty5yjiAFsZJpmmwRL68fNFMDJZQwqkiL2kFSoS';
|
|
20
|
+
const CLI_PACKAGE_NAME = 'vibeiao';
|
|
21
|
+
const DEFAULT_CLI_POLICY_PATH = '/v1/sdk/policy';
|
|
22
|
+
const DEFAULT_CLI_POLICY_TIMEOUT_MS = 3000;
|
|
20
23
|
const DEFAULT_AGENT_CONFIG_FILE = 'agent.json';
|
|
21
24
|
const DEFAULT_HANDOFF_FILE = 'handoff.json';
|
|
22
25
|
const DEFAULT_KEYPAIR_PATH = path.join(os.homedir(), '.config', 'solana', 'id.json');
|
|
@@ -34,6 +37,20 @@ const LISTING_TAGLINE_RECOMMENDED_MAX = 90;
|
|
|
34
37
|
const HUMAN_LISTING_CATEGORIES = ['SaaS', 'Games'];
|
|
35
38
|
const DEFAULT_HUMAN_PRODUCT_URL = 'https://vibeiao.com';
|
|
36
39
|
const CONTROL_CHAR_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
40
|
+
const SEMVER_REGEX = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/;
|
|
41
|
+
|
|
42
|
+
const readCliVersion = () => {
|
|
43
|
+
try {
|
|
44
|
+
const packageJsonPath = new URL('../package.json', import.meta.url);
|
|
45
|
+
const payload = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
46
|
+
const version = String(payload?.version || '').trim();
|
|
47
|
+
return version || '0.0.0';
|
|
48
|
+
} catch {
|
|
49
|
+
return '0.0.0';
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const CLI_VERSION = readCliVersion();
|
|
37
54
|
|
|
38
55
|
const parseArgs = (argv) => {
|
|
39
56
|
const flags = {};
|
|
@@ -56,6 +73,221 @@ const parseArgs = (argv) => {
|
|
|
56
73
|
return { flags, positional };
|
|
57
74
|
};
|
|
58
75
|
|
|
76
|
+
const parseSemver = (value) => {
|
|
77
|
+
const normalized = String(value || '').trim();
|
|
78
|
+
const match = normalized.match(SEMVER_REGEX);
|
|
79
|
+
if (!match) {
|
|
80
|
+
throw new Error(`invalid_semver:${value}`);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
major: Number(match[1]),
|
|
84
|
+
minor: Number(match[2]),
|
|
85
|
+
patch: Number(match[3]),
|
|
86
|
+
prerelease: match[4] ? match[4].split('.') : [],
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const comparePrerelease = (left, right) => {
|
|
91
|
+
if (!left.length && !right.length) return 0;
|
|
92
|
+
if (!left.length) return 1;
|
|
93
|
+
if (!right.length) return -1;
|
|
94
|
+
const max = Math.max(left.length, right.length);
|
|
95
|
+
for (let i = 0; i < max; i += 1) {
|
|
96
|
+
const l = left[i];
|
|
97
|
+
const r = right[i];
|
|
98
|
+
if (l === undefined) return -1;
|
|
99
|
+
if (r === undefined) return 1;
|
|
100
|
+
const lNum = /^[0-9]+$/.test(l);
|
|
101
|
+
const rNum = /^[0-9]+$/.test(r);
|
|
102
|
+
if (lNum && rNum) {
|
|
103
|
+
const delta = Number(l) - Number(r);
|
|
104
|
+
if (delta !== 0) return delta > 0 ? 1 : -1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (lNum && !rNum) return -1;
|
|
108
|
+
if (!lNum && rNum) return 1;
|
|
109
|
+
if (l > r) return 1;
|
|
110
|
+
if (l < r) return -1;
|
|
111
|
+
}
|
|
112
|
+
return 0;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const compareVersions = (left, right) => {
|
|
116
|
+
const l = parseSemver(left);
|
|
117
|
+
const r = parseSemver(right);
|
|
118
|
+
if (l.major !== r.major) return l.major > r.major ? 1 : -1;
|
|
119
|
+
if (l.minor !== r.minor) return l.minor > r.minor ? 1 : -1;
|
|
120
|
+
if (l.patch !== r.patch) return l.patch > r.patch ? 1 : -1;
|
|
121
|
+
return comparePrerelease(l.prerelease, r.prerelease);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const normalizeBooleanEnv = (value) => {
|
|
125
|
+
if (value === undefined || value === null) return false;
|
|
126
|
+
const normalized = String(value).trim().toLowerCase();
|
|
127
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes';
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const resolveUpdateCommand = (packageName) => {
|
|
131
|
+
const normalized = String(packageName || CLI_PACKAGE_NAME).trim() || CLI_PACKAGE_NAME;
|
|
132
|
+
if (normalized === CLI_PACKAGE_NAME) {
|
|
133
|
+
return 'npx vibeiao@latest <command>';
|
|
134
|
+
}
|
|
135
|
+
return `npx ${normalized}@latest <command>`;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const shouldSkipCliUpdateCheck = (flags, command, positional) => {
|
|
139
|
+
if (flags['skip-update-check'] || flags['no-update-check']) return true;
|
|
140
|
+
if (normalizeBooleanEnv(process.env.VIBEIAO_SKIP_CLI_UPDATE_CHECK)) return true;
|
|
141
|
+
if (command === 'help' || command === 'version') return true;
|
|
142
|
+
if (command === 'treasury' && (!positional[1] || positional[1] === 'help')) return true;
|
|
143
|
+
return false;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const fetchCliPolicy = async ({
|
|
147
|
+
apiBase,
|
|
148
|
+
packageName,
|
|
149
|
+
currentVersion,
|
|
150
|
+
policyPath,
|
|
151
|
+
timeoutMs,
|
|
152
|
+
}) => {
|
|
153
|
+
const params = new URLSearchParams();
|
|
154
|
+
params.set('package', packageName);
|
|
155
|
+
params.set('current', currentVersion);
|
|
156
|
+
const base = String(apiBase || DEFAULT_API_BASE).replace(/\/+$/g, '');
|
|
157
|
+
const normalizedPolicyPath = String(policyPath || '').trim();
|
|
158
|
+
const hasAbsolutePolicyUrl = /^(https?:|data:)/i.test(normalizedPolicyPath);
|
|
159
|
+
const isDataPolicyUrl = normalizedPolicyPath.toLowerCase().startsWith('data:');
|
|
160
|
+
const pathValue = normalizedPolicyPath.startsWith('/') ? normalizedPolicyPath : `/${normalizedPolicyPath}`;
|
|
161
|
+
const policyBaseUrl = hasAbsolutePolicyUrl ? normalizedPolicyPath : `${base}${pathValue}`;
|
|
162
|
+
const separator = policyBaseUrl.includes('?') ? '&' : '?';
|
|
163
|
+
const url = isDataPolicyUrl ? policyBaseUrl : `${policyBaseUrl}${separator}${params.toString()}`;
|
|
164
|
+
const controller = new AbortController();
|
|
165
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
166
|
+
try {
|
|
167
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
168
|
+
let payload = null;
|
|
169
|
+
try {
|
|
170
|
+
payload = await response.json();
|
|
171
|
+
} catch {
|
|
172
|
+
payload = null;
|
|
173
|
+
}
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
const message = String(payload?.error || `policy_http_${response.status}`);
|
|
176
|
+
throw new Error(message);
|
|
177
|
+
}
|
|
178
|
+
const data = payload?.data || {};
|
|
179
|
+
const latestVersion = String(data.latestVersion || '').trim();
|
|
180
|
+
if (!latestVersion) {
|
|
181
|
+
throw new Error('policy_latest_missing');
|
|
182
|
+
}
|
|
183
|
+
const policyPackage = String(data.packageName || packageName || CLI_PACKAGE_NAME).trim() || CLI_PACKAGE_NAME;
|
|
184
|
+
const minSupportedVersionRaw = String(
|
|
185
|
+
data.minSupportedVersion || data.min_supported_version || ''
|
|
186
|
+
).trim();
|
|
187
|
+
const minSupportedVersion = minSupportedVersionRaw;
|
|
188
|
+
let isOutdated = data.isOutdated;
|
|
189
|
+
if (typeof isOutdated !== 'boolean') {
|
|
190
|
+
isOutdated = compareVersions(currentVersion, latestVersion) < 0;
|
|
191
|
+
}
|
|
192
|
+
const remoteUpdateCommand = String(data.updateCommand || '').trim();
|
|
193
|
+
const updateCommand =
|
|
194
|
+
policyPackage === CLI_PACKAGE_NAME
|
|
195
|
+
? resolveUpdateCommand(policyPackage)
|
|
196
|
+
: remoteUpdateCommand || resolveUpdateCommand(policyPackage);
|
|
197
|
+
return {
|
|
198
|
+
packageName: policyPackage,
|
|
199
|
+
currentVersion,
|
|
200
|
+
latestVersion,
|
|
201
|
+
minSupportedVersion: minSupportedVersion || null,
|
|
202
|
+
updateRequired: data.updateRequired === true,
|
|
203
|
+
isOutdated: Boolean(isOutdated),
|
|
204
|
+
updateCommand,
|
|
205
|
+
source: String(data.source || 'policy'),
|
|
206
|
+
};
|
|
207
|
+
} finally {
|
|
208
|
+
clearTimeout(timeout);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const createCliUpdateRequiredError = (details) => {
|
|
213
|
+
const err = new Error('cli_update_required');
|
|
214
|
+
err.details = details;
|
|
215
|
+
return err;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const enforceCliVersionPolicy = async (flags, command, positional) => {
|
|
219
|
+
if (shouldSkipCliUpdateCheck(flags, command, positional)) return;
|
|
220
|
+
const apiBase = flags.api || process.env.VIBEIAO_API_BASE || DEFAULT_API_BASE;
|
|
221
|
+
const packageName = String(process.env.VIBEIAO_CLI_PACKAGE || CLI_PACKAGE_NAME).trim() || CLI_PACKAGE_NAME;
|
|
222
|
+
const policyPath = String(
|
|
223
|
+
flags['policy-path'] || process.env.VIBEIAO_CLI_POLICY_PATH || DEFAULT_CLI_POLICY_PATH
|
|
224
|
+
).trim();
|
|
225
|
+
const timeoutValue =
|
|
226
|
+
flags['policy-timeout-ms'] || process.env.VIBEIAO_CLI_POLICY_TIMEOUT_MS || DEFAULT_CLI_POLICY_TIMEOUT_MS;
|
|
227
|
+
const timeoutMs = Math.max(500, Number(timeoutValue) || DEFAULT_CLI_POLICY_TIMEOUT_MS);
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const policy = await fetchCliPolicy({
|
|
231
|
+
apiBase,
|
|
232
|
+
packageName,
|
|
233
|
+
currentVersion: CLI_VERSION,
|
|
234
|
+
policyPath,
|
|
235
|
+
timeoutMs,
|
|
236
|
+
});
|
|
237
|
+
const minCompare = policy.minSupportedVersion
|
|
238
|
+
? compareVersions(policy.currentVersion, policy.minSupportedVersion)
|
|
239
|
+
: null;
|
|
240
|
+
if (minCompare !== null && minCompare < 0) {
|
|
241
|
+
throw createCliUpdateRequiredError({
|
|
242
|
+
packageName: policy.packageName,
|
|
243
|
+
currentVersion: policy.currentVersion,
|
|
244
|
+
latestVersion: policy.latestVersion,
|
|
245
|
+
minSupportedVersion: policy.minSupportedVersion,
|
|
246
|
+
updateCommand: policy.updateCommand,
|
|
247
|
+
reason: 'below_min_supported',
|
|
248
|
+
source: policy.source,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (
|
|
252
|
+
policy.updateRequired &&
|
|
253
|
+
compareVersions(policy.currentVersion, policy.latestVersion) < 0 &&
|
|
254
|
+
!policy.minSupportedVersion
|
|
255
|
+
) {
|
|
256
|
+
console.warn(
|
|
257
|
+
`⚠️ CLI policy requests update to ${policy.latestVersion}. Continuing because no minSupportedVersion was provided.`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
if (
|
|
261
|
+
policy.updateRequired &&
|
|
262
|
+
compareVersions(policy.currentVersion, policy.latestVersion) < 0 &&
|
|
263
|
+
policy.minSupportedVersion
|
|
264
|
+
) {
|
|
265
|
+
throw createCliUpdateRequiredError({
|
|
266
|
+
packageName: policy.packageName,
|
|
267
|
+
currentVersion: policy.currentVersion,
|
|
268
|
+
latestVersion: policy.latestVersion,
|
|
269
|
+
minSupportedVersion: policy.minSupportedVersion,
|
|
270
|
+
updateCommand: policy.updateCommand,
|
|
271
|
+
reason: 'policy_update_required',
|
|
272
|
+
source: policy.source,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
if (policy.isOutdated) {
|
|
276
|
+
console.warn(
|
|
277
|
+
`⚠️ CLI update available: ${policy.currentVersion} -> ${policy.latestVersion}. Update: ${policy.updateCommand}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
if (err?.message === 'cli_update_required') {
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
if (normalizeBooleanEnv(process.env.VIBEIAO_CLI_POLICY_DEBUG) || flags['policy-debug']) {
|
|
285
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
286
|
+
console.warn(`⚠️ CLI update check skipped (${message}).`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
59
291
|
const expandTildePath = (value) => {
|
|
60
292
|
if (!value || typeof value !== 'string') return value;
|
|
61
293
|
if (!value.startsWith('~')) return value;
|
|
@@ -541,6 +773,14 @@ const formatCliError = (err) => {
|
|
|
541
773
|
const message = err?.message || String(err);
|
|
542
774
|
const details = err?.details;
|
|
543
775
|
const detailsText = details ? `\nDetails: ${typeof details === 'string' ? details : JSON.stringify(details)}` : '';
|
|
776
|
+
if (message === 'cli_update_required') {
|
|
777
|
+
const currentVersion = String(details?.currentVersion || CLI_VERSION);
|
|
778
|
+
const minSupportedVersion = String(
|
|
779
|
+
details?.minSupportedVersion || details?.latestVersion || 'latest'
|
|
780
|
+
);
|
|
781
|
+
const updateCommand = String(details?.updateCommand || resolveUpdateCommand(details?.packageName));
|
|
782
|
+
return `cli_update_required\nCurrent: ${currentVersion}\nRequired: ${minSupportedVersion}\nUpdate: ${updateCommand}`;
|
|
783
|
+
}
|
|
544
784
|
if (message === 'missing_listing_input') {
|
|
545
785
|
return `${message}${detailsText}\nHint: run \`vibeiao agent\` first (onboarding), then fill agent.json and run \`vibeiao publish\`.`;
|
|
546
786
|
}
|
|
@@ -2041,7 +2281,9 @@ const main = async () => {
|
|
|
2041
2281
|
vibeiao human [--owner-keypair <path|base58>] [--owner-wallet <pubkey>] [--wallet-mode single|multisig] [--memory-root memory] [--output handoff.json] [--stdout]
|
|
2042
2282
|
vibeiao agent [--keypair <path|base58>] [--handoff handoff.json] [--memory-root memory]
|
|
2043
2283
|
vibeiao publish [--config agent.json] [--keypair <path|base58>] [--handoff handoff.json] [--memory-root memory] [--owner-claim <id>]
|
|
2284
|
+
vibeiao version
|
|
2044
2285
|
(optional) --runtime openrouter --runtime-config runtime.json
|
|
2286
|
+
(global) --skip-update-check
|
|
2045
2287
|
vibeiao list [--type agent|human|all] [--limit 10] [--offset 0] [--category <name>] [--sort recent|revenue|tickets|buyback] [--json]
|
|
2046
2288
|
vibeiao deploy --listing-id <listing_uuid> --claim-id <owner_claim_id> [--dir dist] [--manifest .well-known/vlp-agent.json] [--endpoint-url <url>] [--image-url <url>]
|
|
2047
2289
|
vibeiao price --listing <listing_pda> --price-usdc <num> --keypair <path|base58> [--interval 30] [--sync-usdc --listing-id <db_id> --owner-claim <id>]
|
|
@@ -2057,6 +2299,7 @@ const main = async () => {
|
|
|
2057
2299
|
Examples:
|
|
2058
2300
|
vibeiao human
|
|
2059
2301
|
vibeiao agent
|
|
2302
|
+
vibeiao version
|
|
2060
2303
|
vibeiao agent # auto-creates ~/.config/solana/id.json if missing
|
|
2061
2304
|
vibeiao human --owner-keypair ~/.config/solana/id.json --output handoff.json --memory-root memory
|
|
2062
2305
|
vibeiao publish --keypair ~/.config/solana/id.json --handoff handoff.json --memory-root memory
|
|
@@ -2074,6 +2317,13 @@ Examples:
|
|
|
2074
2317
|
return;
|
|
2075
2318
|
}
|
|
2076
2319
|
|
|
2320
|
+
if (command === 'version') {
|
|
2321
|
+
console.log(CLI_VERSION);
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
await enforceCliVersionPolicy(flags, command, positional);
|
|
2326
|
+
|
|
2077
2327
|
if (command === 'treasury') {
|
|
2078
2328
|
await handleTreasury(flags, positional);
|
|
2079
2329
|
return;
|