@vm0/cli 9.169.2 → 9.171.0

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/zero.js CHANGED
@@ -126,7 +126,6 @@ import {
126
126
  resolveFirewallPolicies,
127
127
  resolveZeroScheduleByAgent,
128
128
  saveConfig,
129
- searchConnectors,
130
129
  searchZeroChat,
131
130
  searchZeroConnectors,
132
131
  searchZeroLogs,
@@ -153,7 +152,7 @@ import {
153
152
  zeroAgentCustomSkillNameSchema,
154
153
  zeroLocalAgentCommand,
155
154
  zeroTokenAllowsFeatureSwitch
156
- } from "./chunk-CZICABIP.js";
155
+ } from "./chunk-HL3E2RLS.js";
157
156
  import {
158
157
  __toESM,
159
158
  init_esm_shims
@@ -1874,6 +1873,162 @@ var listCommand6 = new Command().name("list").alias("ls").description("List all
1874
1873
 
1875
1874
  // src/commands/zero/connector/search.ts
1876
1875
  init_esm_shims();
1876
+
1877
+ // ../../packages/connectors/src/connector-search.ts
1878
+ init_esm_shims();
1879
+ var TOKEN_BOUNDARY = /[_\-\s]+/;
1880
+ var CASE_BOUNDARY = /(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/;
1881
+ var MIN_SCORE = 10;
1882
+ function tokenize(input) {
1883
+ const tokens = /* @__PURE__ */ new Set();
1884
+ for (const chunk of input.split(TOKEN_BOUNDARY)) {
1885
+ if (!chunk) continue;
1886
+ for (const sub of chunk.split(CASE_BOUNDARY)) {
1887
+ const lower = sub.toLowerCase();
1888
+ if (lower) tokens.add(lower);
1889
+ }
1890
+ }
1891
+ return tokens;
1892
+ }
1893
+ function connectorAccessEnvBindings(access) {
1894
+ switch (access.kind) {
1895
+ case "static":
1896
+ case "refresh-token":
1897
+ return access.envBindings;
1898
+ case "none":
1899
+ return {};
1900
+ }
1901
+ }
1902
+ function getManualGrantFields(method) {
1903
+ return method.grant.kind === "manual" ? method.grant.fields : void 0;
1904
+ }
1905
+ function listSecretNames(config) {
1906
+ const names = [];
1907
+ for (const method of Object.values(config.authMethods)) {
1908
+ for (const name of Object.keys(getManualGrantFields(method) ?? {})) {
1909
+ names.push(name);
1910
+ }
1911
+ for (const valueRef of Object.values(
1912
+ connectorAccessEnvBindings(method.access)
1913
+ )) {
1914
+ if (valueRef.startsWith("$secrets.")) {
1915
+ names.push(valueRef.slice("$secrets.".length));
1916
+ }
1917
+ }
1918
+ }
1919
+ return names;
1920
+ }
1921
+ function findExactMatch(keywordLower, type, config) {
1922
+ if (type.toLowerCase() === keywordLower) {
1923
+ return { score: 100, matchedField: "type" };
1924
+ }
1925
+ for (const envName of Object.keys(getConnectorEnvBindings(type))) {
1926
+ if (envName.toLowerCase() === keywordLower) {
1927
+ return { score: 90, matchedField: `env:${envName}` };
1928
+ }
1929
+ }
1930
+ if (config.label.toLowerCase() === keywordLower) {
1931
+ return { score: 80, matchedField: "label" };
1932
+ }
1933
+ const tags = config.tags ?? [];
1934
+ for (const tag of tags) {
1935
+ if (tag === keywordLower) {
1936
+ return { score: 70, matchedField: `tag:${tag}` };
1937
+ }
1938
+ }
1939
+ return null;
1940
+ }
1941
+ function findSubstringMatch(keywordLower, type, config) {
1942
+ if (type.toLowerCase().includes(keywordLower)) {
1943
+ return { score: 50, matchedField: "type" };
1944
+ }
1945
+ if (config.label.toLowerCase().includes(keywordLower)) {
1946
+ return { score: 50, matchedField: "label" };
1947
+ }
1948
+ for (const envName of Object.keys(getConnectorEnvBindings(type))) {
1949
+ if (envName.toLowerCase().includes(keywordLower)) {
1950
+ return { score: 40, matchedField: `env:${envName}` };
1951
+ }
1952
+ }
1953
+ for (const name of listSecretNames(config)) {
1954
+ if (name.toLowerCase().includes(keywordLower)) {
1955
+ return { score: 30, matchedField: `secret:${name}` };
1956
+ }
1957
+ }
1958
+ const tags = config.tags ?? [];
1959
+ for (const tag of tags) {
1960
+ if (tag.includes(keywordLower)) {
1961
+ return { score: 25, matchedField: `tag:${tag}` };
1962
+ }
1963
+ }
1964
+ return null;
1965
+ }
1966
+ function collectCandidateTokens(type, config) {
1967
+ const tokens = /* @__PURE__ */ new Set();
1968
+ const sources = [
1969
+ type,
1970
+ config.label,
1971
+ ...Object.keys(getConnectorEnvBindings(type)),
1972
+ ...listSecretNames(config),
1973
+ ...config.tags ?? []
1974
+ ];
1975
+ for (const source of sources) {
1976
+ for (const token of tokenize(source)) {
1977
+ tokens.add(token);
1978
+ }
1979
+ }
1980
+ return tokens;
1981
+ }
1982
+ function findTokenIntersection(keywordTokens, type, config) {
1983
+ const candidateTokens = collectCandidateTokens(type, config);
1984
+ let intersection = 0;
1985
+ let firstCommon = "";
1986
+ for (const token of keywordTokens) {
1987
+ if (candidateTokens.has(token)) {
1988
+ intersection++;
1989
+ if (!firstCommon) firstCommon = token;
1990
+ }
1991
+ }
1992
+ if (intersection === 0) return null;
1993
+ return { score: 10 * intersection, matchedField: `token:${firstCommon}` };
1994
+ }
1995
+ function scoreConnector(keywordLower, keywordTokens, type, config) {
1996
+ const exact = findExactMatch(keywordLower, type, config);
1997
+ if (exact) return exact;
1998
+ const candidates = [];
1999
+ const substring = findSubstringMatch(keywordLower, type, config);
2000
+ if (substring) candidates.push(substring);
2001
+ const token = findTokenIntersection(keywordTokens, type, config);
2002
+ if (token) candidates.push(token);
2003
+ if (candidates.length === 0) return null;
2004
+ const best = candidates.reduce((a, b) => {
2005
+ return a.score >= b.score ? a : b;
2006
+ });
2007
+ if (best.score < MIN_SCORE) return null;
2008
+ return best;
2009
+ }
2010
+ function searchConnectors(keyword, limit, filter) {
2011
+ const trimmed = keyword.trim();
2012
+ if (!trimmed) return { results: [], total: 0 };
2013
+ const keywordLower = trimmed.toLowerCase();
2014
+ const keywordTokens = tokenize(trimmed);
2015
+ const hits = [];
2016
+ for (const type of CONNECTOR_TYPE_KEYS) {
2017
+ if (filter && !filter(type)) continue;
2018
+ const config = CONNECTOR_TYPES[type];
2019
+ const hit = scoreConnector(keywordLower, keywordTokens, type, config);
2020
+ if (!hit) continue;
2021
+ hits.push({ type, score: hit.score, matchedField: hit.matchedField });
2022
+ }
2023
+ hits.sort((a, b) => {
2024
+ if (b.score !== a.score) return b.score - a.score;
2025
+ return a.type.localeCompare(b.type);
2026
+ });
2027
+ const capped = limit > 0 ? hits.slice(0, limit) : hits;
2028
+ return { results: capped, total: hits.length };
2029
+ }
2030
+
2031
+ // src/commands/zero/connector/search.ts
1877
2032
  var DEFAULT_LIMIT = 5;
1878
2033
  var EXACT_MATCH_THRESHOLD = 80;
1879
2034
  function isConnectorType2(type) {
@@ -6523,6 +6678,13 @@ function extensionForMimeType(mimeType) {
6523
6678
  const suffix = mimeType.startsWith("image/") ? mimeType.slice(6) : "bin";
6524
6679
  return sanitizeFilenamePart(suffix, "bin").toLowerCase();
6525
6680
  }
6681
+ function isRecord(value) {
6682
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6683
+ }
6684
+ function stringField(value, key) {
6685
+ const field = value[key];
6686
+ return typeof field === "string" ? field : void 0;
6687
+ }
6526
6688
  async function writeScreenshotDataUrl(result, dataUrl) {
6527
6689
  const match = DATA_URL_PATTERN.exec(dataUrl);
6528
6690
  if (!match) {
@@ -6543,20 +6705,41 @@ async function writeScreenshotDataUrl(result, dataUrl) {
6543
6705
  await writeFile(outputPath, Buffer.from(base64Data, "base64"));
6544
6706
  return outputPath;
6545
6707
  }
6546
- async function formatComputerUseResultForConsole(result) {
6547
- const printable = { ...result };
6548
- if (typeof printable.screenshot === "string") {
6549
- const screenshotPath = await writeScreenshotDataUrl(
6550
- printable,
6551
- printable.screenshot
6552
- );
6553
- if (screenshotPath) {
6554
- printable.screenshot = screenshotPath;
6708
+ function compactActionResult(action) {
6709
+ const compact = {};
6710
+ for (const [key, value] of Object.entries(action)) {
6711
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
6712
+ compact[key] = value;
6555
6713
  }
6556
6714
  }
6715
+ return compact;
6716
+ }
6717
+ async function formatComputerUseResultForConsole(result) {
6718
+ const printable = { status: "succeeded" };
6719
+ const apps = result.apps;
6720
+ if (Array.isArray(apps)) {
6721
+ printable.apps = apps;
6722
+ }
6723
+ const snapshotId = stringField(result, "snapshotId");
6724
+ if (snapshotId) {
6725
+ printable.snapshotId = snapshotId;
6726
+ }
6727
+ const appState = stringField(result, "appState");
6728
+ if (appState) {
6729
+ printable.appState = appState;
6730
+ }
6731
+ const screenshot = stringField(result, "screenshot");
6732
+ if (screenshot) {
6733
+ const screenshotPath = await writeScreenshotDataUrl(result, screenshot);
6734
+ printable.screenshot = screenshotPath ?? screenshot;
6735
+ }
6736
+ const action = result.action;
6737
+ if (isRecord(action)) {
6738
+ printable.action = compactActionResult(action);
6739
+ }
6557
6740
  return JSON.stringify(printable, null, 2);
6558
6741
  }
6559
- async function resultText(command) {
6742
+ async function commandOutputText(command) {
6560
6743
  if (!command.result) {
6561
6744
  return "";
6562
6745
  }
@@ -6581,7 +6764,7 @@ async function waitForCommand(commandId, timeoutSeconds) {
6581
6764
  command.error ? `${command.error.code}: ${command.error.message}` : "Computer-use command failed"
6582
6765
  );
6583
6766
  }
6584
- const text = await resultText(command);
6767
+ const text = await commandOutputText(command);
6585
6768
  if (text) {
6586
6769
  console.log(text);
6587
6770
  }
@@ -6755,8 +6938,8 @@ init_esm_shims();
6755
6938
 
6756
6939
  // src/commands/zero/shared/open-design-registry.ts
6757
6940
  init_esm_shims();
6758
- var OPEN_DESIGN_REPO = "vm0-ai/open-design";
6759
- var OPEN_DESIGN_COMMIT = "d021b04720ace133f1d6133d1487326f5fc28f07";
6941
+ var OPEN_DESIGN_REPO = "nexu-io/open-design";
6942
+ var OPEN_DESIGN_COMMIT = "3fb620af423534643677c7c6fae76be088fa770a";
6760
6943
  var VM0_SKILLS_REPO = "vm0-ai/vm0-skills";
6761
6944
  var VM0_SKILLS_REF = "main";
6762
6945
  var OPEN_DESIGN_REGISTRY_VERSION = `federated:${OPEN_DESIGN_REPO}@${OPEN_DESIGN_COMMIT}`;
@@ -9147,7 +9330,11 @@ var OPEN_DESIGN_REGISTRY = [
9147
9330
  name: "Notion Illustration",
9148
9331
  description: "Zero-native illustration style for hand-drawn product spot illustrations with simple ink contours and soft backgrounds.",
9149
9332
  desc: 'Notion-editorial-style hand-drawn spot illustration. Black brush-pen ink on white, tapered confident strokes, solid-black curly hair, solid-black pants/shoes, 3/4 face turned toward viewer with closed-eye smile and soft nose hint, open breathing body outlines, and 1-3 supporting scene props + ambient marks that frame the moment. Trigger when user says /notion-illustration, asks for a "Notion-style illustration", "Notion spot illustration", or a new piece in this hand-drawn brush-pen Notion editorial style.',
9150
- source: { path: "illustration-template/notion-illustration" }
9333
+ source: {
9334
+ repo: VM0_SKILLS_REPO,
9335
+ ref: VM0_SKILLS_REF,
9336
+ path: "illustration-template/notion-illustration"
9337
+ }
9151
9338
  },
9152
9339
  {
9153
9340
  id: "vm0:image-style:vm0-illustration",
@@ -9155,7 +9342,11 @@ var OPEN_DESIGN_REGISTRY = [
9155
9342
  name: "vm0 Illustration",
9156
9343
  description: "vm0 in-app spot illustration style with bold hand-drawn ink line art, white-filled interiors, and a soft rounded color backdrop.",
9157
9344
  desc: "Generate vm0-style vm0 in-app spot illustrations: bold hand-drawn ink line art with white-filled interiors, a soft rounded color backdrop, transparent output, and simple iconic metaphors for product states.",
9158
- source: { path: "illustration-template/vm0-illustration" }
9345
+ source: {
9346
+ repo: VM0_SKILLS_REPO,
9347
+ ref: VM0_SKILLS_REF,
9348
+ path: "illustration-template/vm0-illustration"
9349
+ }
9159
9350
  },
9160
9351
  {
9161
9352
  id: "vm0:image-style:postcard-illustration",
@@ -9163,7 +9354,11 @@ var OPEN_DESIGN_REGISTRY = [
9163
9354
  name: "Postcard Illustration",
9164
9355
  description: "Hand-drawn editorial postcard / travel-journal illustration with fine black ink linework, flat saturated gouache fills, sharp edges, dense small repeated ink patterns, paper-grain texture, sparse white speckles, and a tall portrait composition.",
9165
9356
  desc: 'Hand-drawn editorial postcard illustration style. Fine black marker/pen ink linework over flat saturated gouache color fills with sharp edges, dense small repeated ink patterns on surfaces (rows of windows, shingle curves, hatching, stippling), subtle paper-grain background texture, tiny scattered white speckles (snow / petals / sparkle), and a tall portrait composition with a layered foreground-midground-background. Travel-journal / urban-sketcher aesthetic. Trigger when the user says /postcard-illustration, asks for a "postcard illustration", "travel illustration", "urban sketcher style", or briefs a palette + scene archetype + complexity.',
9166
- source: { path: "illustration-template/postcard-illustration" }
9357
+ source: {
9358
+ repo: VM0_SKILLS_REPO,
9359
+ ref: VM0_SKILLS_REF,
9360
+ path: "illustration-template/postcard-illustration"
9361
+ }
9167
9362
  },
9168
9363
  {
9169
9364
  id: "vm0:image-style:folk-storybook",
@@ -9171,7 +9366,11 @@ var OPEN_DESIGN_REGISTRY = [
9171
9366
  name: "Folk Storybook Illustration",
9172
9367
  description: "Folk-art children's picture-book illustration \u2014 hand-painted gouache and watercolor scenes with anthropomorphic animal characters, closed-crescent-eye smiles, dusty muted folk palette, and decorative pattern surfaces.",
9173
9368
  desc: "Folk-art children's picture-book illustration style \u2014 hand-painted gouache/watercolor scene on aged paper, anthropomorphic animal characters with closed-crescent-eye smiles, dusty muted folk palette, decorative pattern surfaces (wallpaper, rugs, textiles), and a hushed lullaby mood. Trigger when users ask for a folk-art illustration, storybook scene, cozy animal illustration, or any new piece in this Eastern European picture-book style.",
9174
- source: { path: "illustration-template/folk-storybook" }
9369
+ source: {
9370
+ repo: VM0_SKILLS_REPO,
9371
+ ref: VM0_SKILLS_REF,
9372
+ path: "illustration-template/folk-storybook"
9373
+ }
9175
9374
  },
9176
9375
  {
9177
9376
  id: "vm0:image-style:papernook",
@@ -9179,7 +9378,11 @@ var OPEN_DESIGN_REGISTRY = [
9179
9378
  name: "Papernook",
9180
9379
  description: "Hand-drawn editorial illustration set in a cozy cluttered personal-studio scene with warm cream paper, scratchy ink, painterly gouache fills, dot-eye character face, and dense edge-to-edge thematic props.",
9181
9380
  desc: 'Hand-drawn editorial illustration in the spirit of a cluttered personal-studio scene. Loose scratchy black ink outlines that wobble, textured gouache fills with visible brush marks, warm cream paper background, simplified dot-eye character face, and a DENSE edge-to-edge composition where a centered character is orbited by thematic props that visually act out the scene metaphor. Default palette: dusty cornflower blue, soft coral pink, fresh sage green, charcoal, warm cream \u2014 no mustard, no burnt-orange. Trigger when user says /papernook, asks for a "papernook illustration", a "cozy cluttered editorial scene", a "warm-cream desk scene", or a new piece in this hand-drawn studio-clutter editorial style.',
9182
- source: { path: "illustration-template/papernook" }
9381
+ source: {
9382
+ repo: VM0_SKILLS_REPO,
9383
+ ref: VM0_SKILLS_REF,
9384
+ path: "illustration-template/papernook"
9385
+ }
9183
9386
  },
9184
9387
  {
9185
9388
  id: "vm0:image-style:painterly-botanical",
@@ -9187,7 +9390,11 @@ var OPEN_DESIGN_REGISTRY = [
9187
9390
  name: "Painterly Botanical",
9188
9391
  description: "Painterly watercolor + gouache portrait illustration with a single figure embraced by lush botanicals, closed-eye introspective expression, and a softly tinted paper-wash background.",
9189
9392
  desc: 'Painterly watercolor + gouache portrait illustration. Single figure (closed eyes, contemplative) embraced by botanicals \u2014 leaves, blossoms, grasses. Translucent washes with visible pigment bleeds, sparse crisp ink line accents on key edges, tiny handwritten cursive signature in an upper corner, and a tinted paper-wash background (never pure white). Eight user axes drive composition: subject, hair, pose, botanicals, palette, background wash, complexity (L1/L2/L3), and format. Trigger when a brief describes a contemplative figure with foliage, a "watercolor portrait", a "botanical embrace", or asks for a piece in this painterly editorial style.',
9190
- source: { path: "illustration-template/painterly-botanical" }
9393
+ source: {
9394
+ repo: VM0_SKILLS_REPO,
9395
+ ref: VM0_SKILLS_REF,
9396
+ path: "illustration-template/painterly-botanical"
9397
+ }
9191
9398
  },
9192
9399
  {
9193
9400
  id: "vm0:image-style:iso-scene",
@@ -9195,7 +9402,11 @@ var OPEN_DESIGN_REGISTRY = [
9195
9402
  name: "Isometric Editorial Scene",
9196
9403
  description: "Isometric editorial-magazine scene illustration with ultra-fine hairline outlines, flat fills, a saturated monochromatic background, and a scene-as-metaphor composition built from theme-native props.",
9197
9404
  desc: 'Isometric editorial-magazine scene illustration in a locked flat-vector style \u2014 ultra-fine hairline outlines, monochromatic saturated background filling the canvas, and a single composed scene whose props themselves embody the theme. Trigger when users say /iso-scene, ask for an "isometric editorial illustration", a "scene illustration in the editorial machine style", or brief with palette + scene archetype + complexity.',
9198
- source: { path: "illustration-template/iso-scene" }
9405
+ source: {
9406
+ repo: VM0_SKILLS_REPO,
9407
+ ref: VM0_SKILLS_REF,
9408
+ path: "illustration-template/iso-scene"
9409
+ }
9199
9410
  },
9200
9411
  {
9201
9412
  id: "vm0:image-style:inkdab",
@@ -9203,7 +9414,11 @@ var OPEN_DESIGN_REGISTRY = [
9203
9414
  name: "Inkdab Illustration",
9204
9415
  description: "Brush-pen editorial illustration where a free-floating color dab is painted first, then loose black ink linework is drawn freely on top \u2014 never as an outline around the color. Scribbled hatched hair, open-outline bodies, pure white background.",
9205
9416
  desc: 'Brush-pen editorial illustration style \u2014 a flat accent-color "dab" painted first, then loose black ink drawn freely on top. ONE flat accent-color shape per prop (painted-first, never outlined in black), black hand-wobbled ink on pure white background, scribbled hatched hair, open-outline bodies with zero fill, and one small solid-accent triangle floating freely as a recurring motif. Trigger when user says /inkdab, asks for an "inkdab illustration", a "brush-pen illustration with a single accent color", a "free-floating color block illustration", or briefs in the style of the included reference images.',
9206
- source: { path: "illustration-template/inkdab" }
9417
+ source: {
9418
+ repo: VM0_SKILLS_REPO,
9419
+ ref: VM0_SKILLS_REF,
9420
+ path: "illustration-template/inkdab"
9421
+ }
9207
9422
  },
9208
9423
  {
9209
9424
  id: "vm0:image-style:riso-relic",
@@ -9211,7 +9426,11 @@ var OPEN_DESIGN_REGISTRY = [
9211
9426
  name: "Riso Relic",
9212
9427
  description: 'Pop-art retro risograph poster of a single nostalgic everyday object on a saturated single-hue field \u2014 bold black ink outlines, halftone grain, hand-drawn doodle accents, tiny "SMALL OBJECTS IN TIME" banner up top, chunky retro headline with offset drop-shadow at the bottom.',
9213
9428
  desc: 'Pop-art retro risograph poster of a single nostalgic everyday object \u2014 saturated single-color background, bold black ink outlines, halftone/riso grain, hand-drawn doodle accents (sparkles, squiggles, dots, music notes, lightning), tiny white "SMALL OBJECTS IN TIME" banner at top, chunky retro display headline at bottom with offset black drop-shadow. Trigger when user says /riso-relic, asks for a "riso poster", a "small objects in time" illustration, or any new piece in this nostalgic pop-art relic-object style.',
9214
- source: { path: "illustration-template/riso-relic" }
9429
+ source: {
9430
+ repo: VM0_SKILLS_REPO,
9431
+ ref: VM0_SKILLS_REF,
9432
+ path: "illustration-template/riso-relic"
9433
+ }
9215
9434
  },
9216
9435
  {
9217
9436
  id: "vm0:image-style:inkstomp",
@@ -9219,7 +9438,11 @@ var OPEN_DESIGN_REGISTRY = [
9219
9438
  name: "Inkstomp",
9220
9439
  description: "Loud indie-packaging poster style \u2014 full-bleed saturated flat color, a two-line hand-lettered headline, and one weird-cute black brush-ink character.",
9221
9440
  desc: 'Inkstomp \u2014 a loud, hand-screened indie-packaging poster style. Full-bleed saturated flat color filling the entire canvas, a two-line hand-lettered headline (thin arched caps over chunky drop-shadowed display), and one weird-cute character drawn in thick uniform black brush ink. Trigger when the user says /inkstomp, asks for an "inkstomp poster", a "Ray Fenwick / Hattie Stewart packaging poster", an "indie brush-ink flavor card", or briefs in a "palette + headline + character" shape.',
9222
- source: { path: "illustration-template/inkstomp" }
9441
+ source: {
9442
+ repo: VM0_SKILLS_REPO,
9443
+ ref: VM0_SKILLS_REF,
9444
+ path: "illustration-template/inkstomp"
9445
+ }
9223
9446
  },
9224
9447
  {
9225
9448
  id: "vm0:image-style:folk-muse",
@@ -9227,7 +9450,11 @@ var OPEN_DESIGN_REGISTRY = [
9227
9450
  name: "Folk Muse",
9228
9451
  description: "Flat folk-art gouache portrait style \u2014 a single contemplative chest-up figure framed by an asymmetric botanical surround, with painted irises, smooth flat hair, a hand against the cheek, and a patterned robe.",
9229
9452
  desc: 'Flat folk-art gouache portrait illustration in the contemporary editorial style of Carson Ellis, Maja Tomljanovic, and Bodil Jane. A single chest-up figure with an elongated mannerist oval face, tiny almond half-lidded eyes, smooth flat hair, one hand pressed against the face, a patterned robe filling the lower frame, and an asymmetric botanical surround filling the background edge-to-edge. Hand-painted matte gouache texture, flat color blocks, no harsh outlines, no photorealism. Calm, slightly melancholic, contemplative mood. Trigger when the user says /folk-muse, asks for a "folk-art portrait", "gouache portrait", "Carson Ellis style portrait", or any new piece in this contemplative folk-portrait style.',
9230
- source: { path: "illustration-template/folk-muse" }
9453
+ source: {
9454
+ repo: VM0_SKILLS_REPO,
9455
+ ref: VM0_SKILLS_REF,
9456
+ path: "illustration-template/folk-muse"
9457
+ }
9231
9458
  },
9232
9459
  {
9233
9460
  id: "vm0:image-style:sunlit-gouache",
@@ -9235,7 +9462,11 @@ var OPEN_DESIGN_REGISTRY = [
9235
9462
  name: "Sunlit Gouache",
9236
9463
  description: "Bright pastel travel-painting illustration in opaque gouache on textured paper with chunky flat brushstrokes, vertical one-point perspective, and figures walking into warm sunlight.",
9237
9464
  desc: 'Sunlit Gouache travel-painting illustration. Opaque gouache on textured paper, visible chunky flat brushstrokes with dry-brush highlights, locked six-color palette (cream, butter-yellow, sky-blue, sage-green, terracotta, one small red accent), vertical 2:3 one-point-perspective composition drawing the eye into a bright sunlit focal point, figures seen from behind walking into the scene, an overhead band of hanging elements (awning, prayer flags, catenary, bunting, lanterns) creating depth, dappled painterly reflections on the ground, airy optimistic warm mood. Trigger when user says /sunlit-gouache, asks for a "sunlit gouache illustration", "painterly travel scene", "gouache caf\xE9/market/temple/station scene", or a new piece in this bright pastel painted-light style.',
9238
- source: { path: "illustration-template/sunlit-gouache" }
9465
+ source: {
9466
+ repo: VM0_SKILLS_REPO,
9467
+ ref: VM0_SKILLS_REF,
9468
+ path: "illustration-template/sunlit-gouache"
9469
+ }
9239
9470
  },
9240
9471
  {
9241
9472
  id: "vm0:image-style:mosaic-still-life",
@@ -9243,7 +9474,11 @@ var OPEN_DESIGN_REGISTRY = [
9243
9474
  name: "Mosaic Still Life",
9244
9475
  description: "Editorial still-life illustration in a mosaic-tile + painterly hybrid style \u2014 tessellated ground/sky/wall surfaces with crisp painterly objects, an animal companion, and a patterned textile peeking through.",
9245
9476
  desc: 'Mosaic-tile + painterly hybrid editorial illustration. Tessellated/pointillist mosaic surfaces (grass, sky, sand, walls, floors) anchor the scene, with crisp painterly still-life objects rendered ON TOP. Always features a still-life centerpiece on a table, an animal companion at the heart of the scene, and at least one patterned textile peeking through. Cozy, nostalgic, bucolic mood. Trigger when user says /mosaic-still-life, asks for a "mosaic illustration", "mosaic-tile editorial illustration", "tessellated still life", or briefs with a palette + scene + animal in this style.',
9246
- source: { path: "illustration-template/mosaic-still-life" }
9477
+ source: {
9478
+ repo: VM0_SKILLS_REPO,
9479
+ ref: VM0_SKILLS_REF,
9480
+ path: "illustration-template/mosaic-still-life"
9481
+ }
9247
9482
  },
9248
9483
  {
9249
9484
  id: "vm0:image-style:ink-mascot",
@@ -9251,7 +9486,11 @@ var OPEN_DESIGN_REGISTRY = [
9251
9486
  name: "Ink Mascot",
9252
9487
  description: "Vintage editorial marketing card. Bold serif headline and short serif descriptor over a hand-drawn black-ink anthropomorphic mascot (stick limbs, chunky white sneakers) on a single solid saturated flat color background.",
9253
9488
  desc: 'Generate a 3:5 portrait editorial marketing card in a locked vintage-textbook style. Bold serif headline plus an optional short serif descriptor sit on a single solid saturated flat color background (no gradient, no divider, no ground line). A hand-drawn black-ink anthropomorphic hero object \u2014 paint bucket, magnifying glass, envelope, notebook, funnel, megaphone, rocket, seedling, gift box, compass, etc. \u2014 stands with two thin stick arms, two stick legs, and chunky white sneakers with black laces (the signature detail). Crosshatch and stipple shading on rounded surfaces; floating ink doodles (sparkles, arrows, hearts, percent or dollar signs, motion lines) at the requested density. Dialable along six axes: concept, palette, hero object, action, doodle density (L1 minimal, L2 balanced, L3 packed), and type layout (A title-top, B headline-bottom, C headline-only, D big-word + tiny-descriptor). Trigger when user says /ink-mascot, asks for a "marketing card illustration", a "retro editorial mascot poster", or briefs with a marketing concept plus palette plus character.',
9254
- source: { path: "illustration-template/ink-mascot" }
9489
+ source: {
9490
+ repo: VM0_SKILLS_REPO,
9491
+ ref: VM0_SKILLS_REF,
9492
+ path: "illustration-template/ink-mascot"
9493
+ }
9255
9494
  },
9256
9495
  {
9257
9496
  id: "vm0:image-style:sticker-sheet",
@@ -9259,7 +9498,11 @@ var OPEN_DESIGN_REGISTRY = [
9259
9498
  name: "Sticker Sheet",
9260
9499
  description: "Hand-painted gouache sticker-sheet illustration with ~20 themed objects floating on white, punchy saturated palette, wobbly hand-drawn ink overlay, and tiny decorative marks on every item.",
9261
9500
  desc: 'Sticker Sheet \u2014 hand-painted gouache sticker-sheet illustration. ~20 small floating themed objects on pure white, punchy saturated palette (coral, mustard, sage, dusty pink, navy, cream, warm brown), flat brushy gouache fills with wobbly hand-drawn ink linework and tiny decorative marks (dots, hatches, squiggles) on every object. Each object slightly tilted, no drop shadows, cheerful cozy lifestyle journal mood. Trigger when user says /sticker-sheet, asks for a "sticker sheet illustration", "hand-painted gouache sticker pack", "themed object sheet", or briefs with a scene theme + object count in this house style.',
9262
- source: { path: "illustration-template/sticker-sheet" }
9501
+ source: {
9502
+ repo: VM0_SKILLS_REPO,
9503
+ ref: VM0_SKILLS_REF,
9504
+ path: "illustration-template/sticker-sheet"
9505
+ }
9263
9506
  },
9264
9507
  {
9265
9508
  id: "vm0:image-style:flat-poster",
@@ -9267,7 +9510,11 @@ var OPEN_DESIGN_REGISTRY = [
9267
9510
  name: "Flat Poster",
9268
9511
  description: "Vertical flat-color editorial poster style \u2014 saturated solid background, one centered hand-drawn vector subject in bold deep-navy outlines with strict two-tone fill, headline pinned top-left, wordmark pinned bottom-right.",
9269
9512
  desc: 'Flat Poster \u2014 a vertical flat-color editorial poster style for brand benefit cards, marketing posters, and in-app campaign visuals. Portrait 2:3 canvas filled edge-to-edge with one saturated hue; a single centered hand-drawn vector subject in deep-navy outlines with strict two-tone fill (pure white plus one darker bg-tint accent); a bold rounded sans-serif headline pinned top-left; a short wordmark (default VM0) pinned bottom-right; small floating accent marks around the subject; no body copy. Six creative dials: palette, subject archetype, composition preset, accent marks, headline voice, mood. Trigger when the user says /flat-poster, asks for a "flat-color editorial poster", a "brand benefit card", a "marketing card in the bold outline + flat color style", or briefs with a palette + subject + headline shape.',
9270
- source: { path: "illustration-template/flat-poster" }
9513
+ source: {
9514
+ repo: VM0_SKILLS_REPO,
9515
+ ref: VM0_SKILLS_REF,
9516
+ path: "illustration-template/flat-poster"
9517
+ }
9271
9518
  },
9272
9519
  {
9273
9520
  id: "vm0:image-style:mellow-pop",
@@ -9275,7 +9522,11 @@ var OPEN_DESIGN_REGISTRY = [
9275
9522
  name: "Mellow Pop",
9276
9523
  description: "Chill flat-vector editorial poster of a serene recurring character on a fully saturated solid color background, with a signature pop of bright leaf-green and a scene-as-metaphor composition.",
9277
9524
  desc: 'Mellow-pop flat-vector editorial illustration: a recurring chill character with closed-eye smile, tiny nose hint, and short dark bobbed hair, posed inside a scene-as-metaphor composition on a single fully saturated solid color background, with a signature pop of bright leaf-green woven into every piece (hero prop, plants, motifs, or sweater). Thin uniform black outlines, flat solid fills only, no gradients or texture. Five dials per brief: palette, scene metaphor, complexity (L1/L2/L3), pose, outfit accent. Trigger when user says /mellow-pop, asks for a "mellow-pop illustration", "chill flat-vector poster", or briefs with a scene metaphor + palette + complexity.',
9278
- source: { path: "illustration-template/mellow-pop" }
9525
+ source: {
9526
+ repo: VM0_SKILLS_REPO,
9527
+ ref: VM0_SKILLS_REF,
9528
+ path: "illustration-template/mellow-pop"
9529
+ }
9279
9530
  }
9280
9531
  ];
9281
9532
  function filterByKind(kind) {
@@ -9308,16 +9559,16 @@ function selectOpenDesignCandidates() {
9308
9559
  registryVersion: OPEN_DESIGN_REGISTRY_VERSION,
9309
9560
  source: {
9310
9561
  repo: OPEN_DESIGN_REPO,
9311
- commit: OPEN_DESIGN_COMMIT
9562
+ ref: OPEN_DESIGN_COMMIT
9312
9563
  },
9313
9564
  sources: [
9314
9565
  {
9315
9566
  repo: OPEN_DESIGN_REPO,
9316
- commit: OPEN_DESIGN_COMMIT
9567
+ ref: OPEN_DESIGN_COMMIT
9317
9568
  },
9318
9569
  {
9319
9570
  repo: VM0_SKILLS_REPO,
9320
- commit: VM0_SKILLS_REF
9571
+ ref: VM0_SKILLS_REF
9321
9572
  }
9322
9573
  ],
9323
9574
  candidates: {
@@ -9395,7 +9646,7 @@ function createStyledImageAuthoringPacket(options) {
9395
9646
  `Registry: \`${candidateSlice.registryVersion}\``,
9396
9647
  "Sources:",
9397
9648
  ...candidateSlice.sources.map((src) => {
9398
- return `- \`${src.repo}@${src.commit}\``;
9649
+ return `- \`${src.repo}@${src.ref}\``;
9399
9650
  }),
9400
9651
  "",
9401
9652
  "```json",
@@ -9404,7 +9655,7 @@ function createStyledImageAuthoringPacket(options) {
9404
9655
  "",
9405
9656
  "## Stage 2: Resolve Selected Resources",
9406
9657
  "- Fetch or read the selected resource source before generation.",
9407
- "- Source refs are pinned as `repo@commit:path`; use the commit in the packet for reproducibility.",
9658
+ "- Each candidate carries a `source` object with `path` and optional `repo`/`ref`; when `repo`/`ref` are omitted, fall back to the registry-level source above.",
9408
9659
  "- For directory refs, inspect the most relevant files such as `SKILL.md`, references, examples, and templates.",
9409
9660
  "- If a source file cannot be fetched, state that limitation and fall back to the registry metadata for that resource.",
9410
9661
  "",
@@ -9574,6 +9825,12 @@ var BUILT_IN_GENERATION_PROVIDERS = {
9574
9825
  model: "fal-ai/bytedance/seedream/v4/text-to-image",
9575
9826
  command: "zero generate image --provider built-in --model seedream4 -h",
9576
9827
  reason: "available without connector setup"
9828
+ },
9829
+ {
9830
+ label: "Built-in fal.ai",
9831
+ model: "fal-ai/nano-banana-2",
9832
+ command: "zero generate image --provider built-in --model nano-banana-2 -h",
9833
+ reason: "available without connector setup"
9577
9834
  }
9578
9835
  ],
9579
9836
  presentation: [
@@ -9677,7 +9934,7 @@ var BUILT_IN_GENERATION_COMMANDS = {
9677
9934
  image: {
9678
9935
  label: "Built-in image generation",
9679
9936
  command: "zero generate image --provider built-in -h",
9680
- models: "fal.ai: gpt-image-1 (default), gpt-image-2, gpt-image-1.5, gpt-image-1-mini, flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, seedream4"
9937
+ models: "fal.ai: gpt-image-1 (default), gpt-image-2, gpt-image-1.5, gpt-image-1-mini, flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, seedream4, nano-banana-2"
9681
9938
  },
9682
9939
  video: {
9683
9940
  label: "Built-in video generation",
@@ -10196,7 +10453,7 @@ function createImageGenerateCommand(config) {
10196
10453
  "When listing providers (no --prompt given), include unavailable or not-yet-authorized connectors"
10197
10454
  ).option(
10198
10455
  "--model <model>",
10199
- "Model: gpt-image-1 (default), gpt-image-2, gpt-image-1.5, gpt-image-1-mini, flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, or seedream4",
10456
+ "Model: gpt-image-1 (default), gpt-image-2, gpt-image-1.5, gpt-image-1-mini, flux-pro-1.1, flux-pro-1.1-ultra, qwen-image, seedream4, or nano-banana-2",
10200
10457
  "gpt-image-1"
10201
10458
  ).option(
10202
10459
  "--size <size>",
@@ -10253,7 +10510,7 @@ Notes:
10253
10510
  Models:
10254
10511
  - fal.ai: gpt-image-1 (default), gpt-image-2, gpt-image-1.5,
10255
10512
  gpt-image-1-mini, flux-pro-1.1, flux-pro-1.1-ultra, qwen-image,
10256
- seedream4.
10513
+ seedream4, nano-banana-2.
10257
10514
  GPT Image models bill by fal output image quality and size.
10258
10515
  Other fal generations bill by output image or rounded-up output
10259
10516
  megapixel, depending on the model.
@@ -10272,15 +10529,15 @@ Options:
10272
10529
  - Quality: low, medium, high, or auto. Low is fastest for drafts.
10273
10530
  - Background: auto, opaque, or transparent when supported. gpt-image-2,
10274
10531
  Flux, Qwen, and Seedream do not support transparent backgrounds.
10275
- - Format: png, jpeg, or webp for GPT Image models; png or jpeg for the
10276
- other fal models.
10277
- - fal-only controls: --seed, --safety-tolerance for Flux, and
10532
+ - Format: png, jpeg, or webp for GPT Image and Nano Banana 2 models; png or
10533
+ jpeg for the other fal models.
10534
+ - fal-only controls: --seed and --safety-tolerance for supported fal models;
10278
10535
  --enhance-prompt for flux-pro-1.1. --compression and --moderation low are
10279
10536
  not supported on the fal-backed image path.
10280
10537
  - Image-to-image: pass --image-url to use the model's fal edit/redux endpoint.
10281
- Flux Redux accepts --image-prompt-strength to override the provider
10282
- default; GPT edit models accept --input-fidelity and supported models
10283
- accept --mask-image-url.
10538
+ Nano Banana 2 accepts up to 14 source images. Flux Redux accepts
10539
+ --image-prompt-strength to override the provider default; GPT edit models
10540
+ accept --input-fidelity and supported models accept --mask-image-url.
10284
10541
 
10285
10542
  Image Styles:
10286
10543
  ${formatStyleListing(styles)}`;
@@ -10390,6 +10647,7 @@ var imageCommand = createImageGenerateCommand({
10390
10647
  Pipe prompt: cat prompt.txt | zero generate image --skip-style
10391
10648
  GPT Image model: zero generate image --skip-style --model gpt-image-1.5 --prompt "A poster" --size 1024x1536 --quality high
10392
10649
  Flux model: zero generate image --skip-style --model flux-pro-1.1 --prompt "A product hero shot" --seed 42
10650
+ Nano Banana 2: zero generate image --skip-style --model nano-banana-2 --prompt "A crisp launch poster with readable typography"
10393
10651
  Image-to-image: zero generate image --skip-style --model flux-pro-1.1 --image-url https://example.com/mockup.png --prompt "Turn this mockup into a polished product shot"
10394
10652
  List providers: zero generate image
10395
10653
  Use a connector: zero generate image --provider replicate`
@@ -10496,7 +10754,7 @@ function createHtmlArtifactAuthoringPacket(options) {
10496
10754
  `Registry: \`${candidateSlice.registryVersion}\``,
10497
10755
  "Sources:",
10498
10756
  ...candidateSlice.sources.map((src) => {
10499
- return `- \`${src.repo}@${src.commit}\``;
10757
+ return `- \`${src.repo}@${src.ref}\``;
10500
10758
  }),
10501
10759
  "",
10502
10760
  "```json",
@@ -10505,7 +10763,7 @@ function createHtmlArtifactAuthoringPacket(options) {
10505
10763
  "",
10506
10764
  "## Stage 2: Resolve Selected Resources",
10507
10765
  "- For every selected resource, fetch or read the referenced source before authoring.",
10508
- "- Source refs are pinned as `repo@commit:path`; use the commit in the packet for reproducibility.",
10766
+ "- Each candidate carries a `source` object with `path` and optional `repo`/`ref`; when `repo`/`ref` are omitted, fall back to the registry-level source above.",
10509
10767
  "- For directory refs, inspect the most relevant files such as `SKILL.md`, `DESIGN.md`, `README.md`, tokens, examples, and templates.",
10510
10768
  "- If a source file cannot be fetched, state that limitation and fall back to the registry metadata for that resource.",
10511
10769
  "",
@@ -11539,7 +11797,7 @@ function parseLimit4(value) {
11539
11797
  }
11540
11798
  return parsed;
11541
11799
  }
11542
- function resultText2(command) {
11800
+ function resultText(command) {
11543
11801
  if (!command.result) {
11544
11802
  return "";
11545
11803
  }
@@ -11572,7 +11830,7 @@ async function runReadCommand2(kind, options) {
11572
11830
  command.error ? `${command.error.code}: ${command.error.message}` : "Local-browser command failed"
11573
11831
  );
11574
11832
  }
11575
- const text = resultText2(command);
11833
+ const text = resultText(command);
11576
11834
  if (text) {
11577
11835
  console.log(text);
11578
11836
  }
@@ -11599,7 +11857,7 @@ async function waitForCommand2(commandId, timeoutSeconds) {
11599
11857
  command.error ? `${command.error.code}: ${command.error.message}` : "Local-browser command failed"
11600
11858
  );
11601
11859
  }
11602
- const text = resultText2(command);
11860
+ const text = resultText(command);
11603
11861
  if (text) {
11604
11862
  console.log(text);
11605
11863
  }
@@ -12566,7 +12824,7 @@ function registerZeroCommands(prog, commands) {
12566
12824
  var program = new Command();
12567
12825
  program.name("zero").description(
12568
12826
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
12569
- ).version("9.169.2").addHelpText("after", () => {
12827
+ ).version("9.171.0").addHelpText("after", () => {
12570
12828
  return buildZeroHelpText();
12571
12829
  });
12572
12830
  if (process.argv[1]?.endsWith("zero.js") || process.argv[1]?.endsWith("zero.ts") || process.argv[1]?.endsWith("zero")) {