@amirhosseinnateghi/vibed-cli 0.1.2 → 0.1.3
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/dist/index.js +377 -19
- package/dist/vibed.cjs +11515 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -5973,7 +5973,10 @@ var require_dist = __commonJS({
|
|
|
5973
5973
|
});
|
|
5974
5974
|
|
|
5975
5975
|
// src/index.ts
|
|
5976
|
-
import { resolve as resolve2 } from "node:path";
|
|
5976
|
+
import { resolve as resolve2, join as join3 } from "node:path";
|
|
5977
|
+
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
5978
|
+
import { tmpdir } from "node:os";
|
|
5979
|
+
import { pathToFileURL } from "node:url";
|
|
5977
5980
|
|
|
5978
5981
|
// src/config.ts
|
|
5979
5982
|
import { homedir } from "node:os";
|
|
@@ -6019,6 +6022,18 @@ import { dirname, extname, isAbsolute, join as join2, resolve } from "node:path"
|
|
|
6019
6022
|
// ../sandbox/src/index.ts
|
|
6020
6023
|
var import_node_html_parser = __toESM(require_dist(), 1);
|
|
6021
6024
|
|
|
6025
|
+
// ../shared/src/terms.ts
|
|
6026
|
+
var ITEM = {
|
|
6027
|
+
/** lowercase singular — "vibe" */
|
|
6028
|
+
one: "vibe",
|
|
6029
|
+
/** lowercase plural — "vibes" */
|
|
6030
|
+
many: "vibes",
|
|
6031
|
+
/** Capitalized singular — "Vibe" */
|
|
6032
|
+
One: "Vibe",
|
|
6033
|
+
/** Capitalized plural — "Vibes" */
|
|
6034
|
+
Many: "Vibes"
|
|
6035
|
+
};
|
|
6036
|
+
|
|
6022
6037
|
// ../shared/src/constants.ts
|
|
6023
6038
|
var CATEGORIES = [
|
|
6024
6039
|
"Game",
|
|
@@ -6031,10 +6046,13 @@ var CATEGORIES = [
|
|
|
6031
6046
|
"Other"
|
|
6032
6047
|
];
|
|
6033
6048
|
var VISIBILITY = ["public", "unlisted"];
|
|
6049
|
+
var COVER_MODES = ["image", "gif"];
|
|
6034
6050
|
var EXPERIENCE_SOURCE = ["builder", "import", "remix"];
|
|
6051
|
+
var PUSH_PROVIDERS = ["webpush", "fcm", "apns"];
|
|
6052
|
+
var DEVICE_PLATFORMS = ["web", "ios", "android"];
|
|
6035
6053
|
var config = {
|
|
6036
|
-
ARTIFACT_MAX_BYTES: intEnv("ARTIFACT_MAX_BYTES",
|
|
6037
|
-
//
|
|
6054
|
+
ARTIFACT_MAX_BYTES: intEnv("ARTIFACT_MAX_BYTES", 8388608),
|
|
6055
|
+
// 8 MB — headroom for an embedded audio track
|
|
6038
6056
|
ARTIFACT_ALLOWED_ORIGINS: strEnv(
|
|
6039
6057
|
"ARTIFACT_ALLOWED_ORIGINS",
|
|
6040
6058
|
"fonts.googleapis.com,fonts.gstatic.com,cdnjs.cloudflare.com,cdn.jsdelivr.net,unpkg.com"
|
|
@@ -6057,6 +6075,19 @@ var config = {
|
|
|
6057
6075
|
BUILDER_CLASSIFIER_MODEL: strEnv("BUILDER_CLASSIFIER_MODEL", "gemini-2.5-flash"),
|
|
6058
6076
|
BUILDER_MAX_TOKENS: intEnv("BUILDER_MAX_TOKENS", 8192),
|
|
6059
6077
|
BUILDER_MAX_MESSAGES: intEnv("BUILDER_MAX_MESSAGES", 30),
|
|
6078
|
+
// Hard cap for a single build turn (across the model + one repair). The build
|
|
6079
|
+
// runs detached from the request, so this — not the browser — is what stops a
|
|
6080
|
+
// runaway/abandoned turn. The provider's own 90s per-stall timeout still applies.
|
|
6081
|
+
// Never cut a LIVE generation — these two guards only catch dead work:
|
|
6082
|
+
// stall = total silence (not even a keep-alive byte) long enough to mean the
|
|
6083
|
+
// connection is dead (TCP half-open never errors on its own); the turn cap is
|
|
6084
|
+
// a platform-cost safety ceiling for the whole turn incl. one repair pass.
|
|
6085
|
+
BUILDER_STALL_TIMEOUT_MS: intEnv("BUILDER_STALL_TIMEOUT_MS", 3e5),
|
|
6086
|
+
BUILDER_TURN_TIMEOUT_MS: intEnv("BUILDER_TURN_TIMEOUT_MS", 9e5),
|
|
6087
|
+
// Once a build has run this long, the UI nudges the user to go explore, and on
|
|
6088
|
+
// completion the server drops a notification (§7.1) — so a slow build never
|
|
6089
|
+
// traps them staring at a spinner.
|
|
6090
|
+
BUILDER_SLOW_MS: intEnv("BUILDER_SLOW_MS", 12e3),
|
|
6060
6091
|
DEFAULT_LOCALE: strEnv("DEFAULT_LOCALE", "en")
|
|
6061
6092
|
};
|
|
6062
6093
|
function strEnv(key, fallback) {
|
|
@@ -6079,6 +6110,31 @@ function boolEnv(key, fallback) {
|
|
|
6079
6110
|
return v === "true" || v === "1";
|
|
6080
6111
|
}
|
|
6081
6112
|
|
|
6113
|
+
// ../shared/src/notifications.ts
|
|
6114
|
+
var NOTIF_VERB = {
|
|
6115
|
+
like_milestone: `liked your ${ITEM.one}`,
|
|
6116
|
+
comment: `commented on your ${ITEM.one}`,
|
|
6117
|
+
reply: "replied to your comment",
|
|
6118
|
+
follow: "started following you",
|
|
6119
|
+
mention: "mentioned you",
|
|
6120
|
+
remix: `remixed your ${ITEM.one}`
|
|
6121
|
+
};
|
|
6122
|
+
var SYSTEM_NOTIF = {
|
|
6123
|
+
build_ready: { icon: "\u2728", text: "Your build is ready \u2014 tap to see it", tone: "info" },
|
|
6124
|
+
build_failed: { icon: "\u26A0\uFE0F", text: "A build didn't finish \u2014 tap to try again", tone: "error" },
|
|
6125
|
+
// Moderation reject (spec §9): the vibe never went live (or was pulled), so
|
|
6126
|
+
// the inbox row must carry everything — title + reason arrive in the payload.
|
|
6127
|
+
post_rejected: { icon: "\u{1F6AB}", text: `Your ${ITEM.one} didn't pass moderation`, tone: "error" }
|
|
6128
|
+
};
|
|
6129
|
+
var NOTIF_PREF_GROUPS = ["follow", "comments", "likes", "remixes", "builder"];
|
|
6130
|
+
var NOTIF_GROUP_LABEL = {
|
|
6131
|
+
follow: { title: "New followers", hint: "when someone follows you" },
|
|
6132
|
+
comments: { title: "Comments", hint: "comments, replies & mentions" },
|
|
6133
|
+
likes: { title: "Likes", hint: `when your ${ITEM.many} hit like milestones` },
|
|
6134
|
+
remixes: { title: "Remixes", hint: `when someone remixes your ${ITEM.one}` },
|
|
6135
|
+
builder: { title: "Builder", hint: "when a build finishes or fails" }
|
|
6136
|
+
};
|
|
6137
|
+
|
|
6082
6138
|
// ../shared/src/policy.ts
|
|
6083
6139
|
function boolEnv2(key, fallback) {
|
|
6084
6140
|
const v = typeof process !== "undefined" ? process.env[key] : void 0;
|
|
@@ -10151,10 +10207,102 @@ var coerce = {
|
|
|
10151
10207
|
};
|
|
10152
10208
|
var NEVER = INVALID;
|
|
10153
10209
|
|
|
10210
|
+
// ../shared/src/storage.ts
|
|
10211
|
+
var STORAGE = {
|
|
10212
|
+
/** Total shared bytes per post (values, serialized). */
|
|
10213
|
+
SHARED_MAX_BYTES: intEnv("STORE_SHARED_MAX_BYTES", 1048576),
|
|
10214
|
+
// 1 MB
|
|
10215
|
+
/** Total shared records (rows) per post. */
|
|
10216
|
+
SHARED_MAX_RECORDS: intEnv("STORE_SHARED_MAX_RECORDS", 5e3),
|
|
10217
|
+
/** Serialized size cap for a single value. */
|
|
10218
|
+
VALUE_MAX_BYTES: intEnv("STORE_VALUE_MAX_BYTES", 16384),
|
|
10219
|
+
// 16 KB
|
|
10220
|
+
/** Records a single author may hold in one post (anti-flood / anti-grief). */
|
|
10221
|
+
AUTHOR_MAX_RECORDS: intEnv("STORE_AUTHOR_MAX_RECORDS", 100),
|
|
10222
|
+
/** Distinct collections per post. */
|
|
10223
|
+
MAX_COLLECTIONS: intEnv("STORE_MAX_COLLECTIONS", 32),
|
|
10224
|
+
/** Local-tier budget per (post, identity) — enforced by the host broker. */
|
|
10225
|
+
LOCAL_MAX_BYTES: intEnv("STORE_LOCAL_MAX_BYTES", 262144),
|
|
10226
|
+
// 256 KB
|
|
10227
|
+
/** Max records returnable in one query page. */
|
|
10228
|
+
QUERY_MAX_LIMIT: intEnv("STORE_QUERY_MAX_LIMIT", 100),
|
|
10229
|
+
/** Whether anonymous (logged-out) shared writes may be enabled per post. */
|
|
10230
|
+
ANON_WRITES_AVAILABLE: boolEnv("STORE_ANON_WRITES_AVAILABLE", false)
|
|
10231
|
+
};
|
|
10232
|
+
var COLLECTION_RE = /^[a-z0-9][a-z0-9:_-]{0,63}$/;
|
|
10233
|
+
var collectionSchemaStore = external_exports.string().regex(COLLECTION_RE, "invalid collection name");
|
|
10234
|
+
var STORE_KEY_RE = /^[a-zA-Z0-9][a-zA-Z0-9:._-]{0,127}$/;
|
|
10235
|
+
var RESERVED_STORE_KEYS = ["submit", "rank", "increment"];
|
|
10236
|
+
var storeKeySchema = external_exports.string().regex(STORE_KEY_RE, "invalid key").refine((k) => !RESERVED_STORE_KEYS.includes(k), {
|
|
10237
|
+
message: "reserved key"
|
|
10238
|
+
});
|
|
10239
|
+
var STORE_WRITE_POLICIES = ["anyone", "logged_in", "owner_only"];
|
|
10240
|
+
var STORE_SORTS = ["num", "-num", "created", "-created"];
|
|
10241
|
+
var storeValueSchema = external_exports.unknown().refine(
|
|
10242
|
+
(v) => {
|
|
10243
|
+
try {
|
|
10244
|
+
const s = JSON.stringify(v);
|
|
10245
|
+
return s !== void 0 && byteLength(s) <= STORAGE.VALUE_MAX_BYTES;
|
|
10246
|
+
} catch {
|
|
10247
|
+
return false;
|
|
10248
|
+
}
|
|
10249
|
+
},
|
|
10250
|
+
{ message: `value must be JSON-serializable and <= ${STORAGE.VALUE_MAX_BYTES} bytes` }
|
|
10251
|
+
);
|
|
10252
|
+
var storePutSchema = external_exports.object({
|
|
10253
|
+
value: storeValueSchema,
|
|
10254
|
+
/** Optimistic concurrency: fail with `conflict` unless current version matches. */
|
|
10255
|
+
ifVersion: external_exports.number().int().positive().optional()
|
|
10256
|
+
});
|
|
10257
|
+
var storeAppendSchema = external_exports.object({
|
|
10258
|
+
value: storeValueSchema,
|
|
10259
|
+
/** Optional numeric field to index (sorting/leaderboards). */
|
|
10260
|
+
num: external_exports.number().finite().optional()
|
|
10261
|
+
});
|
|
10262
|
+
var storeIncrementSchema = external_exports.object({
|
|
10263
|
+
delta: external_exports.number().int().min(-1e6).max(1e6).default(1)
|
|
10264
|
+
});
|
|
10265
|
+
var storeSubmitSchema = external_exports.object({
|
|
10266
|
+
/** The number that ranks this author (mapped into `num`). */
|
|
10267
|
+
score: external_exports.number().finite(),
|
|
10268
|
+
/** Conflict rule when the author already has a row. */
|
|
10269
|
+
keep: external_exports.enum(["max", "min", "last"]).default("max"),
|
|
10270
|
+
/** Small display payload stored alongside (same value-size gate). */
|
|
10271
|
+
meta: storeValueSchema.optional()
|
|
10272
|
+
});
|
|
10273
|
+
var storeQuerySchema = external_exports.object({
|
|
10274
|
+
sort: external_exports.enum(STORE_SORTS).default("-created"),
|
|
10275
|
+
limit: external_exports.coerce.number().int().min(1).max(STORAGE.QUERY_MAX_LIMIT).default(30),
|
|
10276
|
+
cursor: external_exports.string().max(200).optional(),
|
|
10277
|
+
/** Only the caller's records. */
|
|
10278
|
+
mine: external_exports.coerce.boolean().default(false)
|
|
10279
|
+
});
|
|
10280
|
+
var storeAdminSchema = external_exports.discriminatedUnion("action", [
|
|
10281
|
+
external_exports.object({ action: external_exports.literal("freeze") }),
|
|
10282
|
+
external_exports.object({ action: external_exports.literal("unfreeze") }),
|
|
10283
|
+
external_exports.object({ action: external_exports.literal("set_policy"), writePolicy: external_exports.enum(STORE_WRITE_POLICIES) }),
|
|
10284
|
+
external_exports.object({ action: external_exports.literal("set_anon_writes"), anonWrites: external_exports.boolean() }),
|
|
10285
|
+
external_exports.object({ action: external_exports.literal("reset"), collection: collectionSchemaStore.optional() })
|
|
10286
|
+
]);
|
|
10287
|
+
var storageOptInSchema = external_exports.object({
|
|
10288
|
+
local: external_exports.boolean().default(false),
|
|
10289
|
+
shared: external_exports.boolean().default(false)
|
|
10290
|
+
});
|
|
10291
|
+
function byteLength(s) {
|
|
10292
|
+
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(s).length;
|
|
10293
|
+
let n = 0;
|
|
10294
|
+
for (let i = 0; i < s.length; i++) {
|
|
10295
|
+
const c = s.codePointAt(i);
|
|
10296
|
+
n += c <= 127 ? 1 : c <= 2047 ? 2 : c <= 65535 ? 3 : (i++, 4);
|
|
10297
|
+
}
|
|
10298
|
+
return n;
|
|
10299
|
+
}
|
|
10300
|
+
|
|
10154
10301
|
// ../shared/src/schemas.ts
|
|
10155
10302
|
var handleSchema = external_exports.string().regex(/^[a-z0-9_.]{3,24}$/, "3\u201324 chars: a\u2013z, 0\u20139, _ or .");
|
|
10156
10303
|
var categorySchema = external_exports.enum(CATEGORIES);
|
|
10157
10304
|
var visibilitySchema = external_exports.enum(VISIBILITY);
|
|
10305
|
+
var coverModeSchema = external_exports.enum(COVER_MODES);
|
|
10158
10306
|
var sourceSchema = external_exports.enum(EXPERIENCE_SOURCE);
|
|
10159
10307
|
var tagsSchema = external_exports.array(external_exports.string().min(1).max(40)).max(10).transform(
|
|
10160
10308
|
(tags) => Array.from(
|
|
@@ -10168,8 +10316,12 @@ var publishSchema = external_exports.object({
|
|
|
10168
10316
|
tags: tagsSchema,
|
|
10169
10317
|
remixable: external_exports.boolean().default(true),
|
|
10170
10318
|
visibility: visibilitySchema.default("public"),
|
|
10319
|
+
coverMode: coverModeSchema.default("gif"),
|
|
10171
10320
|
draftArtifactKey: external_exports.string().min(1),
|
|
10172
|
-
buildSessionId: external_exports.string().uuid().optional()
|
|
10321
|
+
buildSessionId: external_exports.string().uuid().optional(),
|
|
10322
|
+
/** Storage opt-in override; when omitted, publish auto-detects from the source
|
|
10323
|
+
* (docs/post-storage.md §9 — default off, enabled only when actually used). */
|
|
10324
|
+
storage: storageOptInSchema.optional()
|
|
10173
10325
|
});
|
|
10174
10326
|
var patchExperienceSchema = external_exports.object({
|
|
10175
10327
|
title: external_exports.string().min(1).max(120).optional(),
|
|
@@ -10177,7 +10329,8 @@ var patchExperienceSchema = external_exports.object({
|
|
|
10177
10329
|
tags: tagsSchema.optional(),
|
|
10178
10330
|
category: categorySchema.optional(),
|
|
10179
10331
|
remixable: external_exports.boolean().optional(),
|
|
10180
|
-
visibility: visibilitySchema.optional()
|
|
10332
|
+
visibility: visibilitySchema.optional(),
|
|
10333
|
+
coverMode: coverModeSchema.optional()
|
|
10181
10334
|
});
|
|
10182
10335
|
var commentSchema = external_exports.object({
|
|
10183
10336
|
body: external_exports.string().min(1).max(500),
|
|
@@ -10192,10 +10345,10 @@ var createBuildSchema = external_exports.object({
|
|
|
10192
10345
|
remixParentId: external_exports.string().uuid().optional()
|
|
10193
10346
|
});
|
|
10194
10347
|
var builderAttachmentSchema = external_exports.object({
|
|
10195
|
-
kind: external_exports.enum(["image", "file"]),
|
|
10348
|
+
kind: external_exports.enum(["image", "file", "audio"]),
|
|
10196
10349
|
name: external_exports.string().max(200),
|
|
10197
|
-
|
|
10198
|
-
|
|
10350
|
+
// base64 data URL for image/audio (~8.7MB raw fits, covering a short song).
|
|
10351
|
+
dataUrl: external_exports.string().max(12e6).optional(),
|
|
10199
10352
|
text: external_exports.string().max(5e4).optional()
|
|
10200
10353
|
});
|
|
10201
10354
|
var builderMessageSchema = external_exports.object({
|
|
@@ -10227,10 +10380,21 @@ var reportSchema = external_exports.object({
|
|
|
10227
10380
|
var patchMeSchema = external_exports.object({
|
|
10228
10381
|
displayName: external_exports.string().min(1).max(60).optional(),
|
|
10229
10382
|
bio: external_exports.string().max(300).optional(),
|
|
10230
|
-
avatar
|
|
10383
|
+
// A stored image URL, or "" to remove the photo and fall back to the color avatar.
|
|
10384
|
+
avatar: external_exports.string().url().or(external_exports.literal("")).optional(),
|
|
10385
|
+
// Fallback avatar colour (used when there's no photo). Hex like #6C4CF1.
|
|
10386
|
+
avatarBg: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/, "hex colour, e.g. #6C4CF1").optional(),
|
|
10231
10387
|
handle: handleSchema.optional()
|
|
10232
10388
|
// once
|
|
10233
10389
|
});
|
|
10390
|
+
var waitlistSchema = external_exports.object({
|
|
10391
|
+
email: external_exports.string().trim().email().max(200),
|
|
10392
|
+
note: external_exports.string().trim().max(500).optional()
|
|
10393
|
+
});
|
|
10394
|
+
var waitlistReviewSchema = external_exports.object({
|
|
10395
|
+
requestId: external_exports.string().uuid(),
|
|
10396
|
+
action: external_exports.enum(["approve", "reject"])
|
|
10397
|
+
});
|
|
10234
10398
|
var aiConnectionSchema = external_exports.object({
|
|
10235
10399
|
provider: external_exports.enum(AI_PROVIDERS),
|
|
10236
10400
|
apiKey: external_exports.string().trim().min(12).max(300)
|
|
@@ -10244,28 +10408,185 @@ var feedQuerySchema = external_exports.object({
|
|
|
10244
10408
|
var searchQuerySchema = external_exports.object({
|
|
10245
10409
|
q: external_exports.string().default(""),
|
|
10246
10410
|
tab: external_exports.enum(["experiences", "tags", "creators"]).default("experiences"),
|
|
10247
|
-
|
|
10411
|
+
// Query params arrive as strings; z.coerce.boolean() is just Boolean(x), so
|
|
10412
|
+
// "false"/"0" would (wrongly) become true and the filter could never be turned
|
|
10413
|
+
// off. Parse the string explicitly: only "true"/"1" (or a real boolean) is true.
|
|
10414
|
+
remixableOnly: external_exports.union([external_exports.boolean(), external_exports.string()]).optional().transform((v) => v === true || v === "true" || v === "1"),
|
|
10248
10415
|
cursor: external_exports.string().optional(),
|
|
10249
10416
|
limit: external_exports.coerce.number().int().min(1).max(30).default(15)
|
|
10250
10417
|
});
|
|
10418
|
+
var registerPushDeviceSchema = external_exports.object({
|
|
10419
|
+
provider: external_exports.enum(PUSH_PROVIDERS),
|
|
10420
|
+
token: external_exports.string().trim().min(16).max(4096),
|
|
10421
|
+
keys: external_exports.record(external_exports.string().max(512)).default({}),
|
|
10422
|
+
platform: external_exports.enum(DEVICE_PLATFORMS).default("web"),
|
|
10423
|
+
userAgent: external_exports.string().trim().max(400).default("")
|
|
10424
|
+
}).superRefine((v, ctx) => {
|
|
10425
|
+
if (v.provider === "webpush" && (!v.keys.p256dh || !v.keys.auth)) {
|
|
10426
|
+
ctx.addIssue({
|
|
10427
|
+
code: external_exports.ZodIssueCode.custom,
|
|
10428
|
+
path: ["keys"],
|
|
10429
|
+
message: "webpush requires keys.p256dh and keys.auth"
|
|
10430
|
+
});
|
|
10431
|
+
}
|
|
10432
|
+
});
|
|
10433
|
+
var unregisterPushDeviceSchema = external_exports.object({
|
|
10434
|
+
token: external_exports.string().trim().min(16).max(4096)
|
|
10435
|
+
});
|
|
10436
|
+
var notificationsQuerySchema = external_exports.object({
|
|
10437
|
+
filter: external_exports.enum(["all", "mentions", "remixes"]).default("all"),
|
|
10438
|
+
// Keyset cursor: the `createdAt` ISO timestamp of the last item seen.
|
|
10439
|
+
cursor: external_exports.string().datetime({ offset: true }).optional(),
|
|
10440
|
+
limit: external_exports.coerce.number().int().min(1).max(80).default(30)
|
|
10441
|
+
});
|
|
10442
|
+
var notifPrefsPatchSchema = external_exports.object({
|
|
10443
|
+
enabled: external_exports.boolean().optional(),
|
|
10444
|
+
groups: external_exports.record(external_exports.enum(NOTIF_PREF_GROUPS), external_exports.boolean()).optional()
|
|
10445
|
+
});
|
|
10251
10446
|
|
|
10252
10447
|
// ../shared/src/models.ts
|
|
10253
10448
|
var BUILDER_MODELS = [
|
|
10254
|
-
// ── Free (selectable now) —
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
{ id: "
|
|
10259
|
-
{ id: "
|
|
10449
|
+
// ── Free (selectable now) — ONLY genuinely strong builders ─────────
|
|
10450
|
+
// Curated 2026-07: every id verified against GapGPT with a real full-HTML
|
|
10451
|
+
// build (not a ping). Weak/cheap models were removed on purpose — a bad
|
|
10452
|
+
// first build costs more in user trust than the tokens save.
|
|
10453
|
+
{ id: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", tier: "free", note: "Best for polished vibes \xB7 fast", vision: true },
|
|
10454
|
+
{ id: "claude-sonnet-4-20250514", label: "Claude Sonnet 4", tier: "free", note: "Reliable all-rounder", vision: true },
|
|
10455
|
+
{ id: "gpt-5.2", label: "GPT-5.2", tier: "free", note: "Strong generalist", vision: true },
|
|
10456
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex", tier: "free", note: "Code specialist" },
|
|
10457
|
+
{ id: "gemini-2.5-pro", label: "Gemini 2.5 Pro", tier: "free", note: "Great UI sense", vision: true },
|
|
10260
10458
|
{ id: "deepseek-v4-pro", label: "DeepSeek V4 Pro", tier: "free", note: "Strong coder \xB7 great value" },
|
|
10261
|
-
{ id: "
|
|
10262
|
-
{ id: "gapgpt-qwen-3.6", label: "Qwen 3.6", tier: "free", note: "Good value" },
|
|
10459
|
+
{ id: "qwen3-coder-480b-a35b-instruct", label: "Qwen3 Coder 480B", tier: "free", note: "Fast, capable coder" },
|
|
10263
10460
|
// ── Subscription (locked until billing is enabled) — premium ──────
|
|
10264
|
-
|
|
10461
|
+
// Opus 4.8 is owner-only early access: locked for everyone, live for the owner.
|
|
10462
|
+
{ id: "claude-opus-4-8", label: "Claude Opus 4.8", tier: "subscription", note: "Top quality", vision: true, ownerOnly: true },
|
|
10265
10463
|
{ id: "gpt-5.2-pro", label: "GPT-5.2 Pro", tier: "subscription", note: "Premium" },
|
|
10266
10464
|
{ id: "gemini-3-pro-preview", label: "Gemini 3 Pro", tier: "subscription", note: "Premium", vision: true }
|
|
10267
10465
|
];
|
|
10268
10466
|
var FREE_IDS = new Set(BUILDER_MODELS.filter((m) => m.tier === "free").map((m) => m.id));
|
|
10467
|
+
var OWNER_MODEL_IDS = new Set(BUILDER_MODELS.filter((m) => m.ownerOnly).map((m) => m.id));
|
|
10468
|
+
|
|
10469
|
+
// ../shared/src/i18n.ts
|
|
10470
|
+
var en = {
|
|
10471
|
+
"nav.home": "Home",
|
|
10472
|
+
"nav.search": "Search",
|
|
10473
|
+
"nav.create": "Create",
|
|
10474
|
+
"nav.notifications": "Notifications",
|
|
10475
|
+
"nav.profile": "Profile",
|
|
10476
|
+
"feed.explore": "Explore",
|
|
10477
|
+
"feed.following": "Following",
|
|
10478
|
+
"feed.tapToInteract": "Tap to interact",
|
|
10479
|
+
"feed.loading": `Loading ${ITEM.one}`,
|
|
10480
|
+
"feed.exit": "Exit",
|
|
10481
|
+
"feed.remixedFrom": "Remixed from @{handle}",
|
|
10482
|
+
"feed.remixedFromRemoved": `Remixed from a removed ${ITEM.one}`,
|
|
10483
|
+
"feed.newVersionOf": "New version of {title}",
|
|
10484
|
+
"feed.end.title": "You're all caught up",
|
|
10485
|
+
"feed.end.body": `No new ${ITEM.many} right now \u2014 remix one you loved, or check back soon.`,
|
|
10486
|
+
"feed.end.remix": "Find something to remix",
|
|
10487
|
+
"feed.end.top": "Back to top",
|
|
10488
|
+
"rail.like": "Like",
|
|
10489
|
+
"rail.comment": "Comment",
|
|
10490
|
+
"rail.remix": "Remix",
|
|
10491
|
+
"rail.save": "Save",
|
|
10492
|
+
"rail.share": "Share",
|
|
10493
|
+
"comments.title": "Comments",
|
|
10494
|
+
"comments.placeholder": "Add a comment\u2026",
|
|
10495
|
+
"comments.reply": "Reply",
|
|
10496
|
+
"comments.empty": "No comments yet \u2014 be the first.",
|
|
10497
|
+
"comments.post": "Post",
|
|
10498
|
+
"share.title": "Share",
|
|
10499
|
+
"share.copyLink": "Copy link",
|
|
10500
|
+
"share.copied": "Link copied",
|
|
10501
|
+
"create.title": "Create",
|
|
10502
|
+
"create.buildWithAI": "Build with AI",
|
|
10503
|
+
"create.import": "Import",
|
|
10504
|
+
"create.remix": "Remix something",
|
|
10505
|
+
"create.prompt.placeholder": "Describe what you want to build\u2026",
|
|
10506
|
+
"create.prompt.starters": "Start from a template",
|
|
10507
|
+
"builder.publish": "Publish",
|
|
10508
|
+
"builder.thinking": "Building\u2026",
|
|
10509
|
+
"builder.updated": "Updated \u2713",
|
|
10510
|
+
"builder.placeholder": "Ask for a change\u2026",
|
|
10511
|
+
"builder.mockNotice": "Preview builder \u2014 AI generation is mocked for now.",
|
|
10512
|
+
"import.title": "Import",
|
|
10513
|
+
"import.paste": "Paste HTML, or drop an .html file",
|
|
10514
|
+
"import.validate": "Validate",
|
|
10515
|
+
"import.warnings": "Warnings",
|
|
10516
|
+
"publish.title": "Publish",
|
|
10517
|
+
"publish.postTitle": "Title",
|
|
10518
|
+
"publish.caption": "Caption",
|
|
10519
|
+
"publish.category": "Category",
|
|
10520
|
+
"publish.remixable": "Allow remixes",
|
|
10521
|
+
"publish.public": "Public",
|
|
10522
|
+
"publish.unlisted": "Unlisted",
|
|
10523
|
+
"publish.cta": "Publish",
|
|
10524
|
+
"publish.remixCredit": "Remixing @{handle} \u2014 {title}",
|
|
10525
|
+
"publish.toast.published": "Published! \u{1F389}",
|
|
10526
|
+
"publish.toast.remix": "Remix published \u{1F501} @{handle} was credited",
|
|
10527
|
+
"remix.confirmTitle": "Remixing @{handle}'s {title}",
|
|
10528
|
+
"remix.confirmBody": `They'll be credited on your ${ITEM.one}. Attribution can't be removed.`,
|
|
10529
|
+
"remix.start": "Start remixing",
|
|
10530
|
+
"remix.galleryTitle": "Remixes",
|
|
10531
|
+
"remix.sortPopular": "Popular",
|
|
10532
|
+
"remix.sortRecent": "Recent",
|
|
10533
|
+
"remix.count": "{n} remixes",
|
|
10534
|
+
"remix.identicalWarn": "This looks identical to the original \u2014 publish anyway?",
|
|
10535
|
+
"search.placeholder": `Search ${ITEM.many}, tags, creators`,
|
|
10536
|
+
"search.tab.experiences": ITEM.Many,
|
|
10537
|
+
"search.tab.tags": "Hashtags",
|
|
10538
|
+
"search.tab.creators": "Creators",
|
|
10539
|
+
"search.remixableOnly": "Remixable only",
|
|
10540
|
+
"search.trending": "Trending",
|
|
10541
|
+
"profile.tab.experiences": ITEM.Many,
|
|
10542
|
+
"profile.tab.remixes": "Remixes",
|
|
10543
|
+
"profile.tab.saved": "Saved",
|
|
10544
|
+
"profile.followers": "followers",
|
|
10545
|
+
"profile.following": "following",
|
|
10546
|
+
"profile.likes": "likes",
|
|
10547
|
+
"profile.follow": "Follow",
|
|
10548
|
+
"profile.unfollow": "Following",
|
|
10549
|
+
"profile.edit": "Edit profile",
|
|
10550
|
+
"notifs.all": "All",
|
|
10551
|
+
"notifs.mentions": "Mentions",
|
|
10552
|
+
"notifs.remixes": "Remixes",
|
|
10553
|
+
"notifs.remixedYou": `@{handle} remixed your ${ITEM.one}`,
|
|
10554
|
+
"notifs.liked": `@{handle} liked your ${ITEM.one}`,
|
|
10555
|
+
"notifs.commented": "@{handle} commented",
|
|
10556
|
+
"notifs.followed": "@{handle} started following you",
|
|
10557
|
+
"notifs.empty": "Nothing here yet.",
|
|
10558
|
+
"collections.title": "Saved",
|
|
10559
|
+
"collections.new": "New collection",
|
|
10560
|
+
"analytics.title": "Analytics",
|
|
10561
|
+
"analytics.views": "Views",
|
|
10562
|
+
"analytics.plays": "Plays",
|
|
10563
|
+
"analytics.playRate": "Play rate",
|
|
10564
|
+
"analytics.avgTime": "Avg. time",
|
|
10565
|
+
"analytics.likes": "Likes",
|
|
10566
|
+
"analytics.comments": "Comments",
|
|
10567
|
+
"analytics.shares": "Shares",
|
|
10568
|
+
"analytics.saves": "Saves",
|
|
10569
|
+
"analytics.remixes": "Remixes",
|
|
10570
|
+
"post.options": `${ITEM.One} options`,
|
|
10571
|
+
"post.analytics": "View analytics",
|
|
10572
|
+
"post.edit": "Edit caption",
|
|
10573
|
+
"post.delete": `Delete ${ITEM.one}`,
|
|
10574
|
+
"post.deleteConfirm": `Delete this ${ITEM.one}? This can't be undone.`,
|
|
10575
|
+
"post.captionPlaceholder": "Write a caption\u2026",
|
|
10576
|
+
"auth.signIn": "Sign in",
|
|
10577
|
+
"auth.google": "Continue with Google",
|
|
10578
|
+
"auth.github": "Continue with GitHub",
|
|
10579
|
+
"auth.dev": "Dev login",
|
|
10580
|
+
"auth.needAccount": "Sign in to like, comment, and remix.",
|
|
10581
|
+
"common.cancel": "Cancel",
|
|
10582
|
+
"common.save": "Save",
|
|
10583
|
+
"common.back": "Back",
|
|
10584
|
+
"common.retry": "Retry",
|
|
10585
|
+
"common.loading": "Loading\u2026",
|
|
10586
|
+
"common.report": "Report",
|
|
10587
|
+
"common.delete": "Delete",
|
|
10588
|
+
"common.views": "{n} views"
|
|
10589
|
+
};
|
|
10269
10590
|
|
|
10270
10591
|
// ../shared/src/tokens.ts
|
|
10271
10592
|
var colors = {
|
|
@@ -10452,6 +10773,12 @@ function validate(html, opts) {
|
|
|
10452
10773
|
}
|
|
10453
10774
|
}
|
|
10454
10775
|
}
|
|
10776
|
+
if (/(localStorage|sessionStorage|indexedDB|document\s*\.\s*cookie)/.test(html)) {
|
|
10777
|
+
warnings.push({
|
|
10778
|
+
code: "BROWSER_STORAGE",
|
|
10779
|
+
message: "Uses browser storage (localStorage/sessionStorage/indexedDB/cookies), which throws inside the vibed sandbox. Port persistence to window.vibed.storage (local per-viewer, shared collective)."
|
|
10780
|
+
});
|
|
10781
|
+
}
|
|
10455
10782
|
const lower = html.toLowerCase();
|
|
10456
10783
|
const hasCredField = root.querySelector('input[type="email"], input[type="text"], input[type="tel"]') != null && /(password|passcode|otp|verify|sign\s*in|log\s*in|account)/i.test(html);
|
|
10457
10784
|
if (hasCredField) {
|
|
@@ -10996,6 +11323,7 @@ var USAGE = `vibed \u2014 make it vibed
|
|
|
10996
11323
|
Usage:
|
|
10997
11324
|
vibed login Authenticate this machine (opens the browser)
|
|
10998
11325
|
vibed check [path] Check if a project can be published (no network)
|
|
11326
|
+
vibed preview [path] Bundle + open the artifact locally (no publish)
|
|
10999
11327
|
vibed publish [path] Bundle the project and publish it to vibed
|
|
11000
11328
|
vibed whoami Show the signed-in account
|
|
11001
11329
|
vibed logout Remove the saved token
|
|
@@ -11032,6 +11360,34 @@ async function cmdCheck(args) {
|
|
|
11032
11360
|
});
|
|
11033
11361
|
return result.ok ? 0 : 1;
|
|
11034
11362
|
}
|
|
11363
|
+
async function cmdPreview(args) {
|
|
11364
|
+
const json = isTrue(args.flags.json);
|
|
11365
|
+
const dir2 = resolve2(args._[1] ?? ".");
|
|
11366
|
+
const cfg = await loadConfig({ api: str(args.flags.api) });
|
|
11367
|
+
const policy = isTrue(args.flags["local-policy"]) ? void 0 : await fetchPolicy(cfg.apiBase);
|
|
11368
|
+
const result = await bundleProject(dir2, {
|
|
11369
|
+
entry: str(args.flags.entry),
|
|
11370
|
+
build: !isTrue(args.flags["no-build"]),
|
|
11371
|
+
policy,
|
|
11372
|
+
onLog: (m) => !json && console.error(m)
|
|
11373
|
+
});
|
|
11374
|
+
if (!json) console.log(formatReport(result));
|
|
11375
|
+
if (!result.html) {
|
|
11376
|
+
if (json) out(json, "", { ok: false, fatal: result.fatal });
|
|
11377
|
+
return 1;
|
|
11378
|
+
}
|
|
11379
|
+
const file2 = join3(tmpdir(), `vibed-preview-${result.sizeBytes ?? 0}.html`);
|
|
11380
|
+
await writeFile2(file2, result.html, "utf8");
|
|
11381
|
+
const url = pathToFileURL(file2).href;
|
|
11382
|
+
if (json) {
|
|
11383
|
+
out(json, "", { ok: result.ok, previewFile: file2, previewUrl: url });
|
|
11384
|
+
} else {
|
|
11385
|
+
console.log(`
|
|
11386
|
+
Preview \u2192 ${file2}`);
|
|
11387
|
+
openBrowser(url);
|
|
11388
|
+
}
|
|
11389
|
+
return result.ok ? 0 : 1;
|
|
11390
|
+
}
|
|
11035
11391
|
async function cmdPublish(args) {
|
|
11036
11392
|
const json = isTrue(args.flags.json);
|
|
11037
11393
|
const dir2 = resolve2(args._[1] ?? ".");
|
|
@@ -11131,6 +11487,8 @@ async function main() {
|
|
|
11131
11487
|
return cmdWhoami(args);
|
|
11132
11488
|
case "check":
|
|
11133
11489
|
return cmdCheck(args);
|
|
11490
|
+
case "preview":
|
|
11491
|
+
return cmdPreview(args);
|
|
11134
11492
|
case "publish":
|
|
11135
11493
|
return cmdPublish(args);
|
|
11136
11494
|
case void 0:
|