@venturewild/workspace 0.5.2 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venturewild/workspace",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Claude Code Web — Replit/Lovable-style chat-first browser UI that wraps the AI agent already installed on your machine.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -322,12 +322,50 @@ export function createBazaar({ baseDir, seedDir = SEED_DIR, rails = null } = {})
322
322
  // The cross-user theme pool from the local rails cache, RE-VALIDATED on read —
323
323
  // never trust the pool blindly (spike 2: 15/15 hostile bundles neutralized by
324
324
  // normalizeTheme). A tampered cache file degrades to a clean bundle, not exec.
325
+ //
326
+ // Trust/ranking/payout fields are NEVER trusted from the pool (audit 2026-06-15):
327
+ // a producer could otherwise publish a theme that renders "Verified" with a
328
+ // perfect outcome score, 5 stars, and an inflated payout. We rebuild a clean card
329
+ // input keeping only display fields + the re-validated bundle, and RESET the
330
+ // trust signals so OUR provenanceFor derives the honest Class-A 'auto' verdict and
331
+ // a neutral outcome (local build-results then accrue). Display text is clamped.
332
+ function str(v, max) {
333
+ return typeof v === 'string' ? v.slice(0, max) : '';
334
+ }
325
335
  function readRailsThemes() {
326
336
  const raw = readJsonSafe(railsThemesFile, []);
327
337
  if (!Array.isArray(raw)) return [];
328
338
  return raw
329
339
  .filter((r) => r && typeof r === 'object' && r.id && r.kind === 'theme')
330
- .map((r) => ({ ...r, theme: normalizeTheme(r.theme || {}), source: 'rails' }));
340
+ .map((r) => {
341
+ const p = r.producer && typeof r.producer === 'object' ? r.producer : {};
342
+ return {
343
+ id: String(r.id).slice(0, 120),
344
+ kind: 'theme',
345
+ source: 'rails',
346
+ title: str(r.title, 80) || 'Untitled',
347
+ pitch: str(r.pitch, 200),
348
+ summary: str(r.summary, 400),
349
+ tags: Array.isArray(r.tags) ? r.tags.slice(0, 8).map((t) => String(t).slice(0, 24)) : [],
350
+ producer: {
351
+ name: str(p.name, 60) || 'A maker',
352
+ handle: str(p.handle, 40) || 'maker',
353
+ kind: 'maker',
354
+ },
355
+ theme: normalizeTheme(r.theme || {}),
356
+ // Remix lineage is safe to surface (it's just a pointer + label).
357
+ ...(r.builtFrom && r.builtFrom.id
358
+ ? { builtFrom: { id: String(r.builtFrom.id).slice(0, 120), title: str(r.builtFrom.title, 80) } }
359
+ : {}),
360
+ // RESET publisher-controlled trust/ranking/payout → our derivation governs.
361
+ outcomeScore: 0.7, // the new-listing prior (proven locally over time)
362
+ outcomeStats: { builds: 0, working: 0 },
363
+ rating: { stars: 0, count: 0 }, // no fake stars
364
+ reward: { model: 'one-time', unit: 'per apply', oneTimeValue: 1.5, perUseValue: 0 },
365
+ // No vetting/safetyBadge → provenanceFor derives Class-A 'auto'.
366
+ createdAt: typeof r.createdAt === 'number' ? r.createdAt : 0,
367
+ };
368
+ });
331
369
  }
332
370
 
333
371
  // Overwrite the local cache of the global theme pool (called by the main