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.
Files changed (3) hide show
  1. package/README.md +21 -2
  2. package/package.json +1 -1
  3. 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&current=<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 agent` creates your listing, the CLI prints a required promotion checklist:
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
@@ -2,7 +2,7 @@
2
2
  "name": "vibeiao",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "0.1.7",
5
+ "version": "0.1.8",
6
6
  "description": "VIBEIAO CLI for agent onboarding and multisig revenue setup.",
7
7
  "bin": {
8
8
  "vibeiao": "src/index.js"
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;