@runtypelabs/cli 2.22.12 → 2.22.14

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 (2) hide show
  1. package/dist/index.js +1235 -201
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -142,9 +142,9 @@ import chalk42 from "chalk";
142
142
  // src/lib/load-env.ts
143
143
  import { readFileSync } from "fs";
144
144
  import { resolve } from "path";
145
- function loadEnv(path18 = resolve(process.cwd(), ".env")) {
145
+ function loadEnv(path19 = resolve(process.cwd(), ".env")) {
146
146
  try {
147
- const content = readFileSync(path18, "utf8").replace(/\r\n?/g, "\n");
147
+ const content = readFileSync(path19, "utf8").replace(/\r\n?/g, "\n");
148
148
  for (const line of content.split("\n")) {
149
149
  if (!line.trim() || line.trimStart().startsWith("#")) continue;
150
150
  const match = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/);
@@ -1386,10 +1386,10 @@ function mergeDefs(...defs) {
1386
1386
  function cloneDef(schema) {
1387
1387
  return mergeDefs(schema._zod.def);
1388
1388
  }
1389
- function getElementAtPath(obj, path18) {
1390
- if (!path18)
1389
+ function getElementAtPath(obj, path19) {
1390
+ if (!path19)
1391
1391
  return obj;
1392
- return path18.reduce((acc, key) => acc?.[key], obj);
1392
+ return path19.reduce((acc, key) => acc?.[key], obj);
1393
1393
  }
1394
1394
  function promiseAllObject(promisesObj) {
1395
1395
  const keys = Object.keys(promisesObj);
@@ -1798,11 +1798,11 @@ function explicitlyAborted(x2, startIndex = 0) {
1798
1798
  }
1799
1799
  return false;
1800
1800
  }
1801
- function prefixIssues(path18, issues) {
1801
+ function prefixIssues(path19, issues) {
1802
1802
  return issues.map((iss) => {
1803
1803
  var _a3;
1804
1804
  (_a3 = iss).path ?? (_a3.path = []);
1805
- iss.path.unshift(path18);
1805
+ iss.path.unshift(path19);
1806
1806
  return iss;
1807
1807
  });
1808
1808
  }
@@ -1949,16 +1949,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1949
1949
  }
1950
1950
  function formatError(error51, mapper = (issue2) => issue2.message) {
1951
1951
  const fieldErrors = { _errors: [] };
1952
- const processError = (error52, path18 = []) => {
1952
+ const processError = (error52, path19 = []) => {
1953
1953
  for (const issue2 of error52.issues) {
1954
1954
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1955
- issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
1955
+ issue2.errors.map((issues) => processError({ issues }, [...path19, ...issue2.path]));
1956
1956
  } else if (issue2.code === "invalid_key") {
1957
- processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1957
+ processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
1958
1958
  } else if (issue2.code === "invalid_element") {
1959
- processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1959
+ processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
1960
1960
  } else {
1961
- const fullpath = [...path18, ...issue2.path];
1961
+ const fullpath = [...path19, ...issue2.path];
1962
1962
  if (fullpath.length === 0) {
1963
1963
  fieldErrors._errors.push(mapper(issue2));
1964
1964
  } else {
@@ -1985,17 +1985,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1985
1985
  }
1986
1986
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1987
1987
  const result = { errors: [] };
1988
- const processError = (error52, path18 = []) => {
1988
+ const processError = (error52, path19 = []) => {
1989
1989
  var _a3, _b;
1990
1990
  for (const issue2 of error52.issues) {
1991
1991
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1992
- issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
1992
+ issue2.errors.map((issues) => processError({ issues }, [...path19, ...issue2.path]));
1993
1993
  } else if (issue2.code === "invalid_key") {
1994
- processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1994
+ processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
1995
1995
  } else if (issue2.code === "invalid_element") {
1996
- processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1996
+ processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
1997
1997
  } else {
1998
- const fullpath = [...path18, ...issue2.path];
1998
+ const fullpath = [...path19, ...issue2.path];
1999
1999
  if (fullpath.length === 0) {
2000
2000
  result.errors.push(mapper(issue2));
2001
2001
  continue;
@@ -2027,8 +2027,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2027
2027
  }
2028
2028
  function toDotPath(_path) {
2029
2029
  const segs = [];
2030
- const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2031
- for (const seg of path18) {
2030
+ const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2031
+ for (const seg of path19) {
2032
2032
  if (typeof seg === "number")
2033
2033
  segs.push(`[${seg}]`);
2034
2034
  else if (typeof seg === "symbol")
@@ -14714,13 +14714,13 @@ function resolveRef(ref, ctx) {
14714
14714
  if (!ref.startsWith("#")) {
14715
14715
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14716
14716
  }
14717
- const path18 = ref.slice(1).split("/").filter(Boolean);
14718
- if (path18.length === 0) {
14717
+ const path19 = ref.slice(1).split("/").filter(Boolean);
14718
+ if (path19.length === 0) {
14719
14719
  return ctx.rootSchema;
14720
14720
  }
14721
14721
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14722
- if (path18[0] === defsKey) {
14723
- const key = path18[1];
14722
+ if (path19[0] === defsKey) {
14723
+ const key = path19[1];
14724
14724
  if (!key || !ctx.defs[key]) {
14725
14725
  throw new Error(`Reference not found: ${ref}`);
14726
14726
  }
@@ -15182,8 +15182,8 @@ var edgeContextPayloadSchema = external_exports.object({
15182
15182
  });
15183
15183
 
15184
15184
  // ../shared/dist/chunk-3FPSMWBQ.mjs
15185
- function getNestedValue(obj, path18) {
15186
- let normalizedPath = path18;
15185
+ function getNestedValue(obj, path19) {
15186
+ let normalizedPath = path19;
15187
15187
  normalizedPath = normalizedPath.replace(/^\$\.?/, "");
15188
15188
  normalizedPath = normalizedPath.replace(/\[(\d+)\]/g, ".$1");
15189
15189
  normalizedPath = normalizedPath.replace(/\[['"]([^'"\]]+)['"]\]/g, ".$1");
@@ -19966,8 +19966,8 @@ function validateCodeToolNameCollisions(toolNames, stepRef, code, preSeededCount
19966
19966
  }
19967
19967
  return null;
19968
19968
  }
19969
- function formatPath(path18) {
19970
- return path18.reduce((acc, part) => {
19969
+ function formatPath(path19) {
19970
+ return path19.reduce((acc, part) => {
19971
19971
  if (typeof part === "number") {
19972
19972
  return `${acc}[${part}]`;
19973
19973
  }
@@ -20088,17 +20088,17 @@ function collectTransformDataCodeToolNameCheck(toolsConfig, stepIndex, stepRef,
20088
20088
  if (typeof toolId !== "string") {
20089
20089
  continue;
20090
20090
  }
20091
- const path18 = `flowSteps[${stepIndex}].config.tools.toolIds[${toolIdIndex}]`;
20091
+ const path19 = `flowSteps[${stepIndex}].config.tools.toolIds[${toolIdIndex}]`;
20092
20092
  const named = parseNamedToolRef(toolId);
20093
20093
  if (named) {
20094
- selectedToolNames.push({ name: named.name, path: path18 });
20094
+ selectedToolNames.push({ name: named.name, path: path19 });
20095
20095
  continue;
20096
20096
  }
20097
20097
  const { customToolIds } = separateToolIds([toolId]);
20098
20098
  if (customToolIds.length === 0) {
20099
20099
  continue;
20100
20100
  }
20101
- selectedToolIds.push({ toolId, path: path18 });
20101
+ selectedToolIds.push({ toolId, path: path19 });
20102
20102
  }
20103
20103
  if (selectedToolIds.length > 0 || selectedToolNames.length > 0) {
20104
20104
  pendingChecks.hasAccountScopedReferences = true;
@@ -20131,10 +20131,10 @@ function collectCodeModeToolNameCheck(toolsConfig, stepIndex, stepRef, pendingCh
20131
20131
  if (typeof entry !== "string" || entry.length === 0 || entry.endsWith(":*")) {
20132
20132
  continue;
20133
20133
  }
20134
- const path18 = `flowSteps[${stepIndex}].config.tools.codeModeConfig.toolPool[${toolPoolIndex}]`;
20134
+ const path19 = `flowSteps[${stepIndex}].config.tools.codeModeConfig.toolPool[${toolPoolIndex}]`;
20135
20135
  const named = parseNamedToolRef(entry);
20136
20136
  if (named) {
20137
- selectedToolNames.push({ name: named.name, path: path18 });
20137
+ selectedToolNames.push({ name: named.name, path: path19 });
20138
20138
  continue;
20139
20139
  }
20140
20140
  if (runtimeToolNames.has(entry)) {
@@ -20145,7 +20145,7 @@ function collectCodeModeToolNameCheck(toolsConfig, stepIndex, stepRef, pendingCh
20145
20145
  if (customToolIds.length === 0) {
20146
20146
  continue;
20147
20147
  }
20148
- selectedToolIds.push({ toolId: entry, path: path18 });
20148
+ selectedToolIds.push({ toolId: entry, path: path19 });
20149
20149
  }
20150
20150
  if (selectedToolIds.length > 0 || selectedToolNames.length > 0) {
20151
20151
  pendingChecks.hasAccountScopedReferences = true;
@@ -20196,19 +20196,19 @@ var TEMPLATE_STRING_FIELDS = /* @__PURE__ */ new Set([
20196
20196
  "requestTemplate"
20197
20197
  ]);
20198
20198
  var NON_FLOW_VARIABLE_SUBTREE_KEYS = /* @__PURE__ */ new Set(["tools"]);
20199
- function extractTemplateStrings(config3, path18 = []) {
20199
+ function extractTemplateStrings(config3, path19 = []) {
20200
20200
  const results = [];
20201
20201
  if (typeof config3 === "string") {
20202
- const fieldName = path18[path18.length - 1];
20203
- const parentFieldName = path18.length >= 2 ? path18[path18.length - 2] : void 0;
20202
+ const fieldName = path19[path19.length - 1];
20203
+ const parentFieldName = path19.length >= 2 ? path19[path19.length - 2] : void 0;
20204
20204
  if (fieldName && TEMPLATE_STRING_FIELDS.has(fieldName) || parentFieldName && TEMPLATE_STRING_FIELDS.has(parentFieldName)) {
20205
- results.push({ value: config3, fieldPath: path18.join(".") });
20205
+ results.push({ value: config3, fieldPath: path19.join(".") });
20206
20206
  }
20207
20207
  return results;
20208
20208
  }
20209
20209
  if (Array.isArray(config3)) {
20210
20210
  for (const [index, item] of config3.entries()) {
20211
- results.push(...extractTemplateStrings(item, [...path18, String(index)]));
20211
+ results.push(...extractTemplateStrings(item, [...path19, String(index)]));
20212
20212
  }
20213
20213
  return results;
20214
20214
  }
@@ -20216,9 +20216,9 @@ function extractTemplateStrings(config3, path18 = []) {
20216
20216
  for (const [key, val] of Object.entries(config3)) {
20217
20217
  if (NON_FLOW_VARIABLE_SUBTREE_KEYS.has(key)) continue;
20218
20218
  if (typeof val === "string" && TEMPLATE_STRING_FIELDS.has(key)) {
20219
- results.push({ value: val, fieldPath: [...path18, key].join(".") });
20219
+ results.push({ value: val, fieldPath: [...path19, key].join(".") });
20220
20220
  } else if (typeof val === "object" && val !== null) {
20221
- results.push(...extractTemplateStrings(val, [...path18, key]));
20221
+ results.push(...extractTemplateStrings(val, [...path19, key]));
20222
20222
  }
20223
20223
  }
20224
20224
  }
@@ -20249,8 +20249,8 @@ function extractVariableReferences(config3) {
20249
20249
  while ((match = pattern.exec(value)) !== null) {
20250
20250
  const expr = match[1];
20251
20251
  if (!expr) continue;
20252
- for (const path18 of extractTemplateExpressionPaths(expr)) {
20253
- references.push({ variable: path18, fieldPath });
20252
+ for (const path19 of extractTemplateExpressionPaths(expr)) {
20253
+ references.push({ variable: path19, fieldPath });
20254
20254
  }
20255
20255
  }
20256
20256
  }
@@ -20403,7 +20403,7 @@ function validateUpsertRecordSourceShape(flowSteps, buckets) {
20403
20403
  }
20404
20404
  }
20405
20405
  }
20406
- function checkConditionExpression(expr, path18, stepRef, buckets) {
20406
+ function checkConditionExpression(expr, path19, stepRef, buckets) {
20407
20407
  if (typeof expr !== "string" || !expr.includes("{{")) return;
20408
20408
  const match = UNQUOTED_TEMPLATE_BEFORE_OP.exec(expr) || UNQUOTED_TEMPLATE_AFTER_OP.exec(expr);
20409
20409
  if (!match) return;
@@ -20413,7 +20413,7 @@ function checkConditionExpression(expr, path18, stepRef, buckets) {
20413
20413
  {
20414
20414
  code: "CONDITION_UNQUOTED_TEMPLATE_COMPARISON",
20415
20415
  message: `Expression compares an unquoted {{...}} placeholder against a string literal (\`${snippet}\`). \`condition\` / \`when\` predicates are JavaScript evaluated after template substitution, so a non-numeric value substitutes in as a bare identifier (e.g. \`healthy === 'watch'\`) and throws "ReferenceError: <value> is not defined" at runtime. Quote the placeholder \u2014 e.g. '{{var}}' === '...' \u2014 or compare numerically.`,
20416
- path: path18,
20416
+ path: path19,
20417
20417
  step: stepRef,
20418
20418
  details: { snippet }
20419
20419
  },
@@ -20491,24 +20491,24 @@ function collectAccountScopedReferences(step, stepIndex, pendingChecks) {
20491
20491
  if (step.type === "execute-agent") {
20492
20492
  const agentId = step.config.agentId;
20493
20493
  if (typeof agentId === "string" && !agentId.includes("{{")) {
20494
- const path18 = `flowSteps[${stepIndex}].config.agentId`;
20495
- registerAgentReference(agentId, path18, stepRef, pendingChecks);
20494
+ const path19 = `flowSteps[${stepIndex}].config.agentId`;
20495
+ registerAgentReference(agentId, path19, stepRef, pendingChecks);
20496
20496
  }
20497
20497
  return;
20498
20498
  }
20499
20499
  if (step.type === "tool-call") {
20500
20500
  const toolId = step.config.toolId;
20501
20501
  if (typeof toolId === "string") {
20502
- const path18 = `flowSteps[${stepIndex}].config.toolId`;
20502
+ const path19 = `flowSteps[${stepIndex}].config.toolId`;
20503
20503
  const named = parseNamedToolRef(toolId);
20504
20504
  if (named) {
20505
20505
  pendingChecks.hasAccountScopedReferences = true;
20506
- registerReference(pendingChecks.toolReferencesByName, named.name, { path: path18, step: stepRef });
20506
+ registerReference(pendingChecks.toolReferencesByName, named.name, { path: path19, step: stepRef });
20507
20507
  } else {
20508
20508
  const { customToolIds } = separateToolIds([toolId]);
20509
20509
  if (customToolIds.length > 0) {
20510
20510
  pendingChecks.hasAccountScopedReferences = true;
20511
- registerReference(pendingChecks.toolReferencesById, toolId, { path: path18, step: stepRef });
20511
+ registerReference(pendingChecks.toolReferencesById, toolId, { path: path19, step: stepRef });
20512
20512
  }
20513
20513
  }
20514
20514
  }
@@ -20527,17 +20527,17 @@ function collectAccountScopedReferences(step, stepIndex, pendingChecks) {
20527
20527
  if (typeof toolId !== "string") {
20528
20528
  continue;
20529
20529
  }
20530
- const path18 = `flowSteps[${stepIndex}].config.tools.toolIds[${toolIdIndex}]`;
20530
+ const path19 = `flowSteps[${stepIndex}].config.tools.toolIds[${toolIdIndex}]`;
20531
20531
  const named = parseNamedToolRef(toolId);
20532
20532
  if (named) {
20533
20533
  pendingChecks.hasAccountScopedReferences = true;
20534
- registerReference(pendingChecks.toolReferencesByName, named.name, { path: path18, step: stepRef });
20534
+ registerReference(pendingChecks.toolReferencesByName, named.name, { path: path19, step: stepRef });
20535
20535
  continue;
20536
20536
  }
20537
20537
  const { customToolIds } = separateToolIds([toolId]);
20538
20538
  if (customToolIds.length > 0) {
20539
20539
  pendingChecks.hasAccountScopedReferences = true;
20540
- registerReference(pendingChecks.toolReferencesById, toolId, { path: path18, step: stepRef });
20540
+ registerReference(pendingChecks.toolReferencesById, toolId, { path: path19, step: stepRef });
20541
20541
  }
20542
20542
  }
20543
20543
  }
@@ -20575,22 +20575,22 @@ function collectAccountScopedReferences(step, stepIndex, pendingChecks) {
20575
20575
  }
20576
20576
  }
20577
20577
  }
20578
- function registerAgentReference(agentId, path18, stepRef, pendingChecks) {
20578
+ function registerAgentReference(agentId, path19, stepRef, pendingChecks) {
20579
20579
  const named = parseNamedAgentRef(agentId);
20580
20580
  pendingChecks.hasAccountScopedReferences = true;
20581
20581
  if (named) {
20582
- registerReference(pendingChecks.agentReferencesByName, named.name, { path: path18, step: stepRef });
20582
+ registerReference(pendingChecks.agentReferencesByName, named.name, { path: path19, step: stepRef });
20583
20583
  } else {
20584
- registerReference(pendingChecks.agentReferencesById, agentId, { path: path18, step: stepRef });
20584
+ registerReference(pendingChecks.agentReferencesById, agentId, { path: path19, step: stepRef });
20585
20585
  }
20586
20586
  }
20587
- function registerFlowReference(flowId, path18, stepRef, pendingChecks) {
20587
+ function registerFlowReference(flowId, path19, stepRef, pendingChecks) {
20588
20588
  const named = parseNamedFlowRef(flowId);
20589
20589
  pendingChecks.hasAccountScopedReferences = true;
20590
20590
  if (named) {
20591
- registerReference(pendingChecks.flowReferencesByName, named.name, { path: path18, step: stepRef });
20591
+ registerReference(pendingChecks.flowReferencesByName, named.name, { path: path19, step: stepRef });
20592
20592
  } else {
20593
- registerReference(pendingChecks.flowReferencesById, flowId, { path: path18, step: stepRef });
20593
+ registerReference(pendingChecks.flowReferencesById, flowId, { path: path19, step: stepRef });
20594
20594
  }
20595
20595
  }
20596
20596
  function validateSubagentConfig(value, stepTools, stepIndex, stepRef) {
@@ -35752,7 +35752,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
35752
35752
  {
35753
35753
  id: "bash",
35754
35754
  name: "Bash",
35755
- description: "Run a shell command on your Linux computer (Node 22, Python 3.12, git, pnpm, uv preinstalled). Commands run in /workspace; files you write there are available to later commands, but system-level changes outside /workspace may not persist. Combined stdout/stderr is returned. Long output is truncated (head + tail) with the full output spilled to a file. Pass slow_ok=true for commands that take a while (installs, builds, test suites).",
35755
+ description: 'Run a shell command on your Linux computer (Node 22, Python 3.12, git, pnpm, uv, ripgrep preinstalled). Commands run in /workspace; files you write there are available to later commands, but system-level changes outside /workspace may not persist. Combined stdout/stderr is returned. Prefer searching over dumping: use `rg`/`grep` to find the lines you need and `head`/`tail`/`sed -n` to read slices, rather than printing whole files or verbose logs. Output is capped (head + tail) and the full output is spilled to a file in the sandbox that you can grep \u2014 so re-running a noisy command to "see the rest" wastes time; grep the spilled file instead. Pass slow_ok=true for commands that take a while (installs, builds, test suites).',
35756
35756
  category: BuiltInToolCategory.SANDBOX,
35757
35757
  toolGroup: BuiltInToolGroup.SANDBOX_AGENT,
35758
35758
  providers: [BuiltInToolProvider.MULTI],
@@ -35779,7 +35779,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
35779
35779
  {
35780
35780
  id: "read_file",
35781
35781
  name: "Read File",
35782
- description: "Read a file from your computer. Returns the file contents as a string.",
35782
+ description: "Read a file from your computer (relative paths resolve against /workspace). Returns the contents as a string. Large files and very long lines are truncated; to find something in a big file, grep/rg it from bash (e.g. `rg -n <pattern> <path>`) or read a slice with `sed -n` instead of reading the whole file.",
35783
35783
  category: BuiltInToolCategory.SANDBOX,
35784
35784
  toolGroup: BuiltInToolGroup.SANDBOX_AGENT,
35785
35785
  providers: [BuiltInToolProvider.MULTI],
@@ -37886,6 +37886,9 @@ var MODEL_FAMILY_PROVIDER_IDS = {
37886
37886
  "flux-pro-1.1-ultra": {
37887
37887
  "vercel": "bfl/flux-pro-1.1-ultra"
37888
37888
  },
37889
+ "fugu-ultra": {
37890
+ "vercel": "sakana/fugu-ultra"
37891
+ },
37889
37892
  "gemini-2-5-flash": {
37890
37893
  "google": "gemini-2.5-flash",
37891
37894
  "vercel": "google/gemini-2.5-flash"
@@ -37999,18 +38002,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
37999
38002
  "togetherai": "togetherai/pearl-ai/gemma-4-31b-it",
38000
38003
  "vercel": "google/gemma-4-31b-it"
38001
38004
  },
38002
- "gemma-4-e2b-it": {
38003
- "google": "gemma-4-E2B-it"
38004
- },
38005
- "gemma-4-E2B-it": {
38006
- "google": "gemma-4-E2B-it"
38007
- },
38008
- "gemma-4-e4b-it": {
38009
- "google": "gemma-4-E4B-it"
38010
- },
38011
- "gemma-4-E4B-it": {
38012
- "google": "gemma-4-E4B-it"
38013
- },
38014
38005
  "glm-4-5": {
38015
38006
  "vercel": "zai/glm-4.5"
38016
38007
  },
@@ -38306,9 +38297,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38306
38297
  "openai": "gpt-image-1.5",
38307
38298
  "vercel": "openai/gpt-image-1.5"
38308
38299
  },
38309
- "gpt-image-2": {
38310
- "vercel": "openai/gpt-image-2"
38311
- },
38312
38300
  "gpt-oss-120b": {
38313
38301
  "togetherai": "togetherai/openai/gpt-oss-120b",
38314
38302
  "vercel": "openai/gpt-oss-120b"
@@ -39059,12 +39047,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
39059
39047
  "seedance-2.0-fast": {
39060
39048
  "vercel": "bytedance/seedance-2.0-fast"
39061
39049
  },
39062
- "seedance-v1-0-lite-i2v": {
39063
- "vercel": "bytedance/seedance-v1.0-lite-i2v"
39064
- },
39065
- "seedance-v1-0-lite-t2v": {
39066
- "vercel": "bytedance/seedance-v1.0-lite-t2v"
39067
- },
39068
39050
  "seedance-v1-0-pro": {
39069
39051
  "vercel": "bytedance/seedance-v1.0-pro"
39070
39052
  },
@@ -39074,12 +39056,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
39074
39056
  "seedance-v1-5-pro": {
39075
39057
  "vercel": "bytedance/seedance-v1.5-pro"
39076
39058
  },
39077
- "seedance-v1.0-lite-i2v": {
39078
- "vercel": "bytedance/seedance-v1.0-lite-i2v"
39079
- },
39080
- "seedance-v1.0-lite-t2v": {
39081
- "vercel": "bytedance/seedance-v1.0-lite-t2v"
39082
- },
39083
39059
  "seedance-v1.0-pro": {
39084
39060
  "vercel": "bytedance/seedance-v1.0-pro"
39085
39061
  },
@@ -40866,8 +40842,8 @@ var FLAT_ADVANCED_CONFIG_KEYS = {
40866
40842
  var FLAT_ADVANCED_CONFIG_KEY_LIST = Object.keys(
40867
40843
  FLAT_ADVANCED_CONFIG_KEYS
40868
40844
  );
40869
- function createIssue(severity, code, message, path18, suggestedFix) {
40870
- return { code, message, path: path18, severity, ...suggestedFix ? { suggestedFix } : {} };
40845
+ function createIssue(severity, code, message, path19, suggestedFix) {
40846
+ return { code, message, path: path19, severity, ...suggestedFix ? { suggestedFix } : {} };
40871
40847
  }
40872
40848
  function emptyResult() {
40873
40849
  return { valid: true, errors: [], warnings: [], recommendations: [] };
@@ -41593,16 +41569,16 @@ var FLOW_PREFIX = Object.values(RUNTIME_PREFIXES).find((spec) => spec.namespace
41593
41569
  var SECRET_PREFIX = Object.values(RUNTIME_PREFIXES).find(
41594
41570
  (spec) => spec.namespace === "secret"
41595
41571
  ).prefix;
41596
- function collectStringLeafPaths(value, path18 = []) {
41572
+ function collectStringLeafPaths(value, path19 = []) {
41597
41573
  if (typeof value === "string") {
41598
- return [{ path: path18, value }];
41574
+ return [{ path: path19, value }];
41599
41575
  }
41600
41576
  if (Array.isArray(value)) {
41601
- return value.flatMap((item, index) => collectStringLeafPaths(item, [...path18, String(index)]));
41577
+ return value.flatMap((item, index) => collectStringLeafPaths(item, [...path19, String(index)]));
41602
41578
  }
41603
41579
  if (value && typeof value === "object") {
41604
41580
  return Object.entries(value).flatMap(
41605
- ([key, nestedValue]) => collectStringLeafPaths(nestedValue, [...path18, key])
41581
+ ([key, nestedValue]) => collectStringLeafPaths(nestedValue, [...path19, key])
41606
41582
  );
41607
41583
  }
41608
41584
  return [];
@@ -43460,7 +43436,7 @@ function buildDashboardUrl(opts) {
43460
43436
  while (base.endsWith("/")) {
43461
43437
  base = base.slice(0, -1);
43462
43438
  }
43463
- const path18 = opts.path.startsWith("/") ? opts.path : `/${opts.path}`;
43439
+ const path19 = opts.path.startsWith("/") ? opts.path : `/${opts.path}`;
43464
43440
  const params = new URLSearchParams();
43465
43441
  if (isValidAccountId(opts.account)) {
43466
43442
  params.set(ACCOUNT_QUERY_PARAM, opts.account);
@@ -43473,7 +43449,7 @@ function buildDashboardUrl(opts) {
43473
43449
  }
43474
43450
  }
43475
43451
  const qs = params.toString();
43476
- return qs ? `${base}${path18}?${qs}` : `${base}${path18}`;
43452
+ return qs ? `${base}${path19}?${qs}` : `${base}${path19}`;
43477
43453
  }
43478
43454
  function parseAccountId(value) {
43479
43455
  if (!value) return null;
@@ -44776,13 +44752,13 @@ function parseJsonObject(raw, label) {
44776
44752
  }
44777
44753
  return parsed;
44778
44754
  }
44779
- function readJsonFile(path18, opts = {}) {
44755
+ function readJsonFile(path19, opts = {}) {
44780
44756
  const label = opts.label ?? "file";
44781
44757
  let raw;
44782
44758
  try {
44783
- raw = readFileSync3(path18, "utf-8");
44759
+ raw = readFileSync3(path19, "utf-8");
44784
44760
  } catch {
44785
- console.error(chalk2.red(`Failed to read ${label}: ${path18}`));
44761
+ console.error(chalk2.red(`Failed to read ${label}: ${path19}`));
44786
44762
  process.exit(1);
44787
44763
  }
44788
44764
  const obj = parseJsonObject(raw, label);
@@ -48664,11 +48640,21 @@ import open2 from "open";
48664
48640
 
48665
48641
  // src/lib/account-context.ts
48666
48642
  init_credential_store();
48667
- async function getCurrentAccountId() {
48643
+ async function getCurrentAccountId(options) {
48644
+ if (options?.apiKey) {
48645
+ try {
48646
+ const apiKeyManager = new ApiKeyManager();
48647
+ const user = await apiKeyManager.getCurrentUser(options.apiKey, options.apiUrl);
48648
+ const account = selectAccountId({ userId: user.userId, organizationId: user.orgId });
48649
+ if (account) return account;
48650
+ } catch {
48651
+ }
48652
+ }
48668
48653
  try {
48669
48654
  const store = new CredentialStore();
48670
48655
  const creds = await store.getCredentials();
48671
48656
  if (!creds) return void 0;
48657
+ if (options?.apiKey && creds.apiKey !== options.apiKey) return void 0;
48672
48658
  return selectAccountId({ userId: creds.userId, organizationId: creds.orgId });
48673
48659
  } catch {
48674
48660
  return void 0;
@@ -64429,8 +64415,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
64429
64415
  const client = createCliClient(apiKey);
64430
64416
  if (!isTTY(options) || options.json) {
64431
64417
  try {
64432
- const path18 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
64433
- const data = await client.get(path18);
64418
+ const path19 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
64419
+ const data = await client.get(path19);
64434
64420
  printJson(data);
64435
64421
  } catch (error51) {
64436
64422
  const message = error51 instanceof Error ? error51.message : "Unknown error";
@@ -64447,8 +64433,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
64447
64433
  useEffect31(() => {
64448
64434
  const run2 = async () => {
64449
64435
  try {
64450
- const path18 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
64451
- const data = await client.get(path18);
64436
+ const path19 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
64437
+ const data = await client.get(path19);
64452
64438
  printJson(data);
64453
64439
  setSuccess(true);
64454
64440
  setLoading(false);
@@ -64901,7 +64887,7 @@ clientTokensCommand.command("regenerate <id>").description("Regenerate a client
64901
64887
  import { Command as Command23 } from "commander";
64902
64888
  import chalk30 from "chalk";
64903
64889
  import readline3 from "readline";
64904
- import open5 from "open";
64890
+ import openBrowser from "open";
64905
64891
  import { execFileSync } from "child_process";
64906
64892
 
64907
64893
  // src/lib/persona-init.ts
@@ -65238,8 +65224,52 @@ function generatePersonaInitSnippet(input, personaFormat) {
65238
65224
  target ? { target } : void 0
65239
65225
  );
65240
65226
  }
65227
+ function getPersonaInstallerScriptUrl() {
65228
+ const snippet = R(
65229
+ {
65230
+ apiUrl: "https://api.runtype.com",
65231
+ clientToken: "ct_test_demo_00000000000000000000000000000000",
65232
+ parserType: "json"
65233
+ },
65234
+ "script-installer"
65235
+ );
65236
+ const match = snippet.match(/<script\s+src="([^"]+)"/);
65237
+ return match?.[1] ?? "https://cdn.jsdelivr.net/npm/@runtypelabs/persona/dist/install.global.js";
65238
+ }
65241
65239
 
65242
65240
  // src/lib/persona-init.ts
65241
+ var PERSONA_INIT_AGENT_MODEL = "nemotron-3-ultra-550b-a55b";
65242
+ var PERSONA_INIT_DEMO_SYSTEM_PROMPT = `
65243
+ # Persona Playground Agent
65244
+
65245
+ ## Role
65246
+
65247
+ You are the assistant inside a local Persona Playground generated by the Runtype CLI.
65248
+
65249
+ ## Goal
65250
+
65251
+ Give the user one quick, visible "aha" moment: inspect the local page, request approval for a browser-side update, make the page change, and leave them with native next-step pills.
65252
+
65253
+ ## Available page tools
65254
+
65255
+ - \`get_playground_state\` \u2014 read the current accent, headline, note, status, checklist, URL, and allowed origins.
65256
+ - \`update_playground\` \u2014 update the accent, headline, note, status, or checklist on the local HTML page.
65257
+
65258
+ ## Demo behavior
65259
+
65260
+ 1. Use \`get_playground_state\` before describing the current page or proposing a specific page change.
65261
+ 2. Use \`update_playground\` when the user asks you to change the page.
65262
+ 3. Explain, only when relevant, that mutating page updates require the user to approve Persona's tool-call bubble.
65263
+ 4. After every successful \`update_playground\` call, follow \`responseGuidance\` exactly: do not send a visible response yet; first call \`suggest_replies\` with \`responseGuidance.suggestedReplies\`.
65264
+ 5. When \`suggest_replies\` returns, send \`responseGuidance.assistantMessage\` exactly once as your only visible confirmation, then stop.
65265
+ 6. Do not ask "what would you like to do next?" in prose; the Persona widget renders \`suggest_replies\` as tappable next-step pills.
65266
+
65267
+ ## Response style
65268
+
65269
+ - Be concise, direct, and practical.
65270
+ - Prefer showing the page changing over explaining how it works.
65271
+ - If the user asks how to customize the demo, point them to \`index.html\`, the generated README, and the Runtype dashboard link.
65272
+ `.trim();
65243
65273
  async function getPersonaInitApiKeyNonInteractive(apiUrl) {
65244
65274
  const envApiKey = getRuntimeApiKey();
65245
65275
  if (envApiKey) {
@@ -65257,14 +65287,75 @@ async function getPersonaInitApiKeyNonInteractive(apiUrl) {
65257
65287
  }
65258
65288
  async function runPersonaInit(options) {
65259
65289
  const client = createCliClient(options.apiKey, options.apiUrl);
65290
+ const demoEnabled = !!options.demo;
65260
65291
  const agent = await client.post("/agents", {
65261
65292
  name: options.agentName,
65262
65293
  description: options.agentDescription || "A Persona test agent",
65263
65294
  config: {
65264
- model: "qwen3.5-35b-a3b",
65265
- systemPrompt: "You are a helpful assistant."
65295
+ model: PERSONA_INIT_AGENT_MODEL,
65296
+ systemPrompt: demoEnabled ? PERSONA_INIT_DEMO_SYSTEM_PROMPT : "You are a helpful assistant."
65266
65297
  }
65267
65298
  });
65299
+ let demoResources;
65300
+ if (options.demo) {
65301
+ const product = await client.post("/products", {
65302
+ name: `${options.agentName} Persona Playground`,
65303
+ description: "Local Persona WebMCP playground generated by the Runtype CLI.",
65304
+ icon: "\u2728",
65305
+ spec: {
65306
+ productGoal: "Demonstrate a Persona widget operating a host page through WebMCP tools.",
65307
+ targetAudience: "Developers testing Persona locally.",
65308
+ productStage: "prototype"
65309
+ }
65310
+ });
65311
+ const capability = await client.post(
65312
+ `/products/${product.id}/capabilities`,
65313
+ {
65314
+ agentId: agent.id,
65315
+ capabilityName: "Persona Playground Assistant",
65316
+ capabilityDescription: "Agent that can read and update the local Persona Playground page through WebMCP tools.",
65317
+ enabled: true
65318
+ }
65319
+ );
65320
+ const allowlist = options.demo.origins.map((origin) => ({
65321
+ origin,
65322
+ tools: options.demo?.toolNames ?? []
65323
+ }));
65324
+ const surface = await client.post(
65325
+ `/products/${product.id}/surfaces`,
65326
+ {
65327
+ name: "Local Persona Playground",
65328
+ type: "chat",
65329
+ status: "active",
65330
+ environment: "development",
65331
+ behavior: {
65332
+ type: "chat",
65333
+ welcomeMessage: "Try asking me to inspect or update this local page. I can use WebMCP tools registered by the HTML file.",
65334
+ webmcp: {
65335
+ enabled: true,
65336
+ allowlist,
65337
+ requireConfirmFor: ["update_playground"]
65338
+ }
65339
+ }
65340
+ }
65341
+ );
65342
+ const surfaceItem = await client.post(
65343
+ `/products/${product.id}/surfaces/${surface.id}/items`,
65344
+ {
65345
+ capabilityId: capability.id,
65346
+ exposedName: "Persona Playground Assistant",
65347
+ exposedDescription: "Operate the generated local HTML playground.",
65348
+ enabled: true,
65349
+ isEntryPoint: true
65350
+ }
65351
+ );
65352
+ demoResources = {
65353
+ productId: product.id,
65354
+ capabilityId: capability.id,
65355
+ surfaceId: surface.id,
65356
+ surfaceItemId: surfaceItem.id
65357
+ };
65358
+ }
65268
65359
  const tokenBody = {
65269
65360
  name: options.tokenName,
65270
65361
  flowIds: [],
@@ -65274,7 +65365,8 @@ async function runPersonaInit(options) {
65274
65365
  rateLimitPerMinute: 10,
65275
65366
  rateLimitPerHour: 100,
65276
65367
  maxMessagesPerSession: 100,
65277
- sessionIdleTimeoutMinutes: 30
65368
+ sessionIdleTimeoutMinutes: 30,
65369
+ ...demoResources ? { productSurfaceId: demoResources.surfaceId } : {}
65278
65370
  };
65279
65371
  const tokenRes = await client.post("/client-tokens", tokenBody);
65280
65372
  const personaFormat = mapCliFormatToPersona(options.format);
@@ -65287,7 +65379,7 @@ async function runPersonaInit(options) {
65287
65379
  personaFormat
65288
65380
  );
65289
65381
  const dashboardBase = getDashboardUrl();
65290
- const account = await getCurrentAccountId();
65382
+ const account = await getCurrentAccountId({ apiKey: options.apiKey, apiUrl: options.apiUrl });
65291
65383
  const dashboardUrl = buildDashboardUrl({
65292
65384
  baseUrl: dashboardBase,
65293
65385
  path: `/agents/${agent.id}`,
@@ -65304,20 +65396,718 @@ async function runPersonaInit(options) {
65304
65396
  },
65305
65397
  snippet: { format: options.format, code },
65306
65398
  dashboardUrl,
65307
- warnings: tokenRes.warnings
65399
+ warnings: tokenRes.warnings,
65400
+ ...demoResources ? { demo: demoResources } : {}
65308
65401
  };
65309
65402
  }
65310
65403
 
65404
+ // src/lib/persona-demo.ts
65405
+ import { createServer } from "http";
65406
+ import { createServer as createNetServer } from "net";
65407
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "fs";
65408
+ import path16 from "path";
65409
+ var PERSONA_DEMO_DEFAULT_DIR = "persona-demo";
65410
+ var PERSONA_DEMO_DEFAULT_PORT = 43110;
65411
+ var PERSONA_DEMO_TOOL_NAMES = ["get_playground_state", "update_playground"];
65412
+ function unique(values) {
65413
+ return [...new Set(values.filter(Boolean))];
65414
+ }
65415
+ function buildPersonaDemoOrigins(port) {
65416
+ return [`http://localhost:${port}`, `http://127.0.0.1:${port}`];
65417
+ }
65418
+ function mergePersonaDemoAllowedOrigins(requestedOrigins, demoOrigins) {
65419
+ const explicitOrigins = (requestedOrigins ?? []).filter((origin) => origin !== "*");
65420
+ return unique([...demoOrigins, ...explicitOrigins]);
65421
+ }
65422
+ function resolvePersonaDemoDirectory(input) {
65423
+ return path16.resolve(process.cwd(), input?.trim() || PERSONA_DEMO_DEFAULT_DIR);
65424
+ }
65425
+ function personaDemoIndexPath(directory) {
65426
+ return path16.join(directory, "index.html");
65427
+ }
65428
+ function personaDemoReadmePath(directory) {
65429
+ return path16.join(directory, "README.md");
65430
+ }
65431
+ function ensurePersonaDemoCanWrite(directory, force) {
65432
+ const existingFiles = [personaDemoIndexPath(directory), personaDemoReadmePath(directory)].filter(
65433
+ (filePath) => existsSync13(filePath)
65434
+ );
65435
+ if (existingFiles.length > 0 && !force) {
65436
+ throw new Error(
65437
+ `Demo file already exists at ${existingFiles.join(", ")}. Pass --force to overwrite demo files or choose --demo-dir.`
65438
+ );
65439
+ }
65440
+ }
65441
+ function writePersonaDemoPage(options) {
65442
+ ensurePersonaDemoCanWrite(options.directory, options.force);
65443
+ mkdirSync8(options.directory, { recursive: true });
65444
+ const filePath = personaDemoIndexPath(options.directory);
65445
+ const readmePath = personaDemoReadmePath(options.directory);
65446
+ writeFileSync6(filePath, `${options.html.trim()}
65447
+ `, "utf8");
65448
+ writeFileSync6(readmePath, `${options.readme.trim()}
65449
+ `, "utf8");
65450
+ return { directory: options.directory, filePath, readmePath };
65451
+ }
65452
+ async function findAvailablePersonaDemoPort(preferredPort = PERSONA_DEMO_DEFAULT_PORT) {
65453
+ for (let offset = 0; offset < 50; offset += 1) {
65454
+ const port = preferredPort + offset;
65455
+ if (await canListenOnPort(port)) {
65456
+ return port;
65457
+ }
65458
+ }
65459
+ throw new Error(`Could not find an available local port starting at ${preferredPort}`);
65460
+ }
65461
+ function canListenOnPort(port) {
65462
+ return new Promise((resolve11) => {
65463
+ const server = createNetServer();
65464
+ server.once("error", () => {
65465
+ resolve11(false);
65466
+ });
65467
+ server.once("listening", () => {
65468
+ server.close(() => resolve11(true));
65469
+ });
65470
+ server.listen(port, "127.0.0.1");
65471
+ });
65472
+ }
65473
+ async function startPersonaDemoServer(options) {
65474
+ const filePath = personaDemoIndexPath(options.directory);
65475
+ const server = createServer((req, res) => {
65476
+ const url2 = req.url?.split("?")[0] ?? "/";
65477
+ if (url2 !== "/" && url2 !== "/index.html") {
65478
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
65479
+ res.end("Not found");
65480
+ return;
65481
+ }
65482
+ res.writeHead(200, {
65483
+ "content-type": "text/html; charset=utf-8",
65484
+ "cache-control": "no-store"
65485
+ });
65486
+ res.end(readIndexHtml(filePath));
65487
+ });
65488
+ await listen(server, options.port);
65489
+ return {
65490
+ url: `http://127.0.0.1:${options.port}/`,
65491
+ port: options.port,
65492
+ close: () => new Promise((resolve11, reject) => {
65493
+ server.close((error51) => {
65494
+ if (error51) reject(error51);
65495
+ else resolve11();
65496
+ });
65497
+ })
65498
+ };
65499
+ }
65500
+ function readIndexHtml(filePath) {
65501
+ return readFileSync17(filePath, "utf8");
65502
+ }
65503
+ function listen(server, port) {
65504
+ return new Promise((resolve11, reject) => {
65505
+ server.once("error", reject);
65506
+ server.listen(port, "127.0.0.1", () => {
65507
+ server.off("error", reject);
65508
+ resolve11();
65509
+ });
65510
+ });
65511
+ }
65512
+ function escapeHtml(value) {
65513
+ return value.replace(/[&<>"']/g, (char) => {
65514
+ switch (char) {
65515
+ case "&":
65516
+ return "&amp;";
65517
+ case "<":
65518
+ return "&lt;";
65519
+ case ">":
65520
+ return "&gt;";
65521
+ case '"':
65522
+ return "&quot;";
65523
+ case "'":
65524
+ return "&#39;";
65525
+ default:
65526
+ return char;
65527
+ }
65528
+ });
65529
+ }
65530
+ function inlineJson(value) {
65531
+ return JSON.stringify(value, null, 2).replace(/<\//g, "<\\/");
65532
+ }
65533
+ function generatePersonaDemoHtml(input) {
65534
+ const installerScriptUrl = input.installerScriptUrl ?? getPersonaInstallerScriptUrl();
65535
+ const pageData = {
65536
+ apiUrl: input.apiUrl,
65537
+ clientToken: input.clientToken,
65538
+ clientTokenId: input.clientTokenId,
65539
+ agentId: input.agentId,
65540
+ agentName: input.agentName,
65541
+ dashboardUrl: input.dashboardUrl,
65542
+ environment: input.environment,
65543
+ localUrl: input.localUrl,
65544
+ allowedOrigins: input.allowedOrigins
65545
+ };
65546
+ return `<!doctype html>
65547
+ <html lang="en">
65548
+ <head>
65549
+ <meta charset="utf-8" />
65550
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
65551
+ <title>Persona Local Playground</title>
65552
+ <style>
65553
+ :root {
65554
+ --paper: #fcfcfa;
65555
+ --paper-deep: #f4f0e8;
65556
+ --ink: #24211f;
65557
+ --muted: #67615b;
65558
+ --line: #d9d2c7;
65559
+ --line-strong: #201a16;
65560
+ --accent: #4c00ff;
65561
+ --accent-soft: color-mix(in srgb, var(--accent) 8%, var(--paper));
65562
+ --live: #b6ff00;
65563
+ --success: #178c4b;
65564
+ --radius: 6px;
65565
+ }
65566
+ * { box-sizing: border-box; }
65567
+ body {
65568
+ margin: 0;
65569
+ min-height: 100vh;
65570
+ color: var(--ink);
65571
+ font-family: Asap, Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
65572
+ background:
65573
+ linear-gradient(90deg, rgba(36, 33, 31, .045) 1px, transparent 1px) 0 0 / 40px 40px,
65574
+ linear-gradient(rgba(36, 33, 31, .04) 1px, transparent 1px) 0 0 / 40px 40px,
65575
+ radial-gradient(circle at 18% 0%, var(--accent-soft), transparent 30rem),
65576
+ var(--paper);
65577
+ }
65578
+ button { font: inherit; }
65579
+ .shell {
65580
+ width: min(920px, calc(100% - 32px));
65581
+ margin: 0 auto;
65582
+ padding: clamp(28px, 6vw, 64px) 0 112px;
65583
+ }
65584
+ .panel {
65585
+ border: 1px solid var(--line-strong);
65586
+ border-radius: var(--radius);
65587
+ background: color-mix(in srgb, var(--paper) 91%, white);
65588
+ box-shadow: 7px 7px 0 rgba(36, 33, 31, .12);
65589
+ padding: clamp(18px, 3vw, 28px);
65590
+ }
65591
+ .demo-grid {
65592
+ display: grid;
65593
+ grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
65594
+ gap: 18px;
65595
+ align-items: stretch;
65596
+ }
65597
+ .preview {
65598
+ min-height: 280px;
65599
+ display: grid;
65600
+ align-content: space-between;
65601
+ gap: 24px;
65602
+ border: 1px solid var(--line-strong);
65603
+ border-radius: var(--radius);
65604
+ padding: clamp(20px, 3vw, 28px);
65605
+ color: white;
65606
+ background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 86%, black), var(--accent));
65607
+ }
65608
+ .preview h2 {
65609
+ margin: 0;
65610
+ max-width: 560px;
65611
+ font-family: Newsreader, Georgia, "Times New Roman", serif;
65612
+ font-size: clamp(30px, 5vw, 54px);
65613
+ line-height: .96;
65614
+ letter-spacing: -0.04em;
65615
+ }
65616
+ .preview p { max-width: 560px; margin: 12px 0 0; opacity: .9; line-height: 1.6; }
65617
+ .status-pill {
65618
+ justify-self: start;
65619
+ border: 1px solid rgba(255,255,255,.75);
65620
+ border-radius: 999px;
65621
+ padding: 7px 10px;
65622
+ font-size: 12px;
65623
+ font-weight: 800;
65624
+ }
65625
+ .section-title {
65626
+ margin: 0 0 12px;
65627
+ color: var(--muted);
65628
+ font-size: 12px;
65629
+ font-weight: 800;
65630
+ letter-spacing: .12em;
65631
+ text-transform: uppercase;
65632
+ }
65633
+ .tasks { display: grid; gap: 9px; }
65634
+ .task {
65635
+ display: flex;
65636
+ align-items: center;
65637
+ gap: 10px;
65638
+ padding: 11px 12px;
65639
+ border: 1px solid var(--line);
65640
+ border-radius: var(--radius);
65641
+ background: var(--paper);
65642
+ }
65643
+ .task-dot {
65644
+ display: grid;
65645
+ place-items: center;
65646
+ width: 23px;
65647
+ height: 23px;
65648
+ border-radius: 999px;
65649
+ color: var(--paper);
65650
+ background: #9c958e;
65651
+ font-size: 13px;
65652
+ font-weight: 900;
65653
+ }
65654
+ .task[data-done="true"] .task-dot { background: var(--success); }
65655
+ .task[data-done="true"] .task-label { color: var(--muted); text-decoration: line-through; }
65656
+ .activity {
65657
+ margin-top: 18px;
65658
+ padding-top: 16px;
65659
+ border-top: 1px solid var(--line);
65660
+ }
65661
+ .log { display: grid; gap: 8px; max-height: 120px; overflow: auto; }
65662
+ .log-row {
65663
+ color: #4b463f;
65664
+ font-size: 12px;
65665
+ line-height: 1.45;
65666
+ }
65667
+ .log-row strong { color: var(--ink); }
65668
+ .action-bar {
65669
+ display: flex;
65670
+ flex-wrap: wrap;
65671
+ gap: 10px;
65672
+ align-items: center;
65673
+ margin-top: 18px;
65674
+ padding-top: 18px;
65675
+ border-top: 1px solid var(--line);
65676
+ }
65677
+ .cta {
65678
+ display: inline-flex;
65679
+ align-items: center;
65680
+ justify-content: center;
65681
+ gap: 8px;
65682
+ min-height: 42px;
65683
+ border: 1px solid var(--line-strong);
65684
+ border-radius: var(--radius);
65685
+ padding: 10px 13px;
65686
+ color: var(--ink);
65687
+ font-size: 14px;
65688
+ font-weight: 800;
65689
+ text-decoration: none;
65690
+ cursor: pointer;
65691
+ }
65692
+ .cta-primary { background: var(--accent); color: white; }
65693
+ .cta-secondary { background: var(--paper); }
65694
+ .cta-arrow { font-size: 18px; line-height: 1; }
65695
+ details {
65696
+ margin-top: 18px;
65697
+ color: var(--muted);
65698
+ font-size: 13px;
65699
+ }
65700
+ summary {
65701
+ cursor: pointer;
65702
+ width: fit-content;
65703
+ color: var(--ink);
65704
+ font-weight: 700;
65705
+ }
65706
+ .details-grid {
65707
+ display: grid;
65708
+ grid-template-columns: 90px minmax(0, 1fr);
65709
+ gap: 8px 14px;
65710
+ margin-top: 12px;
65711
+ }
65712
+ code {
65713
+ color: #2f2a26;
65714
+ word-break: break-word;
65715
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
65716
+ font-size: 12px;
65717
+ }
65718
+ @media (max-width: 820px) {
65719
+ .demo-grid { grid-template-columns: 1fr; }
65720
+ .shell { width: min(100% - 24px, 720px); }
65721
+ }
65722
+ @media (prefers-reduced-motion: reduce) {
65723
+ *, *::before, *::after { transition: none !important; }
65724
+ }
65725
+ </style>
65726
+ </head>
65727
+ <body>
65728
+ <!-- Edit this file directly, refresh the browser, and keep customizing your Persona starter. -->
65729
+ <main class="shell">
65730
+ <section class="panel" aria-label="Persona demo workspace">
65731
+ <div class="demo-grid">
65732
+ <div class="preview" id="accent-preview">
65733
+ <div>
65734
+ <h2 id="playground-headline">Local tools. Visible results.</h2>
65735
+ <p id="playground-note">Persona can read this page, request approval, and update the UI from the browser.</p>
65736
+ </div>
65737
+ <span class="status-pill" id="status-pill">Waiting for your first task</span>
65738
+ </div>
65739
+
65740
+ <div>
65741
+ <p class="section-title">Checklist</p>
65742
+ <div class="tasks" id="task-list"></div>
65743
+
65744
+ <div class="activity">
65745
+ <p class="section-title">Activity</p>
65746
+ <div class="log" id="tool-log"></div>
65747
+ </div>
65748
+ </div>
65749
+ </div>
65750
+
65751
+ <div class="action-bar" aria-label="Next actions">
65752
+ <button class="cta cta-primary" id="use-persona-widget" type="button">
65753
+ <span id="use-persona-label">Use Persona widget</span> <span class="cta-arrow" aria-hidden="true">\u2198</span>
65754
+ </button>
65755
+ <a class="cta cta-secondary" href="${escapeHtml(input.dashboardUrl)}" target="_blank" rel="noreferrer">Customize your agent</a>
65756
+ </div>
65757
+
65758
+ <details>
65759
+ <summary>Technical details</summary>
65760
+ <div class="details-grid">
65761
+ <span>Agent</span><code>${escapeHtml(input.agentId)}</code>
65762
+ <span>Token</span><code>${escapeHtml(input.clientTokenId)} (${escapeHtml(input.environment)})</code>
65763
+ <span>Edit</span><code>index.html</code>
65764
+ <span>Origin</span><code>${escapeHtml(input.localUrl)}</code>
65765
+ <span>Tools</span><code>${PERSONA_DEMO_TOOL_NAMES.join(", ")}</code>
65766
+ <span>Dashboard</span><code>${escapeHtml(input.dashboardUrl)}</code>
65767
+ </div>
65768
+ </details>
65769
+ </section>
65770
+ </main>
65771
+
65772
+ <div id="persona-root"></div>
65773
+
65774
+ <!-- 1. Runtime values injected by the CLI. -->
65775
+ <script>
65776
+ window.__RUNTYPE_PERSONA_DEMO__ = ${inlineJson(pageData)};
65777
+ </script>
65778
+ <!-- 2. Minimal WebMCP host bridge for this dependency-free page. -->
65779
+ <script>
65780
+ (function installMinimalModelContext() {
65781
+ if (document.modelContext && typeof document.modelContext.getTools === 'function') {
65782
+ return;
65783
+ }
65784
+ const tools = new Map();
65785
+ document.modelContext = {
65786
+ registerTool(tool) {
65787
+ if (!tool || !tool.name || typeof tool.execute !== 'function') {
65788
+ throw new Error('registerTool requires a name and execute function');
65789
+ }
65790
+ tools.set(tool.name, tool);
65791
+ },
65792
+ async getTools() {
65793
+ return Array.from(tools.values()).map((tool) => ({
65794
+ name: tool.name,
65795
+ title: tool.title || '',
65796
+ description: tool.description || '',
65797
+ inputSchema: JSON.stringify(tool.inputSchema || { type: 'object', properties: {} }),
65798
+ }));
65799
+ },
65800
+ async executeTool(info, inputArgsJson) {
65801
+ const name = typeof info === 'string' ? info : info && info.name;
65802
+ const tool = tools.get(name);
65803
+ if (!tool) throw new Error('Tool not registered: ' + name);
65804
+ const args = inputArgsJson ? JSON.parse(inputArgsJson) : {};
65805
+ const result = await tool.execute(args, {
65806
+ requestUserInteraction: async (callback) => callback(),
65807
+ });
65808
+ return result === undefined ? null : JSON.stringify(result);
65809
+ },
65810
+ };
65811
+ })();
65812
+
65813
+ const demo = window.__RUNTYPE_PERSONA_DEMO__;
65814
+ /* 3. Page state the tools can read and update. */
65815
+ const accentMap = {
65816
+ violet: '#4c00ff',
65817
+ green: '#178c4b',
65818
+ cyan: '#008ca8',
65819
+ orange: '#d95f02',
65820
+ };
65821
+ const state = {
65822
+ accent: 'violet',
65823
+ headline: 'Local tools. Visible results.',
65824
+ note: 'Persona can read this page, request approval, and update the UI from the browser.',
65825
+ status: 'Waiting for your first task',
65826
+ tasks: [
65827
+ { id: 'widget', label: 'Widget installed', done: true },
65828
+ { id: 'webmcp', label: 'WebMCP tools connected', done: true },
65829
+ { id: 'setup', label: 'Setup complete', done: false },
65830
+ ],
65831
+ };
65832
+
65833
+ function escapeText(value) {
65834
+ return String(value).replace(/[&<>]/g, (char) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' })[char]);
65835
+ }
65836
+
65837
+ function logTool(kind, message) {
65838
+ const log = document.getElementById('tool-log');
65839
+ const row = document.createElement('div');
65840
+ row.className = 'log-row';
65841
+ row.innerHTML = '<strong>' + escapeText(kind) + '</strong> \xB7 ' + escapeText(message);
65842
+ log.prepend(row);
65843
+ }
65844
+
65845
+ function snapshot() {
65846
+ return {
65847
+ accent: state.accent,
65848
+ accentHex: accentMap[state.accent],
65849
+ headline: state.headline,
65850
+ note: state.note,
65851
+ status: state.status,
65852
+ tasks: state.tasks,
65853
+ pageUrl: location.href,
65854
+ allowedOrigins: demo.allowedOrigins,
65855
+ };
65856
+ }
65857
+
65858
+ function render() {
65859
+ document.documentElement.style.setProperty('--accent', accentMap[state.accent]);
65860
+ document.getElementById('playground-headline').textContent = state.headline;
65861
+ document.getElementById('playground-note').textContent = state.note;
65862
+ document.getElementById('status-pill').textContent = state.status;
65863
+ const setupDone = state.tasks.some((task) => task.id === 'setup' && task.done);
65864
+ const ctaLabel = document.getElementById('use-persona-label');
65865
+ if (ctaLabel) ctaLabel.textContent = setupDone ? 'Try another page change' : 'Use Persona widget';
65866
+ const taskList = document.getElementById('task-list');
65867
+ taskList.innerHTML = '';
65868
+ for (const task of state.tasks) {
65869
+ const row = document.createElement('div');
65870
+ row.className = 'task';
65871
+ row.dataset.done = String(task.done);
65872
+ row.innerHTML = '<span class="task-dot">\u2713</span><span class="task-label"></span>';
65873
+ row.querySelector('.task-label').textContent = task.label;
65874
+ taskList.appendChild(row);
65875
+ }
65876
+ }
65877
+
65878
+ function taskLabel(id) {
65879
+ const task = state.tasks.find((item) => item.id === id);
65880
+ return task ? task.label : id;
65881
+ }
65882
+
65883
+ function buildAssistantMessage(args, changed) {
65884
+ if (!changed.length) return 'Done \u2014 no visible page changes were needed.';
65885
+
65886
+ const updates = [];
65887
+ if (args.accent && accentMap[args.accent]) updates.push('the page is now ' + args.accent);
65888
+ if (typeof args.headline === 'string' && args.headline.trim()) updates.push('the headline changed');
65889
+ if (typeof args.note === 'string' && args.note.trim()) updates.push('the note changed');
65890
+ if (typeof args.status === 'string' && args.status.trim()) updates.push('the status changed');
65891
+ if (Array.isArray(args.completedTaskIds) && args.completedTaskIds.length) {
65892
+ const labels = args.completedTaskIds.map((id) => taskLabel(id));
65893
+ updates.push(
65894
+ labels.length === 1 ? labels[0] + ' is checked' : labels.join(', ') + ' are checked'
65895
+ );
65896
+ }
65897
+
65898
+ return 'Done \u2014 ' + updates.join(' and ') + '.';
65899
+ }
65900
+
65901
+ function buildSuggestedReplies() {
65902
+ return [
65903
+ 'Change the headline',
65904
+ 'Add another page tool',
65905
+ 'Show the embed code',
65906
+ 'Customize the agent',
65907
+ ];
65908
+ }
65909
+
65910
+ /* 4. WebMCP tools exposed to the Persona widget. */
65911
+ document.modelContext.registerTool({
65912
+ name: 'get_playground_state',
65913
+ title: 'Read playground state',
65914
+ description: 'Read the current local Persona playground state: accent, headline, note, status, checklist, URL, and allowed origins. Use this before proposing page changes.',
65915
+ inputSchema: { type: 'object', properties: {} },
65916
+ annotations: { readOnlyHint: true },
65917
+ async execute() {
65918
+ logTool('Read page state', 'Persona inspected the local HTML page');
65919
+ return snapshot();
65920
+ },
65921
+ });
65922
+
65923
+ document.modelContext.registerTool({
65924
+ name: 'update_playground',
65925
+ title: 'Update playground UI',
65926
+ description: 'Update this local HTML playground. Can set accent to violet, green, cyan, or orange; rewrite the headline or note; set a short status; and mark checklist tasks complete by id.',
65927
+ inputSchema: {
65928
+ type: 'object',
65929
+ properties: {
65930
+ accent: { type: 'string', enum: Object.keys(accentMap), description: 'Accent color to apply.' },
65931
+ headline: { type: 'string', description: 'New hero headline.' },
65932
+ note: { type: 'string', description: 'New explanatory note under the headline.' },
65933
+ status: { type: 'string', description: 'Short status shown inside the demo card.' },
65934
+ completedTaskIds: {
65935
+ type: 'array',
65936
+ items: { type: 'string', enum: state.tasks.map((task) => task.id) },
65937
+ description: 'Checklist task ids to mark complete.',
65938
+ },
65939
+ },
65940
+ },
65941
+ async execute(args) {
65942
+ const changed = [];
65943
+ if (args.accent && accentMap[args.accent]) {
65944
+ state.accent = args.accent;
65945
+ changed.push('accent');
65946
+ }
65947
+ if (typeof args.headline === 'string' && args.headline.trim()) {
65948
+ state.headline = args.headline.trim();
65949
+ changed.push('headline');
65950
+ }
65951
+ if (typeof args.note === 'string' && args.note.trim()) {
65952
+ state.note = args.note.trim();
65953
+ changed.push('note');
65954
+ }
65955
+ if (typeof args.status === 'string' && args.status.trim()) {
65956
+ state.status = args.status.trim();
65957
+ changed.push('status');
65958
+ }
65959
+ if (Array.isArray(args.completedTaskIds) && args.completedTaskIds.length) {
65960
+ const completed = new Set(args.completedTaskIds);
65961
+ state.tasks = state.tasks.map((task) => completed.has(task.id) ? { ...task, done: true } : task);
65962
+ changed.push('checklist');
65963
+ }
65964
+ render();
65965
+ logTool('Updated page', changed.length ? changed.join(' + ') : 'No visible changes requested');
65966
+ return {
65967
+ ok: true,
65968
+ changed,
65969
+ responseGuidance: {
65970
+ assistantMessage: buildAssistantMessage(args, changed),
65971
+ suggestedReplies: buildSuggestedReplies(),
65972
+ instructions: 'Do not send a visible assistant message yet. First call suggest_replies with suggestedReplies. After suggest_replies returns, say assistantMessage exactly once, then stop.',
65973
+ },
65974
+ state: snapshot(),
65975
+ };
65976
+ },
65977
+ });
65978
+
65979
+ /* 5. Persona widget config. The installer below reads window.siteAgentConfig. */
65980
+ window.siteAgentConfig = {
65981
+ target: '#persona-root',
65982
+ windowKey: 'personaPlayground',
65983
+ config: {
65984
+ apiUrl: demo.apiUrl,
65985
+ clientToken: demo.clientToken,
65986
+ parserType: 'json',
65987
+ launcher: {
65988
+ enabled: true,
65989
+ autoExpand: true,
65990
+ title: 'Persona Playground',
65991
+ subtitle: 'Local WebMCP demo',
65992
+ width: '430px',
65993
+ },
65994
+ copy: {
65995
+ welcomeTitle: 'Persona Playground',
65996
+ welcomeSubtitle: 'Use the page tools, then pick a next step.',
65997
+ inputPlaceholder: 'Ask Persona to update this page\u2026',
65998
+ },
65999
+ suggestionChips: [
66000
+ 'Turn this page green and mark Setup complete.',
66001
+ 'What page tools are available?',
66002
+ 'Show the embed code.',
66003
+ ],
66004
+ features: {
66005
+ showToolCalls: true,
66006
+ showEventStreamToggle: true,
66007
+ suggestReplies: {
66008
+ enabled: true,
66009
+ expose: true,
66010
+ },
66011
+ },
66012
+ webmcp: {
66013
+ enabled: true,
66014
+ autoApprove(info) {
66015
+ const ok = info && info.toolName === 'get_playground_state';
66016
+ logTool('Approval gate', (info ? info.toolName : 'unknown') + (ok ? ' auto-approved' : ' awaiting approval'));
66017
+ return ok;
66018
+ },
66019
+ },
66020
+ },
66021
+ onChatReady(handle) {
66022
+ window.personaPlayground = handle;
66023
+ logTool('Widget ready', 'Persona handle is available at window.personaPlayground');
66024
+ setTimeout(() => {
66025
+ if (handle && typeof handle.open === 'function') handle.open();
66026
+ }, 0);
66027
+ },
66028
+ onError(info) {
66029
+ logTool('Persona error', info && info.phase ? info.phase : 'unknown phase');
66030
+ },
66031
+ };
66032
+
66033
+ document.getElementById('use-persona-widget').addEventListener('click', () => {
66034
+ const handle = window.personaPlayground;
66035
+ if (handle && typeof handle.open === 'function') handle.open();
66036
+ if (handle && typeof handle.setMessage === 'function') {
66037
+ handle.setMessage('Turn this page green and mark Setup complete.');
66038
+ }
66039
+ logTool('CTA', 'Opened Persona widget');
66040
+ });
66041
+
66042
+ render();
66043
+ logTool('Tools connected', 'Registered get_playground_state and update_playground');
66044
+ </script>
66045
+ <!-- 6. Version-pinned Persona installer from @runtypelabs/persona. -->
66046
+ <script src="${escapeHtml(installerScriptUrl)}"></script>
66047
+ </body>
66048
+ </html>`;
66049
+ }
66050
+ function generatePersonaDemoReadme(input) {
66051
+ const port = (() => {
66052
+ try {
66053
+ return new URL(input.localUrl).port || String(PERSONA_DEMO_DEFAULT_PORT);
66054
+ } catch {
66055
+ return String(PERSONA_DEMO_DEFAULT_PORT);
66056
+ }
66057
+ })();
66058
+ return `# Persona Playground
66059
+
66060
+ This folder was generated by \`runtype persona init\`.
66061
+
66062
+ ## Next steps
66063
+
66064
+ 1. Use the widget: ${input.localUrl}
66065
+ 2. Customize your agent: ${input.dashboardUrl}
66066
+ 3. Edit the page: ./index.html
66067
+
66068
+ ## Run locally
66069
+
66070
+ \`\`\`bash
66071
+ python3 -m http.server ${port} --bind 127.0.0.1
66072
+ \`\`\`
66073
+
66074
+ Then open ${input.localUrl}.
66075
+
66076
+ ## What this starter demonstrates
66077
+
66078
+ - \`window.siteAgentConfig\` installs Persona with your client token.
66079
+ - \`document.modelContext\` exposes two local WebMCP tools:
66080
+ - \`get_playground_state\` reads the page state.
66081
+ - \`update_playground\` changes the accent, copy, status, and checklist after approval.
66082
+ - Persona native suggested replies render next-step pills after a successful tool call.
66083
+
66084
+ ## Add another page tool
66085
+
66086
+ 1. Add a new \`document.modelContext.registerTool({ ... })\` block in \`index.html\`.
66087
+ 2. Add the tool name to the WebMCP allowlist for this surface in the Runtype dashboard.
66088
+ 3. Refresh the page and ask Persona to use the new tool.
66089
+
66090
+ ## Demo resources
66091
+
66092
+ - Agent: ${input.agentId}
66093
+ - Client token: ${input.clientTokenId} (${input.environment})
66094
+ - Allowed origins: ${input.allowedOrigins.join(", ")}
66095
+ `;
66096
+ }
66097
+
65311
66098
  // src/commands/persona.ts
65312
- var FORMAT_CYCLE = [
65313
- "script-installer",
65314
- "react",
65315
- "script-manual",
65316
- "esm"
65317
- ];
66099
+ var FORMAT_CYCLE = ["script-installer", "react", "script-manual", "esm"];
65318
66100
  function defaultTokenName(agentName) {
65319
66101
  return `${agentName} Widget`;
65320
66102
  }
66103
+ function parsePort(raw, fallback) {
66104
+ if (!raw) return fallback;
66105
+ const port = Number(raw);
66106
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
66107
+ throw new Error(`Invalid port "${raw}". Use a number between 1 and 65535.`);
66108
+ }
66109
+ return port;
66110
+ }
65321
66111
  async function promptLine(rl, question, defaultValue) {
65322
66112
  const hint = defaultValue ? chalk30.dim(` (${defaultValue})`) : "";
65323
66113
  const answer = await new Promise((resolve11) => {
@@ -65366,7 +66156,16 @@ function snippetWithFormat(format, token, apiUrl, targetSelector) {
65366
66156
  );
65367
66157
  return { format, code };
65368
66158
  }
65369
- async function runSuccessKeyLoop(initial, apiUrl, targetSelector) {
66159
+ function printDemoNextSteps(demo, dashboardUrl) {
66160
+ console.log(chalk30.cyan("\nNext steps:"));
66161
+ console.log(` 1. Use the widget: ${chalk30.green(demo.url)}`);
66162
+ console.log(` 2. Customize your agent: ${dashboardUrl}`);
66163
+ console.log(` 3. Edit the page: ${demo.filePath}`);
66164
+ if (demo.readmePath) {
66165
+ console.log(chalk30.dim(` Guide: ${demo.readmePath}`));
66166
+ }
66167
+ }
66168
+ async function runSuccessKeyLoop(initial, apiUrl, targetSelector, demo) {
65370
66169
  if (!process.stdin.isTTY) {
65371
66170
  return;
65372
66171
  }
@@ -65380,39 +66179,48 @@ async function runSuccessKeyLoop(initial, apiUrl, targetSelector) {
65380
66179
  console.log(`${chalk30.bold("Snippet format:")} ${currentFormat}`);
65381
66180
  console.log(chalk30.dim(`
65382
66181
  Dashboard: ${initial.dashboardUrl}`));
66182
+ if (demo) {
66183
+ console.log(`${chalk30.bold("Local demo:")} ${chalk30.green(demo.url)}`);
66184
+ console.log(chalk30.dim(`HTML: ${demo.filePath}`));
66185
+ if (demo.readmePath) {
66186
+ console.log(chalk30.dim(`Guide: ${demo.readmePath}`));
66187
+ }
66188
+ }
65383
66189
  if (initial.warnings?.length) {
65384
66190
  for (const w of initial.warnings) {
65385
66191
  console.log(chalk30.yellow(`\u26A0 ${w.message}`));
65386
66192
  }
65387
66193
  }
65388
- console.log(chalk30.cyan("\nKeys:"));
66194
+ if (demo) {
66195
+ printDemoNextSteps(demo, initial.dashboardUrl);
66196
+ }
66197
+ console.log(chalk30.cyan("\nActions:"));
65389
66198
  console.log(` ${chalk30.green("c")} Copy snippet to clipboard`);
65390
66199
  console.log(` ${chalk30.green("p")} Print snippet to the terminal`);
65391
66200
  console.log(` ${chalk30.green("f")} Switch snippet format`);
65392
66201
  console.log(` ${chalk30.green("o")} Open dashboard in browser`);
65393
- console.log(` ${chalk30.green("q")} Quit`);
65394
- readline3.emitKeypressEvents(process.stdin);
65395
- if (process.stdin.isTTY) {
65396
- process.stdin.setRawMode(true);
66202
+ if (demo) {
66203
+ console.log(` ${chalk30.green("d")} Open local demo in browser`);
65397
66204
  }
65398
- process.stdin.resume();
65399
- const cleanup = () => {
65400
- process.stdin.setRawMode(false);
65401
- process.stdin.removeAllListeners("keypress");
65402
- process.stdin.pause();
65403
- };
66205
+ console.log(` ${chalk30.green("q")} Quit`);
66206
+ console.log(chalk30.dim("\nType a letter and press Enter. Press Ctrl+C to quit."));
66207
+ const actionKeys = demo ? "c/p/f/o/d/q" : "c/p/f/o/q";
66208
+ const rl = readline3.createInterface({
66209
+ input: process.stdin,
66210
+ output: process.stdout,
66211
+ terminal: true
66212
+ });
65404
66213
  await new Promise((resolve11) => {
65405
- const onKeypress = async (_str, key) => {
65406
- if (!key) return;
65407
- if (key.ctrl && key.name === "c") {
65408
- cleanup();
65409
- resolve11();
65410
- process.exit(0);
65411
- }
65412
- const name = key.name;
65413
- if (name === "q" || name === "escape") {
65414
- cleanup();
65415
- resolve11();
66214
+ let finished = false;
66215
+ const finish = () => {
66216
+ if (finished) return;
66217
+ finished = true;
66218
+ rl.close();
66219
+ resolve11();
66220
+ };
66221
+ const runAction = async (name) => {
66222
+ if (name === "q") {
66223
+ finish();
65416
66224
  return;
65417
66225
  }
65418
66226
  if (name === "c") {
@@ -65441,23 +66249,61 @@ Dashboard: ${initial.dashboardUrl}`));
65441
66249
  }
65442
66250
  if (name === "o") {
65443
66251
  try {
65444
- await open5(initial.dashboardUrl);
66252
+ await openBrowser(initial.dashboardUrl);
66253
+ } catch {
66254
+ console.log(chalk30.red("Could not open browser."));
66255
+ }
66256
+ return;
66257
+ }
66258
+ if (name === "d" && demo) {
66259
+ try {
66260
+ await openBrowser(demo.url);
65445
66261
  } catch {
65446
66262
  console.log(chalk30.red("Could not open browser."));
65447
66263
  }
66264
+ return;
65448
66265
  }
66266
+ console.log(chalk30.yellow(`Choose one of: ${actionKeys}`));
66267
+ };
66268
+ const ask = () => {
66269
+ if (finished) return;
66270
+ rl.question(chalk30.dim(`
66271
+ Choose an action (${actionKeys}): `), (answer) => {
66272
+ const names = answer.trim().toLowerCase().split(/[\s,]+/).filter(Boolean).map((part) => part.charAt(0));
66273
+ void (async () => {
66274
+ for (const name of names) {
66275
+ await runAction(name);
66276
+ if (finished) {
66277
+ return;
66278
+ }
66279
+ }
66280
+ if (!finished) {
66281
+ ask();
66282
+ }
66283
+ })();
66284
+ });
65449
66285
  };
65450
- process.stdin.on("keypress", onKeypress);
66286
+ rl.on("SIGINT", finish);
66287
+ ask();
65451
66288
  });
65452
66289
  }
65453
66290
  var personaCommand = new Command23("persona").description(
65454
66291
  "Set up Persona: create an agent, client token, and embed snippet"
65455
66292
  );
65456
- personaCommand.command("init").description("Create agent + client token and output a Persona embed snippet").option("--agent-name <name>", "Name for the new agent").option("--agent-description <text", "Optional agent description").option("--token-name <name>", "Name for the new client token").option("--environment <env>", "Token environment: test or live", "test").option("--origins <origins...>", "Allowed origins (default: * \u2014 broad; prefer explicit URLs in production)").option(
66293
+ personaCommand.command("init").description("Create agent + client token and output a Persona embed snippet").option("--agent-name <name>", "Name for the new agent").option("--agent-description <text", "Optional agent description").option("--token-name <name>", "Name for the new client token").option("--environment <env>", "Token environment: test or live", "test").option(
66294
+ "--origins <origins...>",
66295
+ "Allowed origins (default: * \u2014 broad; prefer explicit URLs in production)"
66296
+ ).option(
65457
66297
  "--format <fmt>",
65458
66298
  "Snippet format: script-installer | script-manual | esm | react",
65459
66299
  "script-installer"
65460
- ).option("--print-snippet", "Print the generated snippet to stdout (non-interactive summary mode)").option("--target-selector <selector>", "CSS selector for widget mount target (omit to use body)").option("--api-url <url>", "Override API base URL").option("--json", "Structured JSON output (includes snippet body)").option("--yes", "Accept defaults in interactive prompts where sensible").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
66300
+ ).option("--print-snippet", "Print the generated snippet to stdout (non-interactive summary mode)").option("--target-selector <selector>", "CSS selector for widget mount target (omit to use body)").option("--demo", "Create a dependency-free local Persona Playground HTML demo").option("--no-demo", "Skip the local Persona Playground demo").option(
66301
+ "--demo-dir <path>",
66302
+ `Directory for the local demo (default: ${PERSONA_DEMO_DEFAULT_DIR})`
66303
+ ).option(
66304
+ "--demo-port <port>",
66305
+ `Preferred localhost port for the local demo (default: ${PERSONA_DEMO_DEFAULT_PORT})`
66306
+ ).option("--open", "Open the local demo in a browser when demo mode is enabled").option("--no-open", "Do not open the local demo automatically").option("--force", "Overwrite existing demo files").option("--api-url <url>", "Override API base URL").option("--json", "Structured JSON output (includes snippet body)").option("--yes", "Accept defaults in interactive prompts where sensible").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
65461
66307
  async (options, cmd) => {
65462
66308
  const globals = cmd.optsWithGlobals();
65463
66309
  const jsonMode = !!(options.json ?? globals.json);
@@ -65468,7 +66314,9 @@ personaCommand.command("init").description("Create agent + client token and outp
65468
66314
  } catch (e) {
65469
66315
  const msg = e instanceof Error ? e.message : String(e);
65470
66316
  if (jsonMode) {
65471
- console.log(JSON.stringify({ status: "error", error: msg, code: "INVALID_FORMAT" }, null, 2));
66317
+ console.log(
66318
+ JSON.stringify({ status: "error", error: msg, code: "INVALID_FORMAT" }, null, 2)
66319
+ );
65472
66320
  } else {
65473
66321
  console.error(chalk30.red(msg));
65474
66322
  }
@@ -65476,6 +66324,20 @@ personaCommand.command("init").description("Create agent + client token and outp
65476
66324
  }
65477
66325
  const apiUrl = options.apiUrl || globals.apiUrl || getApiUrl();
65478
66326
  const targetSelector = options.targetSelector || void 0;
66327
+ let preferredDemoPort;
66328
+ try {
66329
+ preferredDemoPort = parsePort(options.demoPort, PERSONA_DEMO_DEFAULT_PORT);
66330
+ } catch (e) {
66331
+ const msg = e instanceof Error ? e.message : String(e);
66332
+ if (jsonMode) {
66333
+ console.log(
66334
+ JSON.stringify({ status: "error", error: msg, code: "INVALID_DEMO_PORT" }, null, 2)
66335
+ );
66336
+ } else {
66337
+ console.error(chalk30.red(msg));
66338
+ }
66339
+ process.exit(1);
66340
+ }
65479
66341
  let env;
65480
66342
  if (options.environment === "test" || options.environment === "live") {
65481
66343
  env = options.environment;
@@ -65493,12 +66355,20 @@ personaCommand.command("init").description("Create agent + client token and outp
65493
66355
  let tokenName = options.tokenName?.trim();
65494
66356
  let allowedOrigins = options.origins;
65495
66357
  let chosenEnv = env;
66358
+ let demoRequested = options.demo === true;
66359
+ let demoDirectory;
66360
+ let demoPort;
66361
+ let demoOrigins;
66362
+ let demoLocalUrl;
66363
+ let forceDemoWrite = !!options.force;
65496
66364
  const rl = interactive && process.stdin.isTTY && process.stdout.isTTY ? readline3.createInterface({ input: process.stdin, output: process.stdout }) : null;
65497
66365
  if (!interactive) {
65498
66366
  if (!agentName) {
65499
66367
  const msg = "Non-interactive mode requires --agent-name";
65500
66368
  if (jsonMode) {
65501
- console.log(JSON.stringify({ status: "error", error: msg, code: "MISSING_AGENT_NAME" }, null, 2));
66369
+ console.log(
66370
+ JSON.stringify({ status: "error", error: msg, code: "MISSING_AGENT_NAME" }, null, 2)
66371
+ );
65502
66372
  } else {
65503
66373
  console.error(chalk30.red(msg));
65504
66374
  }
@@ -65525,20 +66395,52 @@ personaCommand.command("init").description("Create agent + client token and outp
65525
66395
  tokenName = def;
65526
66396
  }
65527
66397
  }
66398
+ if (options.demo === void 0 && !options.yes) {
66399
+ demoRequested = await promptConfirm2(
66400
+ rl,
66401
+ "Create and open a local Persona Playground HTML demo?",
66402
+ true
66403
+ );
66404
+ } else if (options.demo === void 0 && options.yes) {
66405
+ demoRequested = true;
66406
+ }
66407
+ if (demoRequested) {
66408
+ demoDirectory = resolvePersonaDemoDirectory(options.demoDir);
66409
+ try {
66410
+ ensurePersonaDemoCanWrite(demoDirectory, forceDemoWrite);
66411
+ } catch (e) {
66412
+ const message = e instanceof Error ? e.message : String(e);
66413
+ const ok = await promptConfirm2(rl, `${message} Overwrite it?`, false);
66414
+ if (!ok) {
66415
+ console.log(chalk30.gray("Aborted."));
66416
+ rl.close();
66417
+ process.exit(0);
66418
+ }
66419
+ forceDemoWrite = true;
66420
+ }
66421
+ demoPort = await findAvailablePersonaDemoPort(preferredDemoPort);
66422
+ demoOrigins = buildPersonaDemoOrigins(demoPort);
66423
+ demoLocalUrl = `http://127.0.0.1:${demoPort}/`;
66424
+ }
65528
66425
  if (!allowedOrigins?.length) {
66426
+ const defaultOrigins = demoOrigins?.join(" ") ?? "*";
65529
66427
  if (options.yes) {
65530
- allowedOrigins = ["*"];
66428
+ allowedOrigins = demoOrigins ?? ["*"];
65531
66429
  } else {
65532
66430
  const originsInput = await promptLine(
65533
66431
  rl,
65534
66432
  "Allowed origins (space-separated URLs, or * for any)",
65535
- "*"
66433
+ defaultOrigins
65536
66434
  );
65537
66435
  allowedOrigins = originsInput === "*" ? ["*"] : originsInput.split(/\s+/).filter(Boolean);
65538
66436
  }
65539
66437
  }
65540
66438
  if (chosenEnv === "live") {
65541
- const ok = await promptConfirm2(rl, chalk30.yellow("Create a LIVE token? This is shown only once."), false);
66439
+ const ok = await promptConfirm2(
66440
+ rl,
66441
+ chalk30.yellow("Create a LIVE token? This is shown only once."),
66442
+ false
66443
+ );
65542
66444
  if (!ok) {
65543
66445
  console.log(chalk30.gray("Aborted."));
65544
66446
  rl.close();
@@ -65556,6 +66458,28 @@ personaCommand.command("init").description("Create agent + client token and outp
65556
66458
  }
65557
66459
  }
65558
66460
  }
66461
+ if (demoRequested && !demoDirectory) {
66462
+ demoDirectory = resolvePersonaDemoDirectory(options.demoDir);
66463
+ try {
66464
+ ensurePersonaDemoCanWrite(demoDirectory, forceDemoWrite);
66465
+ } catch (e) {
66466
+ const message = e instanceof Error ? e.message : String(e);
66467
+ if (jsonMode) {
66468
+ console.log(
66469
+ JSON.stringify({ status: "error", error: message, code: "DEMO_EXISTS" }, null, 2)
66470
+ );
66471
+ } else {
66472
+ console.error(chalk30.red(message));
66473
+ }
66474
+ process.exit(1);
66475
+ }
66476
+ demoPort = await findAvailablePersonaDemoPort(preferredDemoPort);
66477
+ demoOrigins = buildPersonaDemoOrigins(demoPort);
66478
+ demoLocalUrl = `http://127.0.0.1:${demoPort}/`;
66479
+ }
66480
+ if (demoRequested && demoOrigins) {
66481
+ allowedOrigins = mergePersonaDemoAllowedOrigins(allowedOrigins, demoOrigins);
66482
+ }
65559
66483
  if (rl) {
65560
66484
  rl.close();
65561
66485
  }
@@ -65607,45 +66531,155 @@ personaCommand.command("init").description("Create agent + client token and outp
65607
66531
  environment: chosenEnv,
65608
66532
  allowedOrigins,
65609
66533
  format: formatCli,
65610
- targetSelector
66534
+ targetSelector,
66535
+ ...demoRequested && demoOrigins ? { demo: { origins: demoOrigins, toolNames: [...PERSONA_DEMO_TOOL_NAMES] } } : {}
65611
66536
  });
65612
66537
  } catch (err) {
65613
66538
  const message = err instanceof Error ? err.message : String(err);
65614
66539
  if (jsonMode) {
65615
- console.log(JSON.stringify({ status: "error", error: message, code: "API_ERROR" }, null, 2));
66540
+ console.log(
66541
+ JSON.stringify({ status: "error", error: message, code: "API_ERROR" }, null, 2)
66542
+ );
65616
66543
  } else {
65617
66544
  console.error(chalk30.red("Persona init failed"));
65618
66545
  console.error(chalk30.red(message));
65619
66546
  }
65620
66547
  process.exit(1);
65621
66548
  }
66549
+ let demoOutput;
66550
+ let demoServer;
66551
+ if (demoRequested && demoDirectory && demoPort && demoOrigins && demoLocalUrl) {
66552
+ const html = generatePersonaDemoHtml({
66553
+ apiUrl,
66554
+ clientToken: success2.clientToken.token,
66555
+ clientTokenId: success2.clientToken.id,
66556
+ agentId: success2.agent.id,
66557
+ agentName: success2.agent.name,
66558
+ dashboardUrl: success2.dashboardUrl,
66559
+ environment: success2.clientToken.environment,
66560
+ localUrl: demoLocalUrl,
66561
+ allowedOrigins: demoOrigins
66562
+ });
66563
+ const readme2 = generatePersonaDemoReadme({
66564
+ apiUrl,
66565
+ clientToken: success2.clientToken.token,
66566
+ clientTokenId: success2.clientToken.id,
66567
+ agentId: success2.agent.id,
66568
+ agentName: success2.agent.name,
66569
+ dashboardUrl: success2.dashboardUrl,
66570
+ environment: success2.clientToken.environment,
66571
+ localUrl: demoLocalUrl,
66572
+ allowedOrigins: demoOrigins
66573
+ });
66574
+ const writeResult = writePersonaDemoPage({
66575
+ directory: demoDirectory,
66576
+ html,
66577
+ readme: readme2,
66578
+ force: forceDemoWrite
66579
+ });
66580
+ demoOutput = {
66581
+ ...writeResult,
66582
+ localUrl: demoLocalUrl,
66583
+ port: demoPort,
66584
+ allowedOrigins: demoOrigins,
66585
+ serverRunning: false
66586
+ };
66587
+ const shouldLaunchDemo = !jsonMode && options.open !== false && (interactive || options.open === true);
66588
+ if (shouldLaunchDemo) {
66589
+ try {
66590
+ demoServer = await startPersonaDemoServer({
66591
+ directory: demoDirectory,
66592
+ port: demoPort
66593
+ });
66594
+ demoOutput.serverRunning = true;
66595
+ demoOutput.localUrl = demoServer.url;
66596
+ await openBrowser(demoServer.url);
66597
+ } catch (e) {
66598
+ demoOutput.serverError = e instanceof Error ? e.message : String(e);
66599
+ if (!jsonMode) {
66600
+ console.log(
66601
+ chalk30.yellow(`Could not start/open local demo server: ${demoOutput.serverError}`)
66602
+ );
66603
+ }
66604
+ }
66605
+ }
66606
+ }
66607
+ const output = demoOutput ? {
66608
+ ...success2,
66609
+ demo: {
66610
+ ...success2.demo,
66611
+ ...demoOutput
66612
+ }
66613
+ } : success2;
65622
66614
  if (jsonMode) {
65623
- printJson(success2);
66615
+ printJson(output);
65624
66616
  return;
65625
66617
  }
65626
66618
  if (!tty || options.printSnippet) {
65627
66619
  console.log(chalk30.green("\nPersona setup complete\n"));
65628
- console.log(`${chalk30.bold("Agent ID:")} ${success2.agent.id}`);
65629
- console.log(`${chalk30.bold("Client Token ID:")} ${success2.clientToken.id}`);
65630
- console.log(`${chalk30.bold("Client Token:")} ${chalk30.yellow(success2.clientToken.token)}`);
65631
- console.log(`${chalk30.bold("Format:")} ${success2.snippet.format}`);
66620
+ console.log(`${chalk30.bold("Agent ID:")} ${output.agent.id}`);
66621
+ console.log(`${chalk30.bold("Client Token ID:")} ${output.clientToken.id}`);
66622
+ console.log(`${chalk30.bold("Client Token:")} ${chalk30.yellow(output.clientToken.token)}`);
66623
+ console.log(`${chalk30.bold("Format:")} ${output.snippet.format}`);
65632
66624
  console.log(chalk30.dim(`
65633
- Dashboard: ${success2.dashboardUrl}`));
66625
+ Dashboard: ${output.dashboardUrl}`));
66626
+ if (demoOutput) {
66627
+ console.log(`${chalk30.bold("Demo HTML:")} ${demoOutput.filePath}`);
66628
+ console.log(`${chalk30.bold("Demo README:")} ${demoOutput.readmePath}`);
66629
+ console.log(`${chalk30.bold("Demo URL:")} ${chalk30.green(demoOutput.localUrl)}`);
66630
+ if (demoOutput.serverRunning) {
66631
+ console.log(chalk30.dim("Local demo server is running. Press Ctrl+C to stop it."));
66632
+ } else {
66633
+ console.log(
66634
+ chalk30.dim(
66635
+ `Run: cd ${demoOutput.directory} && python3 -m http.server ${demoOutput.port} --bind 127.0.0.1`
66636
+ )
66637
+ );
66638
+ }
66639
+ printDemoNextSteps(
66640
+ {
66641
+ url: demoOutput.localUrl,
66642
+ filePath: demoOutput.filePath,
66643
+ readmePath: demoOutput.readmePath
66644
+ },
66645
+ output.dashboardUrl
66646
+ );
66647
+ }
65634
66648
  if (success2.warnings?.length) {
65635
66649
  for (const w of success2.warnings) {
65636
66650
  console.log(chalk30.yellow(`\u26A0 ${w.message}`));
65637
66651
  }
65638
66652
  }
65639
- console.log(chalk30.cyan("\nRecommended next step: npm install @runtypelabs/persona"));
66653
+ if (!demoOutput) {
66654
+ console.log(chalk30.cyan("\nRecommended next step: npm install @runtypelabs/persona"));
66655
+ }
65640
66656
  if (options.printSnippet) {
65641
66657
  console.log(chalk30.cyan("\n--- snippet ---\n"));
65642
66658
  console.log(success2.snippet.code);
65643
66659
  } else {
65644
- console.log(chalk30.dim("\nUse --print-snippet to print the embed code, or run interactively for copy shortcuts."));
66660
+ console.log(
66661
+ chalk30.dim(
66662
+ "\nUse --print-snippet to print the embed code, or run interactively for copy shortcuts."
66663
+ )
66664
+ );
65645
66665
  }
65646
66666
  return;
65647
66667
  }
65648
- await runSuccessKeyLoop(success2, apiUrl, targetSelector);
66668
+ try {
66669
+ await runSuccessKeyLoop(
66670
+ success2,
66671
+ apiUrl,
66672
+ targetSelector,
66673
+ demoOutput ? {
66674
+ url: demoOutput.localUrl,
66675
+ filePath: demoOutput.filePath,
66676
+ readmePath: demoOutput.readmePath
66677
+ } : void 0
66678
+ );
66679
+ } finally {
66680
+ await demoServer?.close().catch(() => {
66681
+ });
66682
+ }
65649
66683
  }
65650
66684
  );
65651
66685
 
@@ -65817,7 +66851,7 @@ import chalk32 from "chalk";
65817
66851
  import React23 from "react";
65818
66852
  import { render as render23 } from "ink";
65819
66853
  import { useState as useState40, useEffect as useEffect34 } from "react";
65820
- import open6 from "open";
66854
+ import open5 from "open";
65821
66855
  var billingCommand = new Command25("billing").description("View billing and subscription info");
65822
66856
  billingCommand.command("status").description("Show current plan and usage").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
65823
66857
  const apiKey = await ensureAuth();
@@ -65920,7 +66954,7 @@ billingCommand.command("portal").description("Open the billing portal in your br
65920
66954
  if (data.url) {
65921
66955
  console.log("Opening billing portal...");
65922
66956
  console.log(data.url);
65923
- await open6(data.url);
66957
+ await open5(data.url);
65924
66958
  } else {
65925
66959
  console.log("No portal URL returned. You may need to set up billing first.");
65926
66960
  }
@@ -65942,7 +66976,7 @@ billingCommand.command("portal").description("Open the billing portal in your br
65942
66976
  try {
65943
66977
  const data = await client.post("/billing/portal");
65944
66978
  if (data.url) {
65945
- await open6(data.url);
66979
+ await open5(data.url);
65946
66980
  setMsg("Billing portal opened in browser");
65947
66981
  setSuccess(true);
65948
66982
  } else {
@@ -66792,7 +67826,7 @@ var tailCommand = new Command28("tail").description("Stream live execution logs
66792
67826
  // src/commands/validate-product.ts
66793
67827
  import { Command as Command29, Option } from "commander";
66794
67828
  import chalk36 from "chalk";
66795
- import { readFileSync as readFileSync17 } from "fs";
67829
+ import { readFileSync as readFileSync18 } from "fs";
66796
67830
  function createValidateProductCommand() {
66797
67831
  return new Command29("validate-product").description("Validate a product (FPO) or FPO template locally (no API call)").argument(
66798
67832
  "[input]",
@@ -66872,7 +67906,7 @@ async function readInput(input) {
66872
67906
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
66873
67907
  return trimmed;
66874
67908
  }
66875
- return readFileSync17(input, "utf-8");
67909
+ return readFileSync18(input, "utf-8");
66876
67910
  }
66877
67911
  async function readStdin() {
66878
67912
  if (process.stdin.isTTY) {
@@ -66975,7 +68009,7 @@ function printIssues(title, issues, color) {
66975
68009
  import { Command as Command30 } from "commander";
66976
68010
  import chalk37 from "chalk";
66977
68011
  import * as fs16 from "fs";
66978
- import * as path16 from "path";
68012
+ import * as path17 from "path";
66979
68013
  import { RuntypeApiError as RuntypeApiError4 } from "@runtypelabs/sdk";
66980
68014
  function bashSingleQuote(s) {
66981
68015
  return "'" + s.replace(/'/g, "'\\''") + "'";
@@ -67945,8 +68979,8 @@ var deployCommand = new Command30("deploy").description("Export an agent or flow
67945
68979
  const apiKey = await ensureAuth();
67946
68980
  if (!apiKey) return;
67947
68981
  const client = createCliClient(apiKey);
67948
- const outDir = path16.resolve(options.output);
67949
- const projectName = options.name ?? slugify2(path16.basename(outDir));
68982
+ const outDir = path17.resolve(options.output);
68983
+ const projectName = options.name ?? slugify2(path17.basename(outDir));
67950
68984
  console.log(chalk37.cyan(`
67951
68985
  Scaffolding ${target} deployment to ${outDir}
67952
68986
  `));
@@ -68011,18 +69045,18 @@ Scaffolding ${target} deployment to ${outDir}
68011
69045
  }
68012
69046
  slugSet.add(slug);
68013
69047
  }
68014
- fs16.mkdirSync(path16.join(outDir, "agents"), { recursive: true });
68015
- fs16.mkdirSync(path16.join(outDir, "packages"), { recursive: true });
69048
+ fs16.mkdirSync(path17.join(outDir, "agents"), { recursive: true });
69049
+ fs16.mkdirSync(path17.join(outDir, "packages"), { recursive: true });
68016
69050
  for (const { name, def } of agentDefs) {
68017
69051
  const filename = `${slugify2(name)}.json`;
68018
- fs16.writeFileSync(path16.join(outDir, "agents", filename), JSON.stringify(def, null, 2));
69052
+ fs16.writeFileSync(path17.join(outDir, "agents", filename), JSON.stringify(def, null, 2));
68019
69053
  console.log(` Wrote agents/${filename}`);
68020
69054
  }
68021
69055
  const agentNames = agentDefs.map((a) => a.name);
68022
69056
  let monorepoRoot = process.cwd();
68023
69057
  for (let i = 0; i < 8; i++) {
68024
- if (fs16.existsSync(path16.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
68025
- const parent = path16.dirname(monorepoRoot);
69058
+ if (fs16.existsSync(path17.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
69059
+ const parent = path17.dirname(monorepoRoot);
68026
69060
  if (parent === monorepoRoot) break;
68027
69061
  monorepoRoot = parent;
68028
69062
  }
@@ -68032,35 +69066,35 @@ Scaffolding ${target} deployment to ${outDir}
68032
69066
  }
68033
69067
  const secretNames = Array.from(allSecrets);
68034
69068
  if (target === "cloudflare") {
68035
- fs16.mkdirSync(path16.join(outDir, "src"), { recursive: true });
68036
- fs16.writeFileSync(path16.join(outDir, "src", "index.ts"), workerIndexTs(agentSlugs));
68037
- fs16.writeFileSync(path16.join(outDir, "wrangler.toml"), wranglerToml(projectName));
68038
- fs16.writeFileSync(path16.join(outDir, "package.json"), workerPackageJson(projectName, "workspace:*"));
68039
- fs16.writeFileSync(path16.join(outDir, "tsconfig.json"), workerTsconfigJson());
68040
- const setupPath = path16.join(outDir, "setup.sh");
69069
+ fs16.mkdirSync(path17.join(outDir, "src"), { recursive: true });
69070
+ fs16.writeFileSync(path17.join(outDir, "src", "index.ts"), workerIndexTs(agentSlugs));
69071
+ fs16.writeFileSync(path17.join(outDir, "wrangler.toml"), wranglerToml(projectName));
69072
+ fs16.writeFileSync(path17.join(outDir, "package.json"), workerPackageJson(projectName, "workspace:*"));
69073
+ fs16.writeFileSync(path17.join(outDir, "tsconfig.json"), workerTsconfigJson());
69074
+ const setupPath = path17.join(outDir, "setup.sh");
68041
69075
  fs16.writeFileSync(setupPath, workerSetupSh(monorepoRoot));
68042
69076
  fs16.chmodSync(setupPath, 493);
68043
- fs16.writeFileSync(path16.join(outDir, "README.md"), workerReadme(agentNames, secretNames));
69077
+ fs16.writeFileSync(path17.join(outDir, "README.md"), workerReadme(agentNames, secretNames));
68044
69078
  } else if (target === "vercel") {
68045
- fs16.mkdirSync(path16.join(outDir, "api"), { recursive: true });
68046
- fs16.writeFileSync(path16.join(outDir, "api", "[[...route]].ts"), vercelRouteTs(agentSlugs));
68047
- fs16.writeFileSync(path16.join(outDir, "vercel.json"), vercelJson());
68048
- fs16.writeFileSync(path16.join(outDir, "package.json"), vercelPackageJson(projectName, "workspace:*"));
68049
- fs16.writeFileSync(path16.join(outDir, "tsconfig.json"), vercelTsconfigJson());
68050
- const setupPath = path16.join(outDir, "setup.sh");
69079
+ fs16.mkdirSync(path17.join(outDir, "api"), { recursive: true });
69080
+ fs16.writeFileSync(path17.join(outDir, "api", "[[...route]].ts"), vercelRouteTs(agentSlugs));
69081
+ fs16.writeFileSync(path17.join(outDir, "vercel.json"), vercelJson());
69082
+ fs16.writeFileSync(path17.join(outDir, "package.json"), vercelPackageJson(projectName, "workspace:*"));
69083
+ fs16.writeFileSync(path17.join(outDir, "tsconfig.json"), vercelTsconfigJson());
69084
+ const setupPath = path17.join(outDir, "setup.sh");
68051
69085
  fs16.writeFileSync(setupPath, vercelSetupSh(monorepoRoot));
68052
69086
  fs16.chmodSync(setupPath, 493);
68053
- fs16.writeFileSync(path16.join(outDir, "README.md"), vercelReadme(agentNames, secretNames));
69087
+ fs16.writeFileSync(path17.join(outDir, "README.md"), vercelReadme(agentNames, secretNames));
68054
69088
  } else {
68055
- fs16.writeFileSync(path16.join(outDir, "server.ts"), serverTs());
68056
- fs16.writeFileSync(path16.join(outDir, "Dockerfile"), dockerfile());
68057
- fs16.writeFileSync(path16.join(outDir, ".dockerignore"), dockerignore());
68058
- fs16.writeFileSync(path16.join(outDir, "tsconfig.json"), tsconfigJson());
68059
- fs16.writeFileSync(path16.join(outDir, "package.json"), packageJson(projectName, "workspace:*"));
68060
- const setupPath = path16.join(outDir, "setup.sh");
69089
+ fs16.writeFileSync(path17.join(outDir, "server.ts"), serverTs());
69090
+ fs16.writeFileSync(path17.join(outDir, "Dockerfile"), dockerfile());
69091
+ fs16.writeFileSync(path17.join(outDir, ".dockerignore"), dockerignore());
69092
+ fs16.writeFileSync(path17.join(outDir, "tsconfig.json"), tsconfigJson());
69093
+ fs16.writeFileSync(path17.join(outDir, "package.json"), packageJson(projectName, "workspace:*"));
69094
+ const setupPath = path17.join(outDir, "setup.sh");
68061
69095
  fs16.writeFileSync(setupPath, setupSh(monorepoRoot));
68062
69096
  fs16.chmodSync(setupPath, 493);
68063
- fs16.writeFileSync(path16.join(outDir, "README.md"), readme(agentNames, secretNames));
69097
+ fs16.writeFileSync(path17.join(outDir, "README.md"), readme(agentNames, secretNames));
68064
69098
  }
68065
69099
  console.log("");
68066
69100
  console.log(chalk37.green(`\u2713 Scaffold written to ${outDir}`));
@@ -68118,19 +69152,19 @@ import { Command as Command31 } from "commander";
68118
69152
  import chalk39 from "chalk";
68119
69153
 
68120
69154
  // src/lib/skills-install.ts
68121
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync18, writeFileSync as writeFileSync7 } from "fs";
68122
- import path17 from "path";
69155
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync8 } from "fs";
69156
+ import path18 from "path";
68123
69157
  import readline4 from "readline";
68124
69158
  import chalk38 from "chalk";
68125
69159
  var SKILLS_REPO = "runtypelabs/skills";
68126
69160
  var SKILLS_INSTALL_RETRY_HINT = "Retry with `runtype skills install`, or install manually: npx skills add runtypelabs/skills";
68127
69161
  var METADATA_FILENAME = "agents-skills-install.json";
68128
69162
  function metadataPath() {
68129
- return path17.join(getRuntypeHomeDir(), METADATA_FILENAME);
69163
+ return path18.join(getRuntypeHomeDir(), METADATA_FILENAME);
68130
69164
  }
68131
69165
  function readSkillsInstallMetadata() {
68132
69166
  try {
68133
- const raw = readFileSync18(metadataPath(), "utf8");
69167
+ const raw = readFileSync19(metadataPath(), "utf8");
68134
69168
  const parsed = JSON.parse(raw);
68135
69169
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && parsed.version === 1 && typeof parsed.accepted === "boolean") {
68136
69170
  return parsed;
@@ -68142,8 +69176,8 @@ function readSkillsInstallMetadata() {
68142
69176
  }
68143
69177
  function writeSkillsInstallMetadata(metadata) {
68144
69178
  try {
68145
- mkdirSync9(path17.dirname(metadataPath()), { recursive: true });
68146
- writeFileSync7(metadataPath(), JSON.stringify(metadata, null, 2));
69179
+ mkdirSync10(path18.dirname(metadataPath()), { recursive: true });
69180
+ writeFileSync8(metadataPath(), JSON.stringify(metadata, null, 2));
68147
69181
  } catch {
68148
69182
  }
68149
69183
  }
@@ -68399,7 +69433,7 @@ skillsCommand.command("install").description(`Install Runtype skills (${SKILLS_R
68399
69433
  );
68400
69434
 
68401
69435
  // src/commands/apps.ts
68402
- import { readdirSync as readdirSync6, readFileSync as readFileSync19, lstatSync, statSync as statSync7, existsSync as existsSync14 } from "fs";
69436
+ import { readdirSync as readdirSync6, readFileSync as readFileSync20, lstatSync, statSync as statSync7, existsSync as existsSync15 } from "fs";
68403
69437
  import { join as join12, relative as relative5 } from "path";
68404
69438
  import { Command as Command32 } from "commander";
68405
69439
  import chalk40 from "chalk";
@@ -68420,7 +69454,7 @@ function collectBundleFiles(dir) {
68420
69454
  if (entry === "node_modules") continue;
68421
69455
  walk(full);
68422
69456
  } else {
68423
- zippable[relative5(dir, full).split("\\").join("/")] = readFileSync19(full);
69457
+ zippable[relative5(dir, full).split("\\").join("/")] = readFileSync20(full);
68424
69458
  }
68425
69459
  }
68426
69460
  };
@@ -68501,7 +69535,7 @@ appsCommand.command("deploy <dir>").description("Zip a bundle directory, upload
68501
69535
  const jsonMode = !!(options.json ?? globals.json);
68502
69536
  const apiKey = await ensureAuth();
68503
69537
  if (!apiKey) return;
68504
- if (!existsSync14(dir) || !statSync7(dir).isDirectory()) {
69538
+ if (!existsSync15(dir) || !statSync7(dir).isDirectory()) {
68505
69539
  fail(`Not a directory: ${dir}`, jsonMode, "INVALID_DIR");
68506
69540
  }
68507
69541
  let bundleFiles = {};