@runtypelabs/cli 2.22.11 → 2.22.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1254 -193
- package/package.json +5 -5
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(
|
|
145
|
+
function loadEnv(path19 = resolve(process.cwd(), ".env")) {
|
|
146
146
|
try {
|
|
147
|
-
const content = readFileSync(
|
|
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,
|
|
1390
|
-
if (!
|
|
1389
|
+
function getElementAtPath(obj, path19) {
|
|
1390
|
+
if (!path19)
|
|
1391
1391
|
return obj;
|
|
1392
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 }, [...
|
|
1955
|
+
issue2.errors.map((issues) => processError({ issues }, [...path19, ...issue2.path]));
|
|
1956
1956
|
} else if (issue2.code === "invalid_key") {
|
|
1957
|
-
processError({ issues: issue2.issues }, [...
|
|
1957
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
1958
1958
|
} else if (issue2.code === "invalid_element") {
|
|
1959
|
-
processError({ issues: issue2.issues }, [...
|
|
1959
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
1960
1960
|
} else {
|
|
1961
|
-
const fullpath = [...
|
|
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,
|
|
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 }, [...
|
|
1992
|
+
issue2.errors.map((issues) => processError({ issues }, [...path19, ...issue2.path]));
|
|
1993
1993
|
} else if (issue2.code === "invalid_key") {
|
|
1994
|
-
processError({ issues: issue2.issues }, [...
|
|
1994
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
1995
1995
|
} else if (issue2.code === "invalid_element") {
|
|
1996
|
-
processError({ issues: issue2.issues }, [...
|
|
1996
|
+
processError({ issues: issue2.issues }, [...path19, ...issue2.path]);
|
|
1997
1997
|
} else {
|
|
1998
|
-
const fullpath = [...
|
|
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
|
|
2031
|
-
for (const seg of
|
|
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
|
|
14718
|
-
if (
|
|
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 (
|
|
14723
|
-
const key =
|
|
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,
|
|
15186
|
-
let normalizedPath =
|
|
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(
|
|
19970
|
-
return
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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,
|
|
20199
|
+
function extractTemplateStrings(config3, path19 = []) {
|
|
20200
20200
|
const results = [];
|
|
20201
20201
|
if (typeof config3 === "string") {
|
|
20202
|
-
const fieldName =
|
|
20203
|
-
const parentFieldName =
|
|
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:
|
|
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, [...
|
|
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: [...
|
|
20219
|
+
results.push({ value: val, fieldPath: [...path19, key].join(".") });
|
|
20220
20220
|
} else if (typeof val === "object" && val !== null) {
|
|
20221
|
-
results.push(...extractTemplateStrings(val, [...
|
|
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
|
|
20253
|
-
references.push({ variable:
|
|
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,
|
|
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:
|
|
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
|
|
20495
|
-
registerAgentReference(agentId,
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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,
|
|
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:
|
|
20582
|
+
registerReference(pendingChecks.agentReferencesByName, named.name, { path: path19, step: stepRef });
|
|
20583
20583
|
} else {
|
|
20584
|
-
registerReference(pendingChecks.agentReferencesById, agentId, { path:
|
|
20584
|
+
registerReference(pendingChecks.agentReferencesById, agentId, { path: path19, step: stepRef });
|
|
20585
20585
|
}
|
|
20586
20586
|
}
|
|
20587
|
-
function registerFlowReference(flowId,
|
|
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:
|
|
20591
|
+
registerReference(pendingChecks.flowReferencesByName, named.name, { path: path19, step: stepRef });
|
|
20592
20592
|
} else {
|
|
20593
|
-
registerReference(pendingChecks.flowReferencesById, flowId, { path:
|
|
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:
|
|
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
|
|
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],
|
|
@@ -40223,9 +40223,9 @@ var memoryConfigSchema = external_exports.object({
|
|
|
40223
40223
|
injectSummary: external_exports.boolean().optional()
|
|
40224
40224
|
});
|
|
40225
40225
|
var sandboxNetworkAccessSchema = external_exports.union([
|
|
40226
|
-
external_exports.enum(["none", "essentials"]),
|
|
40226
|
+
external_exports.enum(["none", "essentials", "open"]),
|
|
40227
40227
|
external_exports.object({
|
|
40228
|
-
profile: external_exports.enum(["none", "essentials"]).optional(),
|
|
40228
|
+
profile: external_exports.enum(["none", "essentials", "open"]).optional(),
|
|
40229
40229
|
allow: external_exports.array(external_exports.string()).optional()
|
|
40230
40230
|
})
|
|
40231
40231
|
]);
|
|
@@ -40866,8 +40866,8 @@ var FLAT_ADVANCED_CONFIG_KEYS = {
|
|
|
40866
40866
|
var FLAT_ADVANCED_CONFIG_KEY_LIST = Object.keys(
|
|
40867
40867
|
FLAT_ADVANCED_CONFIG_KEYS
|
|
40868
40868
|
);
|
|
40869
|
-
function createIssue(severity, code, message,
|
|
40870
|
-
return { code, message, path:
|
|
40869
|
+
function createIssue(severity, code, message, path19, suggestedFix) {
|
|
40870
|
+
return { code, message, path: path19, severity, ...suggestedFix ? { suggestedFix } : {} };
|
|
40871
40871
|
}
|
|
40872
40872
|
function emptyResult() {
|
|
40873
40873
|
return { valid: true, errors: [], warnings: [], recommendations: [] };
|
|
@@ -41593,16 +41593,16 @@ var FLOW_PREFIX = Object.values(RUNTIME_PREFIXES).find((spec) => spec.namespace
|
|
|
41593
41593
|
var SECRET_PREFIX = Object.values(RUNTIME_PREFIXES).find(
|
|
41594
41594
|
(spec) => spec.namespace === "secret"
|
|
41595
41595
|
).prefix;
|
|
41596
|
-
function collectStringLeafPaths(value,
|
|
41596
|
+
function collectStringLeafPaths(value, path19 = []) {
|
|
41597
41597
|
if (typeof value === "string") {
|
|
41598
|
-
return [{ path:
|
|
41598
|
+
return [{ path: path19, value }];
|
|
41599
41599
|
}
|
|
41600
41600
|
if (Array.isArray(value)) {
|
|
41601
|
-
return value.flatMap((item, index) => collectStringLeafPaths(item, [...
|
|
41601
|
+
return value.flatMap((item, index) => collectStringLeafPaths(item, [...path19, String(index)]));
|
|
41602
41602
|
}
|
|
41603
41603
|
if (value && typeof value === "object") {
|
|
41604
41604
|
return Object.entries(value).flatMap(
|
|
41605
|
-
([key, nestedValue]) => collectStringLeafPaths(nestedValue, [...
|
|
41605
|
+
([key, nestedValue]) => collectStringLeafPaths(nestedValue, [...path19, key])
|
|
41606
41606
|
);
|
|
41607
41607
|
}
|
|
41608
41608
|
return [];
|
|
@@ -43460,7 +43460,7 @@ function buildDashboardUrl(opts) {
|
|
|
43460
43460
|
while (base.endsWith("/")) {
|
|
43461
43461
|
base = base.slice(0, -1);
|
|
43462
43462
|
}
|
|
43463
|
-
const
|
|
43463
|
+
const path19 = opts.path.startsWith("/") ? opts.path : `/${opts.path}`;
|
|
43464
43464
|
const params = new URLSearchParams();
|
|
43465
43465
|
if (isValidAccountId(opts.account)) {
|
|
43466
43466
|
params.set(ACCOUNT_QUERY_PARAM, opts.account);
|
|
@@ -43473,7 +43473,7 @@ function buildDashboardUrl(opts) {
|
|
|
43473
43473
|
}
|
|
43474
43474
|
}
|
|
43475
43475
|
const qs = params.toString();
|
|
43476
|
-
return qs ? `${base}${
|
|
43476
|
+
return qs ? `${base}${path19}?${qs}` : `${base}${path19}`;
|
|
43477
43477
|
}
|
|
43478
43478
|
function parseAccountId(value) {
|
|
43479
43479
|
if (!value) return null;
|
|
@@ -43622,6 +43622,9 @@ var AgentInputSchema = external_exports.object({
|
|
|
43622
43622
|
// entry points stay in lockstep.
|
|
43623
43623
|
sandbox: sandboxConfigSchema.optional()
|
|
43624
43624
|
}).superRefine((val, ctx) => {
|
|
43625
|
+
if (val.agentId) {
|
|
43626
|
+
return;
|
|
43627
|
+
}
|
|
43625
43628
|
if (val.agentType !== "claude_managed") {
|
|
43626
43629
|
if (!val.name) {
|
|
43627
43630
|
ctx.addIssue({ code: "custom", path: ["name"], message: "name is required" });
|
|
@@ -44773,13 +44776,13 @@ function parseJsonObject(raw, label) {
|
|
|
44773
44776
|
}
|
|
44774
44777
|
return parsed;
|
|
44775
44778
|
}
|
|
44776
|
-
function readJsonFile(
|
|
44779
|
+
function readJsonFile(path19, opts = {}) {
|
|
44777
44780
|
const label = opts.label ?? "file";
|
|
44778
44781
|
let raw;
|
|
44779
44782
|
try {
|
|
44780
|
-
raw = readFileSync3(
|
|
44783
|
+
raw = readFileSync3(path19, "utf-8");
|
|
44781
44784
|
} catch {
|
|
44782
|
-
console.error(chalk2.red(`Failed to read ${label}: ${
|
|
44785
|
+
console.error(chalk2.red(`Failed to read ${label}: ${path19}`));
|
|
44783
44786
|
process.exit(1);
|
|
44784
44787
|
}
|
|
44785
44788
|
const obj = parseJsonObject(raw, label);
|
|
@@ -48661,11 +48664,21 @@ import open2 from "open";
|
|
|
48661
48664
|
|
|
48662
48665
|
// src/lib/account-context.ts
|
|
48663
48666
|
init_credential_store();
|
|
48664
|
-
async function getCurrentAccountId() {
|
|
48667
|
+
async function getCurrentAccountId(options) {
|
|
48668
|
+
if (options?.apiKey) {
|
|
48669
|
+
try {
|
|
48670
|
+
const apiKeyManager = new ApiKeyManager();
|
|
48671
|
+
const user = await apiKeyManager.getCurrentUser(options.apiKey, options.apiUrl);
|
|
48672
|
+
const account = selectAccountId({ userId: user.userId, organizationId: user.orgId });
|
|
48673
|
+
if (account) return account;
|
|
48674
|
+
} catch {
|
|
48675
|
+
}
|
|
48676
|
+
}
|
|
48665
48677
|
try {
|
|
48666
48678
|
const store = new CredentialStore();
|
|
48667
48679
|
const creds = await store.getCredentials();
|
|
48668
48680
|
if (!creds) return void 0;
|
|
48681
|
+
if (options?.apiKey && creds.apiKey !== options.apiKey) return void 0;
|
|
48669
48682
|
return selectAccountId({ userId: creds.userId, organizationId: creds.orgId });
|
|
48670
48683
|
} catch {
|
|
48671
48684
|
return void 0;
|
|
@@ -64426,8 +64439,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
|
|
|
64426
64439
|
const client = createCliClient(apiKey);
|
|
64427
64440
|
if (!isTTY(options) || options.json) {
|
|
64428
64441
|
try {
|
|
64429
|
-
const
|
|
64430
|
-
const data = await client.get(
|
|
64442
|
+
const path19 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
|
|
64443
|
+
const data = await client.get(path19);
|
|
64431
64444
|
printJson(data);
|
|
64432
64445
|
} catch (error51) {
|
|
64433
64446
|
const message = error51 instanceof Error ? error51.message : "Unknown error";
|
|
@@ -64444,8 +64457,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
|
|
|
64444
64457
|
useEffect31(() => {
|
|
64445
64458
|
const run2 = async () => {
|
|
64446
64459
|
try {
|
|
64447
|
-
const
|
|
64448
|
-
const data = await client.get(
|
|
64460
|
+
const path19 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
|
|
64461
|
+
const data = await client.get(path19);
|
|
64449
64462
|
printJson(data);
|
|
64450
64463
|
setSuccess(true);
|
|
64451
64464
|
setLoading(false);
|
|
@@ -64898,19 +64911,19 @@ clientTokensCommand.command("regenerate <id>").description("Regenerate a client
|
|
|
64898
64911
|
import { Command as Command23 } from "commander";
|
|
64899
64912
|
import chalk30 from "chalk";
|
|
64900
64913
|
import readline3 from "readline";
|
|
64901
|
-
import
|
|
64914
|
+
import openBrowser from "open";
|
|
64902
64915
|
import { execFileSync } from "child_process";
|
|
64903
64916
|
|
|
64904
64917
|
// src/lib/persona-init.ts
|
|
64905
64918
|
init_credential_store();
|
|
64906
64919
|
|
|
64907
|
-
// ../../node_modules/.pnpm/@runtypelabs+persona@4.
|
|
64908
|
-
var S = "4.
|
|
64920
|
+
// ../../node_modules/.pnpm/@runtypelabs+persona@4.3.1/node_modules/@runtypelabs/persona/dist/codegen.js
|
|
64921
|
+
var S = "4.3.1";
|
|
64909
64922
|
var c = S;
|
|
64910
64923
|
function u(e) {
|
|
64911
64924
|
if (e !== void 0) return typeof e == "string" ? e : Array.isArray(e) ? `[${e.map((r) => r.toString()).join(", ")}]` : e.toString();
|
|
64912
64925
|
}
|
|
64913
|
-
function
|
|
64926
|
+
function I(e) {
|
|
64914
64927
|
if (e) return { getHeaders: u(e.getHeaders), onFeedback: u(e.onFeedback), onCopy: u(e.onCopy), requestMiddleware: u(e.requestMiddleware), actionHandlers: u(e.actionHandlers), actionParsers: u(e.actionParsers), postprocessMessage: u(e.postprocessMessage), contextProviders: u(e.contextProviders), streamParser: u(e.streamParser) };
|
|
64915
64928
|
}
|
|
64916
64929
|
var x = `({ text, message }: any) => {
|
|
@@ -64977,28 +64990,28 @@ var O = `function(action, context) {
|
|
|
64977
64990
|
window.location.href = targetUrl;
|
|
64978
64991
|
return { handled: true, displayText: text };
|
|
64979
64992
|
}`;
|
|
64980
|
-
var
|
|
64993
|
+
var _ = `(parsed: any) => {
|
|
64981
64994
|
if (!parsed || typeof parsed !== 'object') return null;
|
|
64982
64995
|
if (parsed.action === 'nav_then_click') return 'Navigating...';
|
|
64983
64996
|
if (parsed.action === 'message') return parsed.text || '';
|
|
64984
64997
|
if (parsed.action === 'message_and_click') return parsed.text || 'Processing...';
|
|
64985
64998
|
return parsed.text || null;
|
|
64986
64999
|
}`;
|
|
64987
|
-
var
|
|
65000
|
+
var T = `function(parsed) {
|
|
64988
65001
|
if (!parsed || typeof parsed !== 'object') return null;
|
|
64989
65002
|
if (parsed.action === 'nav_then_click') return 'Navigating...';
|
|
64990
65003
|
if (parsed.action === 'message') return parsed.text || '';
|
|
64991
65004
|
if (parsed.action === 'message_and_click') return parsed.text || 'Processing...';
|
|
64992
65005
|
return parsed.text || null;
|
|
64993
65006
|
}`;
|
|
64994
|
-
function
|
|
65007
|
+
function M(e) {
|
|
64995
65008
|
if (!e) return null;
|
|
64996
65009
|
let r = e.toString();
|
|
64997
65010
|
return r.includes("createJsonStreamParser") || r.includes("partial-json") ? "json" : r.includes("createRegexJsonParser") || r.includes("regex") ? "regex-json" : r.includes("createXmlParser") || r.includes("<text>") ? "xml" : null;
|
|
64998
65011
|
}
|
|
64999
65012
|
function h(e) {
|
|
65000
65013
|
var r, n;
|
|
65001
|
-
return (n = (r = e.parserType) != null ? r :
|
|
65014
|
+
return (n = (r = e.parserType) != null ? r : M(e.streamParser)) != null ? n : "plain";
|
|
65002
65015
|
}
|
|
65003
65016
|
function m(e, r) {
|
|
65004
65017
|
let n = [];
|
|
@@ -65064,15 +65077,15 @@ function g(e) {
|
|
|
65064
65077
|
var r;
|
|
65065
65078
|
return ((r = e == null ? void 0 : e.target) != null ? r : "body").replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
65066
65079
|
}
|
|
65067
|
-
function
|
|
65080
|
+
function R(e, r = "esm", n) {
|
|
65068
65081
|
let s = { ...e };
|
|
65069
65082
|
delete s.postprocessMessage, delete s.initialMessages;
|
|
65070
|
-
let o = n ? { ...n, hooks:
|
|
65083
|
+
let o = n ? { ...n, hooks: I(n.hooks) } : void 0;
|
|
65071
65084
|
return r === "esm" ? W(s, o) : r === "script-installer" ? k(s, o) : r === "script-advanced" ? F(s, o) : r === "react-component" ? H(s, o) : r === "react-advanced" ? N(s, o) : D(s, o);
|
|
65072
65085
|
}
|
|
65073
65086
|
function W(e, r) {
|
|
65074
65087
|
let n = r == null ? void 0 : r.hooks, s = h(e), o = s !== "plain", t = ["import '@runtypelabs/persona/widget.css';", "import { initAgentWidget, markdownPostprocessor } from '@runtypelabs/persona';", "", "initAgentWidget({", ` target: '${g(r)}',`, " config: {"];
|
|
65075
|
-
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
65088
|
+
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.agentId && t.push(` agentId: "${e.agentId}",`), e.target && t.push(` target: "${e.target}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
65076
65089
|
t.push(` ${i}: "${a}",`);
|
|
65077
65090
|
}), t.push(" },")), e.sendButton && (t.push(" sendButton: {"), Object.entries(e.sendButton).forEach(([i, a]) => {
|
|
65078
65091
|
typeof a == "string" ? t.push(` ${i}: "${a}",`) : typeof a == "boolean" && t.push(` ${i}: ${a},`);
|
|
@@ -65089,7 +65102,7 @@ function W(e, r) {
|
|
|
65089
65102
|
}
|
|
65090
65103
|
function H(e, r) {
|
|
65091
65104
|
let n = r == null ? void 0 : r.hooks, s = h(e), o = s !== "plain", t = ["// ChatWidget.tsx", "'use client'; // Required for Next.js - remove for Vite/CRA", "", "import { useEffect } from 'react';", "import '@runtypelabs/persona/widget.css';", "import { initAgentWidget, markdownPostprocessor } from '@runtypelabs/persona';", "import type { AgentWidgetInitHandle } from '@runtypelabs/persona';", "", "export function ChatWidget() {", " useEffect(() => {", " let handle: AgentWidgetInitHandle | null = null;", "", " handle = initAgentWidget({", ` target: '${g(r)}',`, " config: {"];
|
|
65092
|
-
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
65105
|
+
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.agentId && t.push(` agentId: "${e.agentId}",`), e.target && t.push(` target: "${e.target}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
65093
65106
|
t.push(` ${i}: "${a}",`);
|
|
65094
65107
|
}), t.push(" },")), e.sendButton && (t.push(" sendButton: {"), Object.entries(e.sendButton).forEach(([i, a]) => {
|
|
65095
65108
|
typeof a == "string" ? t.push(` ${i}: "${a}",`) : typeof a == "boolean" && t.push(` ${i}: ${a},`);
|
|
@@ -65106,7 +65119,7 @@ function H(e, r) {
|
|
|
65106
65119
|
}
|
|
65107
65120
|
function N(e, r) {
|
|
65108
65121
|
let n = r == null ? void 0 : r.hooks, s = ["// ChatWidgetAdvanced.tsx", "'use client'; // Required for Next.js - remove for Vite/CRA", "", "import { useEffect } from 'react';", "import '@runtypelabs/persona/widget.css';", "import {", " initAgentWidget,", " createFlexibleJsonStreamParser,", " defaultJsonActionParser,", " defaultActionHandlers,", " markdownPostprocessor", "} from '@runtypelabs/persona';", "import type { AgentWidgetInitHandle } from '@runtypelabs/persona';", "", "const STORAGE_KEY = 'chat-widget-state';", "const PROCESSED_ACTIONS_KEY = 'chat-widget-processed-actions';", "", "// Types for DOM elements", "interface PageElement {", " type: string;", " tagName: string;", " selector: string;", " innerText: string;", " href?: string;", "}", "", "interface DOMContext {", " page_elements: PageElement[];", " page_element_count: number;", " element_types: Record<string, number>;", " page_url: string;", " page_title: string;", " timestamp: string;", "}", "", "// DOM context provider - extracts page elements for AI context", "const collectDOMContext = (): DOMContext => {", " const selectors = {", ` products: '[data-product-id], .product-card, .product-item, [role="article"]',`, ` buttons: 'button, [role="button"], .btn',`, " links: 'a[href]',", " inputs: 'input, textarea, select'", " };", "", " const elements: PageElement[] = [];", " Object.entries(selectors).forEach(([type, selector]) => {", " document.querySelectorAll(selector).forEach((element) => {", " if (!(element instanceof HTMLElement)) return;", " ", " // Exclude elements within the widget", " const widgetHost = element.closest('.persona-host');", " if (widgetHost) return;", " ", " const text = element.innerText?.trim();", " if (!text) return;", "", " const selectorString =", " element.id ? `#${element.id}` :", " element.getAttribute('data-testid') ? `[data-testid=\"${element.getAttribute('data-testid')}\"]` :", " element.getAttribute('data-product-id') ? `[data-product-id=\"${element.getAttribute('data-product-id')}\"]` :", " element.tagName.toLowerCase();", "", " const elementData: PageElement = {", " type,", " tagName: element.tagName.toLowerCase(),", " selector: selectorString,", " innerText: text.substring(0, 200)", " };", "", " if (type === 'links' && element instanceof HTMLAnchorElement && element.href) {", " elementData.href = element.href;", " }", "", " elements.push(elementData);", " });", " });", "", " const counts = elements.reduce((acc, el) => {", " acc[el.type] = (acc[el.type] || 0) + 1;", " return acc;", " }, {} as Record<string, number>);", "", " return {", " page_elements: elements.slice(0, 50),", " page_element_count: elements.length,", " element_types: counts,", " page_url: window.location.href,", " page_title: document.title,", " timestamp: new Date().toISOString()", " };", "};", "", "export function ChatWidgetAdvanced() {", " useEffect(() => {", " let handle: AgentWidgetInitHandle | null = null;", "", " // Load saved state", " const loadSavedMessages = () => {", " const savedState = localStorage.getItem(STORAGE_KEY);", " if (savedState) {", " try {", " const { messages } = JSON.parse(savedState);", " return messages || [];", " } catch (e) {", " console.error('Failed to load saved state:', e);", " }", " }", " return [];", " };", "", " handle = initAgentWidget({", ` target: '${g(r)}',`, " config: {"];
|
|
65109
|
-
return e.apiUrl && s.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && s.push(` clientToken: "${e.clientToken}",`), e.flowId && s.push(` flowId: "${e.flowId}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(s, "theme", e.theme, " "), e.launcher && l(s, "launcher", e.launcher, " "), e.copy && (s.push(" copy: {"), Object.entries(e.copy).forEach(([o, t]) => {
|
|
65122
|
+
return e.apiUrl && s.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && s.push(` clientToken: "${e.clientToken}",`), e.agentId && s.push(` agentId: "${e.agentId}",`), e.target && s.push(` target: "${e.target}",`), e.flowId && s.push(` flowId: "${e.flowId}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(s, "theme", e.theme, " "), e.launcher && l(s, "launcher", e.launcher, " "), e.copy && (s.push(" copy: {"), Object.entries(e.copy).forEach(([o, t]) => {
|
|
65110
65123
|
s.push(` ${o}: "${t}",`);
|
|
65111
65124
|
}), s.push(" },")), e.sendButton && (s.push(" sendButton: {"), Object.entries(e.sendButton).forEach(([o, t]) => {
|
|
65112
65125
|
typeof t == "string" ? s.push(` ${o}: "${t}",`) : typeof t == "boolean" && s.push(` ${o}: ${t},`);
|
|
@@ -65118,13 +65131,13 @@ function N(e, r) {
|
|
|
65118
65131
|
s.push(` ${o}: ${t},`);
|
|
65119
65132
|
}), s.push(" },")), e.suggestionChips && e.suggestionChips.length > 0 && (s.push(" suggestionChips: ["), e.suggestionChips.forEach((o) => {
|
|
65120
65133
|
s.push(` "${o}",`);
|
|
65121
|
-
}), s.push(" ],")), e.suggestionChipsConfig && (s.push(" suggestionChipsConfig: {"), e.suggestionChipsConfig.fontFamily && s.push(` fontFamily: "${e.suggestionChipsConfig.fontFamily}",`), e.suggestionChipsConfig.fontWeight && s.push(` fontWeight: "${e.suggestionChipsConfig.fontWeight}",`), e.suggestionChipsConfig.paddingX && s.push(` paddingX: "${e.suggestionChipsConfig.paddingX}",`), e.suggestionChipsConfig.paddingY && s.push(` paddingY: "${e.suggestionChipsConfig.paddingY}",`), s.push(" },")), s.push(...m(e, " ")), s.push(...f(e, " ", n)), s.push(...y(e, " ")), s.push(...C(e, " ")), n != null && n.getHeaders && s.push(` getHeaders: ${n.getHeaders},`), n != null && n.contextProviders && s.push(` contextProviders: ${n.contextProviders},`), e.debug && s.push(` debug: ${e.debug},`), s.push(" initialMessages: loadSavedMessages(),"), n != null && n.streamParser ? s.push(` streamParser: ${n.streamParser},`) : (s.push(" // Flexible JSON stream parser for handling structured actions"), s.push(` streamParser: () => createFlexibleJsonStreamParser(${
|
|
65134
|
+
}), s.push(" ],")), e.suggestionChipsConfig && (s.push(" suggestionChipsConfig: {"), e.suggestionChipsConfig.fontFamily && s.push(` fontFamily: "${e.suggestionChipsConfig.fontFamily}",`), e.suggestionChipsConfig.fontWeight && s.push(` fontWeight: "${e.suggestionChipsConfig.fontWeight}",`), e.suggestionChipsConfig.paddingX && s.push(` paddingX: "${e.suggestionChipsConfig.paddingX}",`), e.suggestionChipsConfig.paddingY && s.push(` paddingY: "${e.suggestionChipsConfig.paddingY}",`), s.push(" },")), s.push(...m(e, " ")), s.push(...f(e, " ", n)), s.push(...y(e, " ")), s.push(...C(e, " ")), n != null && n.getHeaders && s.push(` getHeaders: ${n.getHeaders},`), n != null && n.contextProviders && s.push(` contextProviders: ${n.contextProviders},`), e.debug && s.push(` debug: ${e.debug},`), s.push(" initialMessages: loadSavedMessages(),"), n != null && n.streamParser ? s.push(` streamParser: ${n.streamParser},`) : (s.push(" // Flexible JSON stream parser for handling structured actions"), s.push(` streamParser: () => createFlexibleJsonStreamParser(${_}),`)), n != null && n.actionParsers ? (s.push(" // Action parsers (custom merged with defaults)"), s.push(` actionParsers: [...(${n.actionParsers}), defaultJsonActionParser,`), s.push(" // Built-in parser for markdown-wrapped JSON"), s.push(` ${x}`), s.push(" ],")) : (s.push(" // Action parsers to detect JSON actions in responses"), s.push(" actionParsers: ["), s.push(" defaultJsonActionParser,"), s.push(" // Parser for markdown-wrapped JSON"), s.push(` ${x}`), s.push(" ],")), n != null && n.actionHandlers ? (s.push(" // Action handlers (custom merged with defaults)"), s.push(` actionHandlers: [...(${n.actionHandlers}),`), s.push(" defaultActionHandlers.message,"), s.push(" defaultActionHandlers.messageAndClick,"), s.push(" // Built-in handler for nav_then_click action"), s.push(` ${j}`), s.push(" ],")) : (s.push(" // Action handlers for navigation and other actions"), s.push(" actionHandlers: ["), s.push(" defaultActionHandlers.message,"), s.push(" defaultActionHandlers.messageAndClick,"), s.push(" // Handler for nav_then_click action"), s.push(` ${j}`), s.push(" ],")), n != null && n.postprocessMessage ? s.push(` postprocessMessage: ${n.postprocessMessage},`) : s.push(" postprocessMessage: ({ text }) => markdownPostprocessor(text),"), n != null && n.requestMiddleware ? (s.push(" // Request middleware (custom merged with DOM context)"), s.push(" requestMiddleware: ({ payload, config }) => {"), s.push(` const customResult = (${n.requestMiddleware})({ payload, config });`), s.push(" const merged = customResult || payload;"), s.push(" return {"), s.push(" ...merged,"), s.push(" metadata: { ...merged.metadata, ...collectDOMContext() }"), s.push(" };"), s.push(" }")) : (s.push(" requestMiddleware: ({ payload }) => {"), s.push(" return {"), s.push(" ...payload,"), s.push(" metadata: collectDOMContext()"), s.push(" };"), s.push(" }")), s.push(" }"), s.push(" });"), s.push(""), s.push(" // Save state on message events"), s.push(" const handleMessage = () => {"), s.push(" const session = handle?.getSession?.();"), s.push(" if (session) {"), s.push(" localStorage.setItem(STORAGE_KEY, JSON.stringify({"), s.push(" messages: session.messages,"), s.push(" timestamp: new Date().toISOString()"), s.push(" }));"), s.push(" }"), s.push(" };"), s.push(""), s.push(" // Clear state on clear chat"), s.push(" const handleClearChat = () => {"), s.push(" localStorage.removeItem(STORAGE_KEY);"), s.push(" localStorage.removeItem(PROCESSED_ACTIONS_KEY);"), s.push(" };"), s.push(""), s.push(" window.addEventListener('persona:message', handleMessage);"), s.push(" window.addEventListener('persona:clear-chat', handleClearChat);"), s.push(""), s.push(" // Cleanup on unmount"), s.push(" return () => {"), s.push(" window.removeEventListener('persona:message', handleMessage);"), s.push(" window.removeEventListener('persona:clear-chat', handleClearChat);"), s.push(" if (handle) {"), s.push(" handle.destroy();"), s.push(" }"), s.push(" };"), s.push(" }, []);"), s.push(""), s.push(" return null; // Widget injects itself into the DOM"), s.push("}"), s.push(""), s.push("// Usage: Collects DOM context for AI-powered navigation"), s.push("// Features:"), s.push("// - Extracts page elements (products, buttons, links)"), s.push("// - Persists chat history across page loads"), s.push("// - Handles navigation actions (nav_then_click)"), s.push("// - Processes structured JSON actions from AI"), s.push("//"), s.push("// Example usage in Next.js:"), s.push("// import { ChatWidgetAdvanced } from './components/ChatWidgetAdvanced';"), s.push("//"), s.push("// export default function RootLayout({ children }) {"), s.push("// return ("), s.push('// <html lang="en">'), s.push("// <body>"), s.push("// {children}"), s.push("// <ChatWidgetAdvanced />"), s.push("// </body>"), s.push("// </html>"), s.push("// );"), s.push("// }"), s.join(`
|
|
65122
65135
|
`);
|
|
65123
65136
|
}
|
|
65124
65137
|
function P(e) {
|
|
65125
65138
|
var o;
|
|
65126
65139
|
let r = h(e), n = r !== "plain", s = {};
|
|
65127
|
-
if (e.apiUrl && (s.apiUrl = e.apiUrl), e.clientToken && (s.clientToken = e.clientToken), e.flowId && (s.flowId = e.flowId), n && (s.parserType = r), e.theme && (s.theme = e.theme), e.launcher && (s.launcher = e.launcher), e.copy && (s.copy = e.copy), e.sendButton && (s.sendButton = e.sendButton), e.voiceRecognition && (s.voiceRecognition = e.voiceRecognition), e.statusIndicator && (s.statusIndicator = e.statusIndicator), e.features && (s.features = e.features), ((o = e.suggestionChips) == null ? void 0 : o.length) > 0 && (s.suggestionChips = e.suggestionChips), e.suggestionChipsConfig && (s.suggestionChipsConfig = e.suggestionChipsConfig), e.debug && (s.debug = e.debug), e.toolCall) {
|
|
65140
|
+
if (e.apiUrl && (s.apiUrl = e.apiUrl), e.clientToken && (s.clientToken = e.clientToken), e.agentId && (s.agentId = e.agentId), e.target && (s.target = e.target), e.flowId && (s.flowId = e.flowId), n && (s.parserType = r), e.theme && (s.theme = e.theme), e.launcher && (s.launcher = e.launcher), e.copy && (s.copy = e.copy), e.sendButton && (s.sendButton = e.sendButton), e.voiceRecognition && (s.voiceRecognition = e.voiceRecognition), e.statusIndicator && (s.statusIndicator = e.statusIndicator), e.features && (s.features = e.features), ((o = e.suggestionChips) == null ? void 0 : o.length) > 0 && (s.suggestionChips = e.suggestionChips), e.suggestionChipsConfig && (s.suggestionChipsConfig = e.suggestionChipsConfig), e.debug && (s.debug = e.debug), e.toolCall) {
|
|
65128
65141
|
let t = {};
|
|
65129
65142
|
Object.entries(e.toolCall).forEach(([i, a]) => {
|
|
65130
65143
|
typeof a == "string" && (t[i] = a);
|
|
@@ -65170,7 +65183,7 @@ function k(e, r) {
|
|
|
65170
65183
|
}
|
|
65171
65184
|
function D(e, r) {
|
|
65172
65185
|
let n = r == null ? void 0 : r.hooks, s = h(e), o = s !== "plain", t = ["<!-- Load CSS -->", `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@${c}/dist/widget.css" />`, "", "<!-- Load JavaScript -->", `<script src="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@${c}/dist/index.global.js"></script>`, "", "<!-- Initialize widget -->", "<script>", " var handle = window.AgentWidget.initAgentWidget({", ` target: '${g(r)}',`, ...r != null && r.windowKey ? [` windowKey: '${r.windowKey}',`] : [], " config: {"];
|
|
65173
|
-
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
65186
|
+
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.agentId && t.push(` agentId: "${e.agentId}",`), e.target && t.push(` target: "${e.target}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
65174
65187
|
t.push(` ${i}: "${a}",`);
|
|
65175
65188
|
}), t.push(" },")), e.sendButton && (t.push(" sendButton: {"), Object.entries(e.sendButton).forEach(([i, a]) => {
|
|
65176
65189
|
typeof a == "string" ? t.push(` ${i}: "${a}",`) : typeof a == "boolean" && t.push(` ${i}: ${a},`);
|
|
@@ -65189,7 +65202,7 @@ function F(e, r) {
|
|
|
65189
65202
|
let n = r == null ? void 0 : r.hooks, s = P(e), t = ["<script>", "(function() {", " 'use strict';", "", " // Configuration", ` var CONFIG = ${JSON.stringify(s, null, 2).split(`
|
|
65190
65203
|
`).map((i, a) => a === 0 ? i : " " + i).join(`
|
|
65191
65204
|
`)};`, "", " // Constants", ` var CDN_BASE = 'https://cdn.jsdelivr.net/npm/@runtypelabs/persona@${c}/dist';`, " var STORAGE_KEY = 'chat-widget-state';", " var PROCESSED_ACTIONS_KEY = 'chat-widget-processed-actions';", "", " // DOM context provider - extracts page elements for AI context", " var domContextProvider = function() {", " var selectors = {", ` products: '[data-product-id], .product-card, .product-item, [role="article"]',`, ` buttons: 'button, [role="button"], .btn',`, " links: 'a[href]',", " inputs: 'input, textarea, select'", " };", "", " var elements = [];", " Object.entries(selectors).forEach(function(entry) {", " var type = entry[0], selector = entry[1];", " document.querySelectorAll(selector).forEach(function(element) {", " if (!(element instanceof HTMLElement)) return;", " var widgetHost = element.closest('.persona-host');", " if (widgetHost) return;", " var text = element.innerText ? element.innerText.trim() : '';", " if (!text) return;", "", " var selectorString = element.id ? '#' + element.id :", ` element.getAttribute('data-testid') ? '[data-testid="' + element.getAttribute('data-testid') + '"]' :`, ` element.getAttribute('data-product-id') ? '[data-product-id="' + element.getAttribute('data-product-id') + '"]' :`, " element.tagName.toLowerCase();", "", " var elementData = {", " type: type,", " tagName: element.tagName.toLowerCase(),", " selector: selectorString,", " innerText: text.substring(0, 200)", " };", "", " if (type === 'links' && element instanceof HTMLAnchorElement && element.href) {", " elementData.href = element.href;", " }", " elements.push(elementData);", " });", " });", "", " var counts = elements.reduce(function(acc, el) {", " acc[el.type] = (acc[el.type] || 0) + 1;", " return acc;", " }, {});", "", " return {", " page_elements: elements.slice(0, 50),", " page_element_count: elements.length,", " element_types: counts,", " page_url: window.location.href,", " page_title: document.title,", " timestamp: new Date().toISOString()", " };", " };", "", " // Load CSS dynamically", " var loadCSS = function() {", " if (document.querySelector('link[data-persona]')) return;", " var link = document.createElement('link');", " link.rel = 'stylesheet';", " link.href = CDN_BASE + '/widget.css';", " link.setAttribute('data-persona', 'true');", " document.head.appendChild(link);", " };", "", " // Load JS dynamically", " var loadJS = function(callback) {", " if (window.AgentWidget) { callback(); return; }", " var script = document.createElement('script');", " script.src = CDN_BASE + '/index.global.js';", " script.onload = callback;", " script.onerror = function() { console.error('Failed to load AgentWidget'); };", " document.head.appendChild(script);", " };", "", " // Create widget config with advanced features", " var createWidgetConfig = function(agentWidget) {", " var widgetConfig = Object.assign({}, CONFIG);", ""];
|
|
65192
|
-
return n != null && n.getHeaders && (t.push(` widgetConfig.getHeaders = ${n.getHeaders};`), t.push("")), n != null && n.contextProviders && (t.push(` widgetConfig.contextProviders = ${n.contextProviders};`), t.push("")), n != null && n.streamParser ? t.push(` widgetConfig.streamParser = ${n.streamParser};`) : (t.push(" // Flexible JSON stream parser for handling structured actions"), t.push(" widgetConfig.streamParser = function() {"), t.push(` return agentWidget.createFlexibleJsonStreamParser(${
|
|
65205
|
+
return n != null && n.getHeaders && (t.push(` widgetConfig.getHeaders = ${n.getHeaders};`), t.push("")), n != null && n.contextProviders && (t.push(` widgetConfig.contextProviders = ${n.contextProviders};`), t.push("")), n != null && n.streamParser ? t.push(` widgetConfig.streamParser = ${n.streamParser};`) : (t.push(" // Flexible JSON stream parser for handling structured actions"), t.push(" widgetConfig.streamParser = function() {"), t.push(` return agentWidget.createFlexibleJsonStreamParser(${T});`), t.push(" };")), t.push(""), n != null && n.actionParsers ? (t.push(" // Action parsers (custom merged with defaults)"), t.push(` var customParsers = ${n.actionParsers};`), t.push(" widgetConfig.actionParsers = customParsers.concat(["), t.push(" agentWidget.defaultJsonActionParser,"), t.push(` ${A}`), t.push(" ]);")) : (t.push(" // Action parsers to detect JSON actions in responses"), t.push(" widgetConfig.actionParsers = ["), t.push(" agentWidget.defaultJsonActionParser,"), t.push(` ${A}`), t.push(" ];")), t.push(""), n != null && n.actionHandlers ? (t.push(" // Action handlers (custom merged with defaults)"), t.push(` var customHandlers = ${n.actionHandlers};`), t.push(" widgetConfig.actionHandlers = customHandlers.concat(["), t.push(" agentWidget.defaultActionHandlers.message,"), t.push(" agentWidget.defaultActionHandlers.messageAndClick,"), t.push(` ${O}`), t.push(" ]);")) : (t.push(" // Action handlers for navigation and other actions"), t.push(" widgetConfig.actionHandlers = ["), t.push(" agentWidget.defaultActionHandlers.message,"), t.push(" agentWidget.defaultActionHandlers.messageAndClick,"), t.push(` ${O}`), t.push(" ];")), t.push(""), n != null && n.requestMiddleware ? (t.push(" // Request middleware (custom merged with DOM context)"), t.push(" widgetConfig.requestMiddleware = function(ctx) {"), t.push(` var customResult = (${n.requestMiddleware})(ctx);`), t.push(" var merged = customResult || ctx.payload;"), t.push(" return Object.assign({}, merged, { metadata: Object.assign({}, merged.metadata, domContextProvider()) });"), t.push(" };")) : (t.push(" // Send DOM context with each request"), t.push(" widgetConfig.requestMiddleware = function(ctx) {"), t.push(" return Object.assign({}, ctx.payload, { metadata: domContextProvider() });"), t.push(" };")), t.push(""), n != null && n.postprocessMessage ? t.push(` widgetConfig.postprocessMessage = ${n.postprocessMessage};`) : (t.push(" // Markdown postprocessor"), t.push(" widgetConfig.postprocessMessage = function(ctx) {"), t.push(" return agentWidget.markdownPostprocessor(ctx.text);"), t.push(" };")), t.push(""), (n != null && n.onFeedback || n != null && n.onCopy) && (t.push(" // Message action callbacks"), t.push(" widgetConfig.messageActions = widgetConfig.messageActions || {};"), n != null && n.onFeedback && t.push(` widgetConfig.messageActions.onFeedback = ${n.onFeedback};`), n != null && n.onCopy && t.push(` widgetConfig.messageActions.onCopy = ${n.onCopy};`), t.push("")), t.push(" return widgetConfig;", " };", "", " // Initialize widget", " var init = function() {", " var agentWidget = window.AgentWidget;", " if (!agentWidget) {", " console.error('AgentWidget not loaded');", " return;", " }", "", " var widgetConfig = createWidgetConfig(agentWidget);", "", " // Load saved state", " var savedState = localStorage.getItem(STORAGE_KEY);", " if (savedState) {", " try {", " var parsed = JSON.parse(savedState);", " widgetConfig.initialMessages = parsed.messages || [];", " } catch (e) {", " console.error('Failed to load saved state:', e);", " }", " }", "", " // Initialize widget", " var handle = agentWidget.initAgentWidget({", ` target: '${g(r)}',`, " useShadowDom: false,", ...r != null && r.windowKey ? [` windowKey: '${r.windowKey}',`] : [], " config: widgetConfig", " });", "", " // Save state on message events", " window.addEventListener('persona:message', function() {", " var session = handle.getSession ? handle.getSession() : null;", " if (session) {", " localStorage.setItem(STORAGE_KEY, JSON.stringify({", " messages: session.messages,", " timestamp: new Date().toISOString()", " }));", " }", " });", "", " // Clear state on clear chat", " window.addEventListener('persona:clear-chat', function() {", " localStorage.removeItem(STORAGE_KEY);", " localStorage.removeItem(PROCESSED_ACTIONS_KEY);", " });", " };", "", " // Wait for framework hydration to complete (Next.js, Nuxt, etc.)", " // This prevents the framework from removing dynamically added CSS during reconciliation", " var waitForHydration = function(callback) {", " var executed = false;", " ", " var execute = function() {", " if (executed) return;", " executed = true;", " callback();", " };", "", " var afterDom = function() {", " // Strategy 1: Use requestIdleCallback if available (best for detecting idle after hydration)", " if (typeof requestIdleCallback !== 'undefined') {", " requestIdleCallback(function() {", " // Double requestAnimationFrame ensures at least one full paint cycle completed", " requestAnimationFrame(function() {", " requestAnimationFrame(execute);", " });", " }, { timeout: 3000 }); // Max wait 3 seconds, then proceed anyway", " } else {", " // Strategy 2: Fallback for Safari (no requestIdleCallback)", " // 300ms is typically enough for hydration on most pages", " setTimeout(execute, 300);", " }", " };", "", " if (document.readyState === 'loading') {", " document.addEventListener('DOMContentLoaded', afterDom);", " } else {", " // DOM already ready, but still wait for potential hydration", " afterDom();", " }", " };", "", " // Boot sequence: wait for hydration, then load CSS and JS, then initialize", " // This prevents Next.js/Nuxt/etc. from removing dynamically added CSS during reconciliation", " waitForHydration(function() {", " loadCSS();", " loadJS(function() {", " init();", " });", " });", "})();", "</script>"), t.join(`
|
|
65193
65206
|
`);
|
|
65194
65207
|
}
|
|
65195
65208
|
|
|
@@ -65229,14 +65242,58 @@ function buildWidgetConfig(input) {
|
|
|
65229
65242
|
function generatePersonaInitSnippet(input, personaFormat) {
|
|
65230
65243
|
const widgetConfig = buildWidgetConfig(input);
|
|
65231
65244
|
const target = input.targetSelector?.trim();
|
|
65232
|
-
return
|
|
65245
|
+
return R(
|
|
65233
65246
|
widgetConfig,
|
|
65234
65247
|
personaFormat,
|
|
65235
65248
|
target ? { target } : void 0
|
|
65236
65249
|
);
|
|
65237
65250
|
}
|
|
65251
|
+
function getPersonaInstallerScriptUrl() {
|
|
65252
|
+
const snippet = R(
|
|
65253
|
+
{
|
|
65254
|
+
apiUrl: "https://api.runtype.com",
|
|
65255
|
+
clientToken: "ct_test_demo_00000000000000000000000000000000",
|
|
65256
|
+
parserType: "json"
|
|
65257
|
+
},
|
|
65258
|
+
"script-installer"
|
|
65259
|
+
);
|
|
65260
|
+
const match = snippet.match(/<script\s+src="([^"]+)"/);
|
|
65261
|
+
return match?.[1] ?? "https://cdn.jsdelivr.net/npm/@runtypelabs/persona/dist/install.global.js";
|
|
65262
|
+
}
|
|
65238
65263
|
|
|
65239
65264
|
// src/lib/persona-init.ts
|
|
65265
|
+
var PERSONA_INIT_AGENT_MODEL = "nemotron-3-ultra-550b-a55b";
|
|
65266
|
+
var PERSONA_INIT_DEMO_SYSTEM_PROMPT = `
|
|
65267
|
+
# Persona Playground Agent
|
|
65268
|
+
|
|
65269
|
+
## Role
|
|
65270
|
+
|
|
65271
|
+
You are the assistant inside a local Persona Playground generated by the Runtype CLI.
|
|
65272
|
+
|
|
65273
|
+
## Goal
|
|
65274
|
+
|
|
65275
|
+
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.
|
|
65276
|
+
|
|
65277
|
+
## Available page tools
|
|
65278
|
+
|
|
65279
|
+
- \`get_playground_state\` \u2014 read the current accent, headline, note, status, checklist, URL, and allowed origins.
|
|
65280
|
+
- \`update_playground\` \u2014 update the accent, headline, note, status, or checklist on the local HTML page.
|
|
65281
|
+
|
|
65282
|
+
## Demo behavior
|
|
65283
|
+
|
|
65284
|
+
1. Use \`get_playground_state\` before describing the current page or proposing a specific page change.
|
|
65285
|
+
2. Use \`update_playground\` when the user asks you to change the page.
|
|
65286
|
+
3. Explain, only when relevant, that mutating page updates require the user to approve Persona's tool-call bubble.
|
|
65287
|
+
4. After every successful \`update_playground\` call, follow \`responseGuidance\` exactly: do not send a visible response yet; first call \`suggest_replies\` with \`responseGuidance.suggestedReplies\`.
|
|
65288
|
+
5. When \`suggest_replies\` returns, send \`responseGuidance.assistantMessage\` exactly once as your only visible confirmation, then stop.
|
|
65289
|
+
6. Do not ask "what would you like to do next?" in prose; the Persona widget renders \`suggest_replies\` as tappable next-step pills.
|
|
65290
|
+
|
|
65291
|
+
## Response style
|
|
65292
|
+
|
|
65293
|
+
- Be concise, direct, and practical.
|
|
65294
|
+
- Prefer showing the page changing over explaining how it works.
|
|
65295
|
+
- If the user asks how to customize the demo, point them to \`index.html\`, the generated README, and the Runtype dashboard link.
|
|
65296
|
+
`.trim();
|
|
65240
65297
|
async function getPersonaInitApiKeyNonInteractive(apiUrl) {
|
|
65241
65298
|
const envApiKey = getRuntimeApiKey();
|
|
65242
65299
|
if (envApiKey) {
|
|
@@ -65254,14 +65311,75 @@ async function getPersonaInitApiKeyNonInteractive(apiUrl) {
|
|
|
65254
65311
|
}
|
|
65255
65312
|
async function runPersonaInit(options) {
|
|
65256
65313
|
const client = createCliClient(options.apiKey, options.apiUrl);
|
|
65314
|
+
const demoEnabled = !!options.demo;
|
|
65257
65315
|
const agent = await client.post("/agents", {
|
|
65258
65316
|
name: options.agentName,
|
|
65259
65317
|
description: options.agentDescription || "A Persona test agent",
|
|
65260
65318
|
config: {
|
|
65261
|
-
model:
|
|
65262
|
-
systemPrompt: "You are a helpful assistant."
|
|
65319
|
+
model: PERSONA_INIT_AGENT_MODEL,
|
|
65320
|
+
systemPrompt: demoEnabled ? PERSONA_INIT_DEMO_SYSTEM_PROMPT : "You are a helpful assistant."
|
|
65263
65321
|
}
|
|
65264
65322
|
});
|
|
65323
|
+
let demoResources;
|
|
65324
|
+
if (options.demo) {
|
|
65325
|
+
const product = await client.post("/products", {
|
|
65326
|
+
name: `${options.agentName} Persona Playground`,
|
|
65327
|
+
description: "Local Persona WebMCP playground generated by the Runtype CLI.",
|
|
65328
|
+
icon: "\u2728",
|
|
65329
|
+
spec: {
|
|
65330
|
+
productGoal: "Demonstrate a Persona widget operating a host page through WebMCP tools.",
|
|
65331
|
+
targetAudience: "Developers testing Persona locally.",
|
|
65332
|
+
productStage: "prototype"
|
|
65333
|
+
}
|
|
65334
|
+
});
|
|
65335
|
+
const capability = await client.post(
|
|
65336
|
+
`/products/${product.id}/capabilities`,
|
|
65337
|
+
{
|
|
65338
|
+
agentId: agent.id,
|
|
65339
|
+
capabilityName: "Persona Playground Assistant",
|
|
65340
|
+
capabilityDescription: "Agent that can read and update the local Persona Playground page through WebMCP tools.",
|
|
65341
|
+
enabled: true
|
|
65342
|
+
}
|
|
65343
|
+
);
|
|
65344
|
+
const allowlist = options.demo.origins.map((origin) => ({
|
|
65345
|
+
origin,
|
|
65346
|
+
tools: options.demo?.toolNames ?? []
|
|
65347
|
+
}));
|
|
65348
|
+
const surface = await client.post(
|
|
65349
|
+
`/products/${product.id}/surfaces`,
|
|
65350
|
+
{
|
|
65351
|
+
name: "Local Persona Playground",
|
|
65352
|
+
type: "chat",
|
|
65353
|
+
status: "active",
|
|
65354
|
+
environment: "development",
|
|
65355
|
+
behavior: {
|
|
65356
|
+
type: "chat",
|
|
65357
|
+
welcomeMessage: "Try asking me to inspect or update this local page. I can use WebMCP tools registered by the HTML file.",
|
|
65358
|
+
webmcp: {
|
|
65359
|
+
enabled: true,
|
|
65360
|
+
allowlist,
|
|
65361
|
+
requireConfirmFor: ["update_playground"]
|
|
65362
|
+
}
|
|
65363
|
+
}
|
|
65364
|
+
}
|
|
65365
|
+
);
|
|
65366
|
+
const surfaceItem = await client.post(
|
|
65367
|
+
`/products/${product.id}/surfaces/${surface.id}/items`,
|
|
65368
|
+
{
|
|
65369
|
+
capabilityId: capability.id,
|
|
65370
|
+
exposedName: "Persona Playground Assistant",
|
|
65371
|
+
exposedDescription: "Operate the generated local HTML playground.",
|
|
65372
|
+
enabled: true,
|
|
65373
|
+
isEntryPoint: true
|
|
65374
|
+
}
|
|
65375
|
+
);
|
|
65376
|
+
demoResources = {
|
|
65377
|
+
productId: product.id,
|
|
65378
|
+
capabilityId: capability.id,
|
|
65379
|
+
surfaceId: surface.id,
|
|
65380
|
+
surfaceItemId: surfaceItem.id
|
|
65381
|
+
};
|
|
65382
|
+
}
|
|
65265
65383
|
const tokenBody = {
|
|
65266
65384
|
name: options.tokenName,
|
|
65267
65385
|
flowIds: [],
|
|
@@ -65271,7 +65389,8 @@ async function runPersonaInit(options) {
|
|
|
65271
65389
|
rateLimitPerMinute: 10,
|
|
65272
65390
|
rateLimitPerHour: 100,
|
|
65273
65391
|
maxMessagesPerSession: 100,
|
|
65274
|
-
sessionIdleTimeoutMinutes: 30
|
|
65392
|
+
sessionIdleTimeoutMinutes: 30,
|
|
65393
|
+
...demoResources ? { productSurfaceId: demoResources.surfaceId } : {}
|
|
65275
65394
|
};
|
|
65276
65395
|
const tokenRes = await client.post("/client-tokens", tokenBody);
|
|
65277
65396
|
const personaFormat = mapCliFormatToPersona(options.format);
|
|
@@ -65284,7 +65403,7 @@ async function runPersonaInit(options) {
|
|
|
65284
65403
|
personaFormat
|
|
65285
65404
|
);
|
|
65286
65405
|
const dashboardBase = getDashboardUrl();
|
|
65287
|
-
const account = await getCurrentAccountId();
|
|
65406
|
+
const account = await getCurrentAccountId({ apiKey: options.apiKey, apiUrl: options.apiUrl });
|
|
65288
65407
|
const dashboardUrl = buildDashboardUrl({
|
|
65289
65408
|
baseUrl: dashboardBase,
|
|
65290
65409
|
path: `/agents/${agent.id}`,
|
|
@@ -65301,20 +65420,718 @@ async function runPersonaInit(options) {
|
|
|
65301
65420
|
},
|
|
65302
65421
|
snippet: { format: options.format, code },
|
|
65303
65422
|
dashboardUrl,
|
|
65304
|
-
warnings: tokenRes.warnings
|
|
65423
|
+
warnings: tokenRes.warnings,
|
|
65424
|
+
...demoResources ? { demo: demoResources } : {}
|
|
65305
65425
|
};
|
|
65306
65426
|
}
|
|
65307
65427
|
|
|
65428
|
+
// src/lib/persona-demo.ts
|
|
65429
|
+
import { createServer } from "http";
|
|
65430
|
+
import { createServer as createNetServer } from "net";
|
|
65431
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "fs";
|
|
65432
|
+
import path16 from "path";
|
|
65433
|
+
var PERSONA_DEMO_DEFAULT_DIR = "persona-demo";
|
|
65434
|
+
var PERSONA_DEMO_DEFAULT_PORT = 43110;
|
|
65435
|
+
var PERSONA_DEMO_TOOL_NAMES = ["get_playground_state", "update_playground"];
|
|
65436
|
+
function unique(values) {
|
|
65437
|
+
return [...new Set(values.filter(Boolean))];
|
|
65438
|
+
}
|
|
65439
|
+
function buildPersonaDemoOrigins(port) {
|
|
65440
|
+
return [`http://localhost:${port}`, `http://127.0.0.1:${port}`];
|
|
65441
|
+
}
|
|
65442
|
+
function mergePersonaDemoAllowedOrigins(requestedOrigins, demoOrigins) {
|
|
65443
|
+
const explicitOrigins = (requestedOrigins ?? []).filter((origin) => origin !== "*");
|
|
65444
|
+
return unique([...demoOrigins, ...explicitOrigins]);
|
|
65445
|
+
}
|
|
65446
|
+
function resolvePersonaDemoDirectory(input) {
|
|
65447
|
+
return path16.resolve(process.cwd(), input?.trim() || PERSONA_DEMO_DEFAULT_DIR);
|
|
65448
|
+
}
|
|
65449
|
+
function personaDemoIndexPath(directory) {
|
|
65450
|
+
return path16.join(directory, "index.html");
|
|
65451
|
+
}
|
|
65452
|
+
function personaDemoReadmePath(directory) {
|
|
65453
|
+
return path16.join(directory, "README.md");
|
|
65454
|
+
}
|
|
65455
|
+
function ensurePersonaDemoCanWrite(directory, force) {
|
|
65456
|
+
const existingFiles = [personaDemoIndexPath(directory), personaDemoReadmePath(directory)].filter(
|
|
65457
|
+
(filePath) => existsSync13(filePath)
|
|
65458
|
+
);
|
|
65459
|
+
if (existingFiles.length > 0 && !force) {
|
|
65460
|
+
throw new Error(
|
|
65461
|
+
`Demo file already exists at ${existingFiles.join(", ")}. Pass --force to overwrite demo files or choose --demo-dir.`
|
|
65462
|
+
);
|
|
65463
|
+
}
|
|
65464
|
+
}
|
|
65465
|
+
function writePersonaDemoPage(options) {
|
|
65466
|
+
ensurePersonaDemoCanWrite(options.directory, options.force);
|
|
65467
|
+
mkdirSync8(options.directory, { recursive: true });
|
|
65468
|
+
const filePath = personaDemoIndexPath(options.directory);
|
|
65469
|
+
const readmePath = personaDemoReadmePath(options.directory);
|
|
65470
|
+
writeFileSync6(filePath, `${options.html.trim()}
|
|
65471
|
+
`, "utf8");
|
|
65472
|
+
writeFileSync6(readmePath, `${options.readme.trim()}
|
|
65473
|
+
`, "utf8");
|
|
65474
|
+
return { directory: options.directory, filePath, readmePath };
|
|
65475
|
+
}
|
|
65476
|
+
async function findAvailablePersonaDemoPort(preferredPort = PERSONA_DEMO_DEFAULT_PORT) {
|
|
65477
|
+
for (let offset = 0; offset < 50; offset += 1) {
|
|
65478
|
+
const port = preferredPort + offset;
|
|
65479
|
+
if (await canListenOnPort(port)) {
|
|
65480
|
+
return port;
|
|
65481
|
+
}
|
|
65482
|
+
}
|
|
65483
|
+
throw new Error(`Could not find an available local port starting at ${preferredPort}`);
|
|
65484
|
+
}
|
|
65485
|
+
function canListenOnPort(port) {
|
|
65486
|
+
return new Promise((resolve11) => {
|
|
65487
|
+
const server = createNetServer();
|
|
65488
|
+
server.once("error", () => {
|
|
65489
|
+
resolve11(false);
|
|
65490
|
+
});
|
|
65491
|
+
server.once("listening", () => {
|
|
65492
|
+
server.close(() => resolve11(true));
|
|
65493
|
+
});
|
|
65494
|
+
server.listen(port, "127.0.0.1");
|
|
65495
|
+
});
|
|
65496
|
+
}
|
|
65497
|
+
async function startPersonaDemoServer(options) {
|
|
65498
|
+
const filePath = personaDemoIndexPath(options.directory);
|
|
65499
|
+
const server = createServer((req, res) => {
|
|
65500
|
+
const url2 = req.url?.split("?")[0] ?? "/";
|
|
65501
|
+
if (url2 !== "/" && url2 !== "/index.html") {
|
|
65502
|
+
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
65503
|
+
res.end("Not found");
|
|
65504
|
+
return;
|
|
65505
|
+
}
|
|
65506
|
+
res.writeHead(200, {
|
|
65507
|
+
"content-type": "text/html; charset=utf-8",
|
|
65508
|
+
"cache-control": "no-store"
|
|
65509
|
+
});
|
|
65510
|
+
res.end(readIndexHtml(filePath));
|
|
65511
|
+
});
|
|
65512
|
+
await listen(server, options.port);
|
|
65513
|
+
return {
|
|
65514
|
+
url: `http://127.0.0.1:${options.port}/`,
|
|
65515
|
+
port: options.port,
|
|
65516
|
+
close: () => new Promise((resolve11, reject) => {
|
|
65517
|
+
server.close((error51) => {
|
|
65518
|
+
if (error51) reject(error51);
|
|
65519
|
+
else resolve11();
|
|
65520
|
+
});
|
|
65521
|
+
})
|
|
65522
|
+
};
|
|
65523
|
+
}
|
|
65524
|
+
function readIndexHtml(filePath) {
|
|
65525
|
+
return readFileSync17(filePath, "utf8");
|
|
65526
|
+
}
|
|
65527
|
+
function listen(server, port) {
|
|
65528
|
+
return new Promise((resolve11, reject) => {
|
|
65529
|
+
server.once("error", reject);
|
|
65530
|
+
server.listen(port, "127.0.0.1", () => {
|
|
65531
|
+
server.off("error", reject);
|
|
65532
|
+
resolve11();
|
|
65533
|
+
});
|
|
65534
|
+
});
|
|
65535
|
+
}
|
|
65536
|
+
function escapeHtml(value) {
|
|
65537
|
+
return value.replace(/[&<>"']/g, (char) => {
|
|
65538
|
+
switch (char) {
|
|
65539
|
+
case "&":
|
|
65540
|
+
return "&";
|
|
65541
|
+
case "<":
|
|
65542
|
+
return "<";
|
|
65543
|
+
case ">":
|
|
65544
|
+
return ">";
|
|
65545
|
+
case '"':
|
|
65546
|
+
return """;
|
|
65547
|
+
case "'":
|
|
65548
|
+
return "'";
|
|
65549
|
+
default:
|
|
65550
|
+
return char;
|
|
65551
|
+
}
|
|
65552
|
+
});
|
|
65553
|
+
}
|
|
65554
|
+
function inlineJson(value) {
|
|
65555
|
+
return JSON.stringify(value, null, 2).replace(/<\//g, "<\\/");
|
|
65556
|
+
}
|
|
65557
|
+
function generatePersonaDemoHtml(input) {
|
|
65558
|
+
const installerScriptUrl = input.installerScriptUrl ?? getPersonaInstallerScriptUrl();
|
|
65559
|
+
const pageData = {
|
|
65560
|
+
apiUrl: input.apiUrl,
|
|
65561
|
+
clientToken: input.clientToken,
|
|
65562
|
+
clientTokenId: input.clientTokenId,
|
|
65563
|
+
agentId: input.agentId,
|
|
65564
|
+
agentName: input.agentName,
|
|
65565
|
+
dashboardUrl: input.dashboardUrl,
|
|
65566
|
+
environment: input.environment,
|
|
65567
|
+
localUrl: input.localUrl,
|
|
65568
|
+
allowedOrigins: input.allowedOrigins
|
|
65569
|
+
};
|
|
65570
|
+
return `<!doctype html>
|
|
65571
|
+
<html lang="en">
|
|
65572
|
+
<head>
|
|
65573
|
+
<meta charset="utf-8" />
|
|
65574
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
65575
|
+
<title>Persona Local Playground</title>
|
|
65576
|
+
<style>
|
|
65577
|
+
:root {
|
|
65578
|
+
--paper: #fcfcfa;
|
|
65579
|
+
--paper-deep: #f4f0e8;
|
|
65580
|
+
--ink: #24211f;
|
|
65581
|
+
--muted: #67615b;
|
|
65582
|
+
--line: #d9d2c7;
|
|
65583
|
+
--line-strong: #201a16;
|
|
65584
|
+
--accent: #4c00ff;
|
|
65585
|
+
--accent-soft: color-mix(in srgb, var(--accent) 8%, var(--paper));
|
|
65586
|
+
--live: #b6ff00;
|
|
65587
|
+
--success: #178c4b;
|
|
65588
|
+
--radius: 6px;
|
|
65589
|
+
}
|
|
65590
|
+
* { box-sizing: border-box; }
|
|
65591
|
+
body {
|
|
65592
|
+
margin: 0;
|
|
65593
|
+
min-height: 100vh;
|
|
65594
|
+
color: var(--ink);
|
|
65595
|
+
font-family: Asap, Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
65596
|
+
background:
|
|
65597
|
+
linear-gradient(90deg, rgba(36, 33, 31, .045) 1px, transparent 1px) 0 0 / 40px 40px,
|
|
65598
|
+
linear-gradient(rgba(36, 33, 31, .04) 1px, transparent 1px) 0 0 / 40px 40px,
|
|
65599
|
+
radial-gradient(circle at 18% 0%, var(--accent-soft), transparent 30rem),
|
|
65600
|
+
var(--paper);
|
|
65601
|
+
}
|
|
65602
|
+
button { font: inherit; }
|
|
65603
|
+
.shell {
|
|
65604
|
+
width: min(920px, calc(100% - 32px));
|
|
65605
|
+
margin: 0 auto;
|
|
65606
|
+
padding: clamp(28px, 6vw, 64px) 0 112px;
|
|
65607
|
+
}
|
|
65608
|
+
.panel {
|
|
65609
|
+
border: 1px solid var(--line-strong);
|
|
65610
|
+
border-radius: var(--radius);
|
|
65611
|
+
background: color-mix(in srgb, var(--paper) 91%, white);
|
|
65612
|
+
box-shadow: 7px 7px 0 rgba(36, 33, 31, .12);
|
|
65613
|
+
padding: clamp(18px, 3vw, 28px);
|
|
65614
|
+
}
|
|
65615
|
+
.demo-grid {
|
|
65616
|
+
display: grid;
|
|
65617
|
+
grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
|
|
65618
|
+
gap: 18px;
|
|
65619
|
+
align-items: stretch;
|
|
65620
|
+
}
|
|
65621
|
+
.preview {
|
|
65622
|
+
min-height: 280px;
|
|
65623
|
+
display: grid;
|
|
65624
|
+
align-content: space-between;
|
|
65625
|
+
gap: 24px;
|
|
65626
|
+
border: 1px solid var(--line-strong);
|
|
65627
|
+
border-radius: var(--radius);
|
|
65628
|
+
padding: clamp(20px, 3vw, 28px);
|
|
65629
|
+
color: white;
|
|
65630
|
+
background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 86%, black), var(--accent));
|
|
65631
|
+
}
|
|
65632
|
+
.preview h2 {
|
|
65633
|
+
margin: 0;
|
|
65634
|
+
max-width: 560px;
|
|
65635
|
+
font-family: Newsreader, Georgia, "Times New Roman", serif;
|
|
65636
|
+
font-size: clamp(30px, 5vw, 54px);
|
|
65637
|
+
line-height: .96;
|
|
65638
|
+
letter-spacing: -0.04em;
|
|
65639
|
+
}
|
|
65640
|
+
.preview p { max-width: 560px; margin: 12px 0 0; opacity: .9; line-height: 1.6; }
|
|
65641
|
+
.status-pill {
|
|
65642
|
+
justify-self: start;
|
|
65643
|
+
border: 1px solid rgba(255,255,255,.75);
|
|
65644
|
+
border-radius: 999px;
|
|
65645
|
+
padding: 7px 10px;
|
|
65646
|
+
font-size: 12px;
|
|
65647
|
+
font-weight: 800;
|
|
65648
|
+
}
|
|
65649
|
+
.section-title {
|
|
65650
|
+
margin: 0 0 12px;
|
|
65651
|
+
color: var(--muted);
|
|
65652
|
+
font-size: 12px;
|
|
65653
|
+
font-weight: 800;
|
|
65654
|
+
letter-spacing: .12em;
|
|
65655
|
+
text-transform: uppercase;
|
|
65656
|
+
}
|
|
65657
|
+
.tasks { display: grid; gap: 9px; }
|
|
65658
|
+
.task {
|
|
65659
|
+
display: flex;
|
|
65660
|
+
align-items: center;
|
|
65661
|
+
gap: 10px;
|
|
65662
|
+
padding: 11px 12px;
|
|
65663
|
+
border: 1px solid var(--line);
|
|
65664
|
+
border-radius: var(--radius);
|
|
65665
|
+
background: var(--paper);
|
|
65666
|
+
}
|
|
65667
|
+
.task-dot {
|
|
65668
|
+
display: grid;
|
|
65669
|
+
place-items: center;
|
|
65670
|
+
width: 23px;
|
|
65671
|
+
height: 23px;
|
|
65672
|
+
border-radius: 999px;
|
|
65673
|
+
color: var(--paper);
|
|
65674
|
+
background: #9c958e;
|
|
65675
|
+
font-size: 13px;
|
|
65676
|
+
font-weight: 900;
|
|
65677
|
+
}
|
|
65678
|
+
.task[data-done="true"] .task-dot { background: var(--success); }
|
|
65679
|
+
.task[data-done="true"] .task-label { color: var(--muted); text-decoration: line-through; }
|
|
65680
|
+
.activity {
|
|
65681
|
+
margin-top: 18px;
|
|
65682
|
+
padding-top: 16px;
|
|
65683
|
+
border-top: 1px solid var(--line);
|
|
65684
|
+
}
|
|
65685
|
+
.log { display: grid; gap: 8px; max-height: 120px; overflow: auto; }
|
|
65686
|
+
.log-row {
|
|
65687
|
+
color: #4b463f;
|
|
65688
|
+
font-size: 12px;
|
|
65689
|
+
line-height: 1.45;
|
|
65690
|
+
}
|
|
65691
|
+
.log-row strong { color: var(--ink); }
|
|
65692
|
+
.action-bar {
|
|
65693
|
+
display: flex;
|
|
65694
|
+
flex-wrap: wrap;
|
|
65695
|
+
gap: 10px;
|
|
65696
|
+
align-items: center;
|
|
65697
|
+
margin-top: 18px;
|
|
65698
|
+
padding-top: 18px;
|
|
65699
|
+
border-top: 1px solid var(--line);
|
|
65700
|
+
}
|
|
65701
|
+
.cta {
|
|
65702
|
+
display: inline-flex;
|
|
65703
|
+
align-items: center;
|
|
65704
|
+
justify-content: center;
|
|
65705
|
+
gap: 8px;
|
|
65706
|
+
min-height: 42px;
|
|
65707
|
+
border: 1px solid var(--line-strong);
|
|
65708
|
+
border-radius: var(--radius);
|
|
65709
|
+
padding: 10px 13px;
|
|
65710
|
+
color: var(--ink);
|
|
65711
|
+
font-size: 14px;
|
|
65712
|
+
font-weight: 800;
|
|
65713
|
+
text-decoration: none;
|
|
65714
|
+
cursor: pointer;
|
|
65715
|
+
}
|
|
65716
|
+
.cta-primary { background: var(--accent); color: white; }
|
|
65717
|
+
.cta-secondary { background: var(--paper); }
|
|
65718
|
+
.cta-arrow { font-size: 18px; line-height: 1; }
|
|
65719
|
+
details {
|
|
65720
|
+
margin-top: 18px;
|
|
65721
|
+
color: var(--muted);
|
|
65722
|
+
font-size: 13px;
|
|
65723
|
+
}
|
|
65724
|
+
summary {
|
|
65725
|
+
cursor: pointer;
|
|
65726
|
+
width: fit-content;
|
|
65727
|
+
color: var(--ink);
|
|
65728
|
+
font-weight: 700;
|
|
65729
|
+
}
|
|
65730
|
+
.details-grid {
|
|
65731
|
+
display: grid;
|
|
65732
|
+
grid-template-columns: 90px minmax(0, 1fr);
|
|
65733
|
+
gap: 8px 14px;
|
|
65734
|
+
margin-top: 12px;
|
|
65735
|
+
}
|
|
65736
|
+
code {
|
|
65737
|
+
color: #2f2a26;
|
|
65738
|
+
word-break: break-word;
|
|
65739
|
+
font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
|
|
65740
|
+
font-size: 12px;
|
|
65741
|
+
}
|
|
65742
|
+
@media (max-width: 820px) {
|
|
65743
|
+
.demo-grid { grid-template-columns: 1fr; }
|
|
65744
|
+
.shell { width: min(100% - 24px, 720px); }
|
|
65745
|
+
}
|
|
65746
|
+
@media (prefers-reduced-motion: reduce) {
|
|
65747
|
+
*, *::before, *::after { transition: none !important; }
|
|
65748
|
+
}
|
|
65749
|
+
</style>
|
|
65750
|
+
</head>
|
|
65751
|
+
<body>
|
|
65752
|
+
<!-- Edit this file directly, refresh the browser, and keep customizing your Persona starter. -->
|
|
65753
|
+
<main class="shell">
|
|
65754
|
+
<section class="panel" aria-label="Persona demo workspace">
|
|
65755
|
+
<div class="demo-grid">
|
|
65756
|
+
<div class="preview" id="accent-preview">
|
|
65757
|
+
<div>
|
|
65758
|
+
<h2 id="playground-headline">Local tools. Visible results.</h2>
|
|
65759
|
+
<p id="playground-note">Persona can read this page, request approval, and update the UI from the browser.</p>
|
|
65760
|
+
</div>
|
|
65761
|
+
<span class="status-pill" id="status-pill">Waiting for your first task</span>
|
|
65762
|
+
</div>
|
|
65763
|
+
|
|
65764
|
+
<div>
|
|
65765
|
+
<p class="section-title">Checklist</p>
|
|
65766
|
+
<div class="tasks" id="task-list"></div>
|
|
65767
|
+
|
|
65768
|
+
<div class="activity">
|
|
65769
|
+
<p class="section-title">Activity</p>
|
|
65770
|
+
<div class="log" id="tool-log"></div>
|
|
65771
|
+
</div>
|
|
65772
|
+
</div>
|
|
65773
|
+
</div>
|
|
65774
|
+
|
|
65775
|
+
<div class="action-bar" aria-label="Next actions">
|
|
65776
|
+
<button class="cta cta-primary" id="use-persona-widget" type="button">
|
|
65777
|
+
<span id="use-persona-label">Use Persona widget</span> <span class="cta-arrow" aria-hidden="true">\u2198</span>
|
|
65778
|
+
</button>
|
|
65779
|
+
<a class="cta cta-secondary" href="${escapeHtml(input.dashboardUrl)}" target="_blank" rel="noreferrer">Customize your agent</a>
|
|
65780
|
+
</div>
|
|
65781
|
+
|
|
65782
|
+
<details>
|
|
65783
|
+
<summary>Technical details</summary>
|
|
65784
|
+
<div class="details-grid">
|
|
65785
|
+
<span>Agent</span><code>${escapeHtml(input.agentId)}</code>
|
|
65786
|
+
<span>Token</span><code>${escapeHtml(input.clientTokenId)} (${escapeHtml(input.environment)})</code>
|
|
65787
|
+
<span>Edit</span><code>index.html</code>
|
|
65788
|
+
<span>Origin</span><code>${escapeHtml(input.localUrl)}</code>
|
|
65789
|
+
<span>Tools</span><code>${PERSONA_DEMO_TOOL_NAMES.join(", ")}</code>
|
|
65790
|
+
<span>Dashboard</span><code>${escapeHtml(input.dashboardUrl)}</code>
|
|
65791
|
+
</div>
|
|
65792
|
+
</details>
|
|
65793
|
+
</section>
|
|
65794
|
+
</main>
|
|
65795
|
+
|
|
65796
|
+
<div id="persona-root"></div>
|
|
65797
|
+
|
|
65798
|
+
<!-- 1. Runtime values injected by the CLI. -->
|
|
65799
|
+
<script>
|
|
65800
|
+
window.__RUNTYPE_PERSONA_DEMO__ = ${inlineJson(pageData)};
|
|
65801
|
+
</script>
|
|
65802
|
+
<!-- 2. Minimal WebMCP host bridge for this dependency-free page. -->
|
|
65803
|
+
<script>
|
|
65804
|
+
(function installMinimalModelContext() {
|
|
65805
|
+
if (document.modelContext && typeof document.modelContext.getTools === 'function') {
|
|
65806
|
+
return;
|
|
65807
|
+
}
|
|
65808
|
+
const tools = new Map();
|
|
65809
|
+
document.modelContext = {
|
|
65810
|
+
registerTool(tool) {
|
|
65811
|
+
if (!tool || !tool.name || typeof tool.execute !== 'function') {
|
|
65812
|
+
throw new Error('registerTool requires a name and execute function');
|
|
65813
|
+
}
|
|
65814
|
+
tools.set(tool.name, tool);
|
|
65815
|
+
},
|
|
65816
|
+
async getTools() {
|
|
65817
|
+
return Array.from(tools.values()).map((tool) => ({
|
|
65818
|
+
name: tool.name,
|
|
65819
|
+
title: tool.title || '',
|
|
65820
|
+
description: tool.description || '',
|
|
65821
|
+
inputSchema: JSON.stringify(tool.inputSchema || { type: 'object', properties: {} }),
|
|
65822
|
+
}));
|
|
65823
|
+
},
|
|
65824
|
+
async executeTool(info, inputArgsJson) {
|
|
65825
|
+
const name = typeof info === 'string' ? info : info && info.name;
|
|
65826
|
+
const tool = tools.get(name);
|
|
65827
|
+
if (!tool) throw new Error('Tool not registered: ' + name);
|
|
65828
|
+
const args = inputArgsJson ? JSON.parse(inputArgsJson) : {};
|
|
65829
|
+
const result = await tool.execute(args, {
|
|
65830
|
+
requestUserInteraction: async (callback) => callback(),
|
|
65831
|
+
});
|
|
65832
|
+
return result === undefined ? null : JSON.stringify(result);
|
|
65833
|
+
},
|
|
65834
|
+
};
|
|
65835
|
+
})();
|
|
65836
|
+
|
|
65837
|
+
const demo = window.__RUNTYPE_PERSONA_DEMO__;
|
|
65838
|
+
/* 3. Page state the tools can read and update. */
|
|
65839
|
+
const accentMap = {
|
|
65840
|
+
violet: '#4c00ff',
|
|
65841
|
+
green: '#178c4b',
|
|
65842
|
+
cyan: '#008ca8',
|
|
65843
|
+
orange: '#d95f02',
|
|
65844
|
+
};
|
|
65845
|
+
const state = {
|
|
65846
|
+
accent: 'violet',
|
|
65847
|
+
headline: 'Local tools. Visible results.',
|
|
65848
|
+
note: 'Persona can read this page, request approval, and update the UI from the browser.',
|
|
65849
|
+
status: 'Waiting for your first task',
|
|
65850
|
+
tasks: [
|
|
65851
|
+
{ id: 'widget', label: 'Widget installed', done: true },
|
|
65852
|
+
{ id: 'webmcp', label: 'WebMCP tools connected', done: true },
|
|
65853
|
+
{ id: 'setup', label: 'Setup complete', done: false },
|
|
65854
|
+
],
|
|
65855
|
+
};
|
|
65856
|
+
|
|
65857
|
+
function escapeText(value) {
|
|
65858
|
+
return String(value).replace(/[&<>]/g, (char) => ({ '&': '&', '<': '<', '>': '>' })[char]);
|
|
65859
|
+
}
|
|
65860
|
+
|
|
65861
|
+
function logTool(kind, message) {
|
|
65862
|
+
const log = document.getElementById('tool-log');
|
|
65863
|
+
const row = document.createElement('div');
|
|
65864
|
+
row.className = 'log-row';
|
|
65865
|
+
row.innerHTML = '<strong>' + escapeText(kind) + '</strong> \xB7 ' + escapeText(message);
|
|
65866
|
+
log.prepend(row);
|
|
65867
|
+
}
|
|
65868
|
+
|
|
65869
|
+
function snapshot() {
|
|
65870
|
+
return {
|
|
65871
|
+
accent: state.accent,
|
|
65872
|
+
accentHex: accentMap[state.accent],
|
|
65873
|
+
headline: state.headline,
|
|
65874
|
+
note: state.note,
|
|
65875
|
+
status: state.status,
|
|
65876
|
+
tasks: state.tasks,
|
|
65877
|
+
pageUrl: location.href,
|
|
65878
|
+
allowedOrigins: demo.allowedOrigins,
|
|
65879
|
+
};
|
|
65880
|
+
}
|
|
65881
|
+
|
|
65882
|
+
function render() {
|
|
65883
|
+
document.documentElement.style.setProperty('--accent', accentMap[state.accent]);
|
|
65884
|
+
document.getElementById('playground-headline').textContent = state.headline;
|
|
65885
|
+
document.getElementById('playground-note').textContent = state.note;
|
|
65886
|
+
document.getElementById('status-pill').textContent = state.status;
|
|
65887
|
+
const setupDone = state.tasks.some((task) => task.id === 'setup' && task.done);
|
|
65888
|
+
const ctaLabel = document.getElementById('use-persona-label');
|
|
65889
|
+
if (ctaLabel) ctaLabel.textContent = setupDone ? 'Try another page change' : 'Use Persona widget';
|
|
65890
|
+
const taskList = document.getElementById('task-list');
|
|
65891
|
+
taskList.innerHTML = '';
|
|
65892
|
+
for (const task of state.tasks) {
|
|
65893
|
+
const row = document.createElement('div');
|
|
65894
|
+
row.className = 'task';
|
|
65895
|
+
row.dataset.done = String(task.done);
|
|
65896
|
+
row.innerHTML = '<span class="task-dot">\u2713</span><span class="task-label"></span>';
|
|
65897
|
+
row.querySelector('.task-label').textContent = task.label;
|
|
65898
|
+
taskList.appendChild(row);
|
|
65899
|
+
}
|
|
65900
|
+
}
|
|
65901
|
+
|
|
65902
|
+
function taskLabel(id) {
|
|
65903
|
+
const task = state.tasks.find((item) => item.id === id);
|
|
65904
|
+
return task ? task.label : id;
|
|
65905
|
+
}
|
|
65906
|
+
|
|
65907
|
+
function buildAssistantMessage(args, changed) {
|
|
65908
|
+
if (!changed.length) return 'Done \u2014 no visible page changes were needed.';
|
|
65909
|
+
|
|
65910
|
+
const updates = [];
|
|
65911
|
+
if (args.accent && accentMap[args.accent]) updates.push('the page is now ' + args.accent);
|
|
65912
|
+
if (typeof args.headline === 'string' && args.headline.trim()) updates.push('the headline changed');
|
|
65913
|
+
if (typeof args.note === 'string' && args.note.trim()) updates.push('the note changed');
|
|
65914
|
+
if (typeof args.status === 'string' && args.status.trim()) updates.push('the status changed');
|
|
65915
|
+
if (Array.isArray(args.completedTaskIds) && args.completedTaskIds.length) {
|
|
65916
|
+
const labels = args.completedTaskIds.map((id) => taskLabel(id));
|
|
65917
|
+
updates.push(
|
|
65918
|
+
labels.length === 1 ? labels[0] + ' is checked' : labels.join(', ') + ' are checked'
|
|
65919
|
+
);
|
|
65920
|
+
}
|
|
65921
|
+
|
|
65922
|
+
return 'Done \u2014 ' + updates.join(' and ') + '.';
|
|
65923
|
+
}
|
|
65924
|
+
|
|
65925
|
+
function buildSuggestedReplies() {
|
|
65926
|
+
return [
|
|
65927
|
+
'Change the headline',
|
|
65928
|
+
'Add another page tool',
|
|
65929
|
+
'Show the embed code',
|
|
65930
|
+
'Customize the agent',
|
|
65931
|
+
];
|
|
65932
|
+
}
|
|
65933
|
+
|
|
65934
|
+
/* 4. WebMCP tools exposed to the Persona widget. */
|
|
65935
|
+
document.modelContext.registerTool({
|
|
65936
|
+
name: 'get_playground_state',
|
|
65937
|
+
title: 'Read playground state',
|
|
65938
|
+
description: 'Read the current local Persona playground state: accent, headline, note, status, checklist, URL, and allowed origins. Use this before proposing page changes.',
|
|
65939
|
+
inputSchema: { type: 'object', properties: {} },
|
|
65940
|
+
annotations: { readOnlyHint: true },
|
|
65941
|
+
async execute() {
|
|
65942
|
+
logTool('Read page state', 'Persona inspected the local HTML page');
|
|
65943
|
+
return snapshot();
|
|
65944
|
+
},
|
|
65945
|
+
});
|
|
65946
|
+
|
|
65947
|
+
document.modelContext.registerTool({
|
|
65948
|
+
name: 'update_playground',
|
|
65949
|
+
title: 'Update playground UI',
|
|
65950
|
+
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.',
|
|
65951
|
+
inputSchema: {
|
|
65952
|
+
type: 'object',
|
|
65953
|
+
properties: {
|
|
65954
|
+
accent: { type: 'string', enum: Object.keys(accentMap), description: 'Accent color to apply.' },
|
|
65955
|
+
headline: { type: 'string', description: 'New hero headline.' },
|
|
65956
|
+
note: { type: 'string', description: 'New explanatory note under the headline.' },
|
|
65957
|
+
status: { type: 'string', description: 'Short status shown inside the demo card.' },
|
|
65958
|
+
completedTaskIds: {
|
|
65959
|
+
type: 'array',
|
|
65960
|
+
items: { type: 'string', enum: state.tasks.map((task) => task.id) },
|
|
65961
|
+
description: 'Checklist task ids to mark complete.',
|
|
65962
|
+
},
|
|
65963
|
+
},
|
|
65964
|
+
},
|
|
65965
|
+
async execute(args) {
|
|
65966
|
+
const changed = [];
|
|
65967
|
+
if (args.accent && accentMap[args.accent]) {
|
|
65968
|
+
state.accent = args.accent;
|
|
65969
|
+
changed.push('accent');
|
|
65970
|
+
}
|
|
65971
|
+
if (typeof args.headline === 'string' && args.headline.trim()) {
|
|
65972
|
+
state.headline = args.headline.trim();
|
|
65973
|
+
changed.push('headline');
|
|
65974
|
+
}
|
|
65975
|
+
if (typeof args.note === 'string' && args.note.trim()) {
|
|
65976
|
+
state.note = args.note.trim();
|
|
65977
|
+
changed.push('note');
|
|
65978
|
+
}
|
|
65979
|
+
if (typeof args.status === 'string' && args.status.trim()) {
|
|
65980
|
+
state.status = args.status.trim();
|
|
65981
|
+
changed.push('status');
|
|
65982
|
+
}
|
|
65983
|
+
if (Array.isArray(args.completedTaskIds) && args.completedTaskIds.length) {
|
|
65984
|
+
const completed = new Set(args.completedTaskIds);
|
|
65985
|
+
state.tasks = state.tasks.map((task) => completed.has(task.id) ? { ...task, done: true } : task);
|
|
65986
|
+
changed.push('checklist');
|
|
65987
|
+
}
|
|
65988
|
+
render();
|
|
65989
|
+
logTool('Updated page', changed.length ? changed.join(' + ') : 'No visible changes requested');
|
|
65990
|
+
return {
|
|
65991
|
+
ok: true,
|
|
65992
|
+
changed,
|
|
65993
|
+
responseGuidance: {
|
|
65994
|
+
assistantMessage: buildAssistantMessage(args, changed),
|
|
65995
|
+
suggestedReplies: buildSuggestedReplies(),
|
|
65996
|
+
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.',
|
|
65997
|
+
},
|
|
65998
|
+
state: snapshot(),
|
|
65999
|
+
};
|
|
66000
|
+
},
|
|
66001
|
+
});
|
|
66002
|
+
|
|
66003
|
+
/* 5. Persona widget config. The installer below reads window.siteAgentConfig. */
|
|
66004
|
+
window.siteAgentConfig = {
|
|
66005
|
+
target: '#persona-root',
|
|
66006
|
+
windowKey: 'personaPlayground',
|
|
66007
|
+
config: {
|
|
66008
|
+
apiUrl: demo.apiUrl,
|
|
66009
|
+
clientToken: demo.clientToken,
|
|
66010
|
+
parserType: 'json',
|
|
66011
|
+
launcher: {
|
|
66012
|
+
enabled: true,
|
|
66013
|
+
autoExpand: true,
|
|
66014
|
+
title: 'Persona Playground',
|
|
66015
|
+
subtitle: 'Local WebMCP demo',
|
|
66016
|
+
width: '430px',
|
|
66017
|
+
},
|
|
66018
|
+
copy: {
|
|
66019
|
+
welcomeTitle: 'Persona Playground',
|
|
66020
|
+
welcomeSubtitle: 'Use the page tools, then pick a next step.',
|
|
66021
|
+
inputPlaceholder: 'Ask Persona to update this page\u2026',
|
|
66022
|
+
},
|
|
66023
|
+
suggestionChips: [
|
|
66024
|
+
'Turn this page green and mark Setup complete.',
|
|
66025
|
+
'What page tools are available?',
|
|
66026
|
+
'Show the embed code.',
|
|
66027
|
+
],
|
|
66028
|
+
features: {
|
|
66029
|
+
showToolCalls: true,
|
|
66030
|
+
showEventStreamToggle: true,
|
|
66031
|
+
suggestReplies: {
|
|
66032
|
+
enabled: true,
|
|
66033
|
+
expose: true,
|
|
66034
|
+
},
|
|
66035
|
+
},
|
|
66036
|
+
webmcp: {
|
|
66037
|
+
enabled: true,
|
|
66038
|
+
autoApprove(info) {
|
|
66039
|
+
const ok = info && info.toolName === 'get_playground_state';
|
|
66040
|
+
logTool('Approval gate', (info ? info.toolName : 'unknown') + (ok ? ' auto-approved' : ' awaiting approval'));
|
|
66041
|
+
return ok;
|
|
66042
|
+
},
|
|
66043
|
+
},
|
|
66044
|
+
},
|
|
66045
|
+
onChatReady(handle) {
|
|
66046
|
+
window.personaPlayground = handle;
|
|
66047
|
+
logTool('Widget ready', 'Persona handle is available at window.personaPlayground');
|
|
66048
|
+
setTimeout(() => {
|
|
66049
|
+
if (handle && typeof handle.open === 'function') handle.open();
|
|
66050
|
+
}, 0);
|
|
66051
|
+
},
|
|
66052
|
+
onError(info) {
|
|
66053
|
+
logTool('Persona error', info && info.phase ? info.phase : 'unknown phase');
|
|
66054
|
+
},
|
|
66055
|
+
};
|
|
66056
|
+
|
|
66057
|
+
document.getElementById('use-persona-widget').addEventListener('click', () => {
|
|
66058
|
+
const handle = window.personaPlayground;
|
|
66059
|
+
if (handle && typeof handle.open === 'function') handle.open();
|
|
66060
|
+
if (handle && typeof handle.setMessage === 'function') {
|
|
66061
|
+
handle.setMessage('Turn this page green and mark Setup complete.');
|
|
66062
|
+
}
|
|
66063
|
+
logTool('CTA', 'Opened Persona widget');
|
|
66064
|
+
});
|
|
66065
|
+
|
|
66066
|
+
render();
|
|
66067
|
+
logTool('Tools connected', 'Registered get_playground_state and update_playground');
|
|
66068
|
+
</script>
|
|
66069
|
+
<!-- 6. Version-pinned Persona installer from @runtypelabs/persona. -->
|
|
66070
|
+
<script src="${escapeHtml(installerScriptUrl)}"></script>
|
|
66071
|
+
</body>
|
|
66072
|
+
</html>`;
|
|
66073
|
+
}
|
|
66074
|
+
function generatePersonaDemoReadme(input) {
|
|
66075
|
+
const port = (() => {
|
|
66076
|
+
try {
|
|
66077
|
+
return new URL(input.localUrl).port || String(PERSONA_DEMO_DEFAULT_PORT);
|
|
66078
|
+
} catch {
|
|
66079
|
+
return String(PERSONA_DEMO_DEFAULT_PORT);
|
|
66080
|
+
}
|
|
66081
|
+
})();
|
|
66082
|
+
return `# Persona Playground
|
|
66083
|
+
|
|
66084
|
+
This folder was generated by \`runtype persona init\`.
|
|
66085
|
+
|
|
66086
|
+
## Next steps
|
|
66087
|
+
|
|
66088
|
+
1. Use the widget: ${input.localUrl}
|
|
66089
|
+
2. Customize your agent: ${input.dashboardUrl}
|
|
66090
|
+
3. Edit the page: ./index.html
|
|
66091
|
+
|
|
66092
|
+
## Run locally
|
|
66093
|
+
|
|
66094
|
+
\`\`\`bash
|
|
66095
|
+
python3 -m http.server ${port} --bind 127.0.0.1
|
|
66096
|
+
\`\`\`
|
|
66097
|
+
|
|
66098
|
+
Then open ${input.localUrl}.
|
|
66099
|
+
|
|
66100
|
+
## What this starter demonstrates
|
|
66101
|
+
|
|
66102
|
+
- \`window.siteAgentConfig\` installs Persona with your client token.
|
|
66103
|
+
- \`document.modelContext\` exposes two local WebMCP tools:
|
|
66104
|
+
- \`get_playground_state\` reads the page state.
|
|
66105
|
+
- \`update_playground\` changes the accent, copy, status, and checklist after approval.
|
|
66106
|
+
- Persona native suggested replies render next-step pills after a successful tool call.
|
|
66107
|
+
|
|
66108
|
+
## Add another page tool
|
|
66109
|
+
|
|
66110
|
+
1. Add a new \`document.modelContext.registerTool({ ... })\` block in \`index.html\`.
|
|
66111
|
+
2. Add the tool name to the WebMCP allowlist for this surface in the Runtype dashboard.
|
|
66112
|
+
3. Refresh the page and ask Persona to use the new tool.
|
|
66113
|
+
|
|
66114
|
+
## Demo resources
|
|
66115
|
+
|
|
66116
|
+
- Agent: ${input.agentId}
|
|
66117
|
+
- Client token: ${input.clientTokenId} (${input.environment})
|
|
66118
|
+
- Allowed origins: ${input.allowedOrigins.join(", ")}
|
|
66119
|
+
`;
|
|
66120
|
+
}
|
|
66121
|
+
|
|
65308
66122
|
// src/commands/persona.ts
|
|
65309
|
-
var FORMAT_CYCLE = [
|
|
65310
|
-
"script-installer",
|
|
65311
|
-
"react",
|
|
65312
|
-
"script-manual",
|
|
65313
|
-
"esm"
|
|
65314
|
-
];
|
|
66123
|
+
var FORMAT_CYCLE = ["script-installer", "react", "script-manual", "esm"];
|
|
65315
66124
|
function defaultTokenName(agentName) {
|
|
65316
66125
|
return `${agentName} Widget`;
|
|
65317
66126
|
}
|
|
66127
|
+
function parsePort(raw, fallback) {
|
|
66128
|
+
if (!raw) return fallback;
|
|
66129
|
+
const port = Number(raw);
|
|
66130
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
66131
|
+
throw new Error(`Invalid port "${raw}". Use a number between 1 and 65535.`);
|
|
66132
|
+
}
|
|
66133
|
+
return port;
|
|
66134
|
+
}
|
|
65318
66135
|
async function promptLine(rl, question, defaultValue) {
|
|
65319
66136
|
const hint = defaultValue ? chalk30.dim(` (${defaultValue})`) : "";
|
|
65320
66137
|
const answer = await new Promise((resolve11) => {
|
|
@@ -65363,7 +66180,16 @@ function snippetWithFormat(format, token, apiUrl, targetSelector) {
|
|
|
65363
66180
|
);
|
|
65364
66181
|
return { format, code };
|
|
65365
66182
|
}
|
|
65366
|
-
|
|
66183
|
+
function printDemoNextSteps(demo, dashboardUrl) {
|
|
66184
|
+
console.log(chalk30.cyan("\nNext steps:"));
|
|
66185
|
+
console.log(` 1. Use the widget: ${chalk30.green(demo.url)}`);
|
|
66186
|
+
console.log(` 2. Customize your agent: ${dashboardUrl}`);
|
|
66187
|
+
console.log(` 3. Edit the page: ${demo.filePath}`);
|
|
66188
|
+
if (demo.readmePath) {
|
|
66189
|
+
console.log(chalk30.dim(` Guide: ${demo.readmePath}`));
|
|
66190
|
+
}
|
|
66191
|
+
}
|
|
66192
|
+
async function runSuccessKeyLoop(initial, apiUrl, targetSelector, demo) {
|
|
65367
66193
|
if (!process.stdin.isTTY) {
|
|
65368
66194
|
return;
|
|
65369
66195
|
}
|
|
@@ -65377,39 +66203,48 @@ async function runSuccessKeyLoop(initial, apiUrl, targetSelector) {
|
|
|
65377
66203
|
console.log(`${chalk30.bold("Snippet format:")} ${currentFormat}`);
|
|
65378
66204
|
console.log(chalk30.dim(`
|
|
65379
66205
|
Dashboard: ${initial.dashboardUrl}`));
|
|
66206
|
+
if (demo) {
|
|
66207
|
+
console.log(`${chalk30.bold("Local demo:")} ${chalk30.green(demo.url)}`);
|
|
66208
|
+
console.log(chalk30.dim(`HTML: ${demo.filePath}`));
|
|
66209
|
+
if (demo.readmePath) {
|
|
66210
|
+
console.log(chalk30.dim(`Guide: ${demo.readmePath}`));
|
|
66211
|
+
}
|
|
66212
|
+
}
|
|
65380
66213
|
if (initial.warnings?.length) {
|
|
65381
66214
|
for (const w of initial.warnings) {
|
|
65382
66215
|
console.log(chalk30.yellow(`\u26A0 ${w.message}`));
|
|
65383
66216
|
}
|
|
65384
66217
|
}
|
|
65385
|
-
|
|
66218
|
+
if (demo) {
|
|
66219
|
+
printDemoNextSteps(demo, initial.dashboardUrl);
|
|
66220
|
+
}
|
|
66221
|
+
console.log(chalk30.cyan("\nActions:"));
|
|
65386
66222
|
console.log(` ${chalk30.green("c")} Copy snippet to clipboard`);
|
|
65387
66223
|
console.log(` ${chalk30.green("p")} Print snippet to the terminal`);
|
|
65388
66224
|
console.log(` ${chalk30.green("f")} Switch snippet format`);
|
|
65389
66225
|
console.log(` ${chalk30.green("o")} Open dashboard in browser`);
|
|
65390
|
-
|
|
65391
|
-
|
|
65392
|
-
if (process.stdin.isTTY) {
|
|
65393
|
-
process.stdin.setRawMode(true);
|
|
66226
|
+
if (demo) {
|
|
66227
|
+
console.log(` ${chalk30.green("d")} Open local demo in browser`);
|
|
65394
66228
|
}
|
|
65395
|
-
|
|
65396
|
-
|
|
65397
|
-
|
|
65398
|
-
|
|
65399
|
-
process.stdin
|
|
65400
|
-
|
|
66229
|
+
console.log(` ${chalk30.green("q")} Quit`);
|
|
66230
|
+
console.log(chalk30.dim("\nType a letter and press Enter. Press Ctrl+C to quit."));
|
|
66231
|
+
const actionKeys = demo ? "c/p/f/o/d/q" : "c/p/f/o/q";
|
|
66232
|
+
const rl = readline3.createInterface({
|
|
66233
|
+
input: process.stdin,
|
|
66234
|
+
output: process.stdout,
|
|
66235
|
+
terminal: true
|
|
66236
|
+
});
|
|
65401
66237
|
await new Promise((resolve11) => {
|
|
65402
|
-
|
|
65403
|
-
|
|
65404
|
-
if (
|
|
65405
|
-
|
|
65406
|
-
|
|
65407
|
-
|
|
65408
|
-
|
|
65409
|
-
|
|
65410
|
-
if (name === "q"
|
|
65411
|
-
|
|
65412
|
-
resolve11();
|
|
66238
|
+
let finished = false;
|
|
66239
|
+
const finish = () => {
|
|
66240
|
+
if (finished) return;
|
|
66241
|
+
finished = true;
|
|
66242
|
+
rl.close();
|
|
66243
|
+
resolve11();
|
|
66244
|
+
};
|
|
66245
|
+
const runAction = async (name) => {
|
|
66246
|
+
if (name === "q") {
|
|
66247
|
+
finish();
|
|
65413
66248
|
return;
|
|
65414
66249
|
}
|
|
65415
66250
|
if (name === "c") {
|
|
@@ -65438,23 +66273,61 @@ Dashboard: ${initial.dashboardUrl}`));
|
|
|
65438
66273
|
}
|
|
65439
66274
|
if (name === "o") {
|
|
65440
66275
|
try {
|
|
65441
|
-
await
|
|
66276
|
+
await openBrowser(initial.dashboardUrl);
|
|
65442
66277
|
} catch {
|
|
65443
66278
|
console.log(chalk30.red("Could not open browser."));
|
|
65444
66279
|
}
|
|
66280
|
+
return;
|
|
65445
66281
|
}
|
|
66282
|
+
if (name === "d" && demo) {
|
|
66283
|
+
try {
|
|
66284
|
+
await openBrowser(demo.url);
|
|
66285
|
+
} catch {
|
|
66286
|
+
console.log(chalk30.red("Could not open browser."));
|
|
66287
|
+
}
|
|
66288
|
+
return;
|
|
66289
|
+
}
|
|
66290
|
+
console.log(chalk30.yellow(`Choose one of: ${actionKeys}`));
|
|
66291
|
+
};
|
|
66292
|
+
const ask = () => {
|
|
66293
|
+
if (finished) return;
|
|
66294
|
+
rl.question(chalk30.dim(`
|
|
66295
|
+
Choose an action (${actionKeys}): `), (answer) => {
|
|
66296
|
+
const names = answer.trim().toLowerCase().split(/[\s,]+/).filter(Boolean).map((part) => part.charAt(0));
|
|
66297
|
+
void (async () => {
|
|
66298
|
+
for (const name of names) {
|
|
66299
|
+
await runAction(name);
|
|
66300
|
+
if (finished) {
|
|
66301
|
+
return;
|
|
66302
|
+
}
|
|
66303
|
+
}
|
|
66304
|
+
if (!finished) {
|
|
66305
|
+
ask();
|
|
66306
|
+
}
|
|
66307
|
+
})();
|
|
66308
|
+
});
|
|
65446
66309
|
};
|
|
65447
|
-
|
|
66310
|
+
rl.on("SIGINT", finish);
|
|
66311
|
+
ask();
|
|
65448
66312
|
});
|
|
65449
66313
|
}
|
|
65450
66314
|
var personaCommand = new Command23("persona").description(
|
|
65451
66315
|
"Set up Persona: create an agent, client token, and embed snippet"
|
|
65452
66316
|
);
|
|
65453
|
-
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(
|
|
66317
|
+
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(
|
|
66318
|
+
"--origins <origins...>",
|
|
66319
|
+
"Allowed origins (default: * \u2014 broad; prefer explicit URLs in production)"
|
|
66320
|
+
).option(
|
|
65454
66321
|
"--format <fmt>",
|
|
65455
66322
|
"Snippet format: script-installer | script-manual | esm | react",
|
|
65456
66323
|
"script-installer"
|
|
65457
|
-
).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("--
|
|
66324
|
+
).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(
|
|
66325
|
+
"--demo-dir <path>",
|
|
66326
|
+
`Directory for the local demo (default: ${PERSONA_DEMO_DEFAULT_DIR})`
|
|
66327
|
+
).option(
|
|
66328
|
+
"--demo-port <port>",
|
|
66329
|
+
`Preferred localhost port for the local demo (default: ${PERSONA_DEMO_DEFAULT_PORT})`
|
|
66330
|
+
).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(
|
|
65458
66331
|
async (options, cmd) => {
|
|
65459
66332
|
const globals = cmd.optsWithGlobals();
|
|
65460
66333
|
const jsonMode = !!(options.json ?? globals.json);
|
|
@@ -65465,7 +66338,9 @@ personaCommand.command("init").description("Create agent + client token and outp
|
|
|
65465
66338
|
} catch (e) {
|
|
65466
66339
|
const msg = e instanceof Error ? e.message : String(e);
|
|
65467
66340
|
if (jsonMode) {
|
|
65468
|
-
console.log(
|
|
66341
|
+
console.log(
|
|
66342
|
+
JSON.stringify({ status: "error", error: msg, code: "INVALID_FORMAT" }, null, 2)
|
|
66343
|
+
);
|
|
65469
66344
|
} else {
|
|
65470
66345
|
console.error(chalk30.red(msg));
|
|
65471
66346
|
}
|
|
@@ -65473,6 +66348,20 @@ personaCommand.command("init").description("Create agent + client token and outp
|
|
|
65473
66348
|
}
|
|
65474
66349
|
const apiUrl = options.apiUrl || globals.apiUrl || getApiUrl();
|
|
65475
66350
|
const targetSelector = options.targetSelector || void 0;
|
|
66351
|
+
let preferredDemoPort;
|
|
66352
|
+
try {
|
|
66353
|
+
preferredDemoPort = parsePort(options.demoPort, PERSONA_DEMO_DEFAULT_PORT);
|
|
66354
|
+
} catch (e) {
|
|
66355
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
66356
|
+
if (jsonMode) {
|
|
66357
|
+
console.log(
|
|
66358
|
+
JSON.stringify({ status: "error", error: msg, code: "INVALID_DEMO_PORT" }, null, 2)
|
|
66359
|
+
);
|
|
66360
|
+
} else {
|
|
66361
|
+
console.error(chalk30.red(msg));
|
|
66362
|
+
}
|
|
66363
|
+
process.exit(1);
|
|
66364
|
+
}
|
|
65476
66365
|
let env;
|
|
65477
66366
|
if (options.environment === "test" || options.environment === "live") {
|
|
65478
66367
|
env = options.environment;
|
|
@@ -65490,12 +66379,20 @@ personaCommand.command("init").description("Create agent + client token and outp
|
|
|
65490
66379
|
let tokenName = options.tokenName?.trim();
|
|
65491
66380
|
let allowedOrigins = options.origins;
|
|
65492
66381
|
let chosenEnv = env;
|
|
66382
|
+
let demoRequested = options.demo === true;
|
|
66383
|
+
let demoDirectory;
|
|
66384
|
+
let demoPort;
|
|
66385
|
+
let demoOrigins;
|
|
66386
|
+
let demoLocalUrl;
|
|
66387
|
+
let forceDemoWrite = !!options.force;
|
|
65493
66388
|
const rl = interactive && process.stdin.isTTY && process.stdout.isTTY ? readline3.createInterface({ input: process.stdin, output: process.stdout }) : null;
|
|
65494
66389
|
if (!interactive) {
|
|
65495
66390
|
if (!agentName) {
|
|
65496
66391
|
const msg = "Non-interactive mode requires --agent-name";
|
|
65497
66392
|
if (jsonMode) {
|
|
65498
|
-
console.log(
|
|
66393
|
+
console.log(
|
|
66394
|
+
JSON.stringify({ status: "error", error: msg, code: "MISSING_AGENT_NAME" }, null, 2)
|
|
66395
|
+
);
|
|
65499
66396
|
} else {
|
|
65500
66397
|
console.error(chalk30.red(msg));
|
|
65501
66398
|
}
|
|
@@ -65522,20 +66419,52 @@ personaCommand.command("init").description("Create agent + client token and outp
|
|
|
65522
66419
|
tokenName = def;
|
|
65523
66420
|
}
|
|
65524
66421
|
}
|
|
66422
|
+
if (options.demo === void 0 && !options.yes) {
|
|
66423
|
+
demoRequested = await promptConfirm2(
|
|
66424
|
+
rl,
|
|
66425
|
+
"Create and open a local Persona Playground HTML demo?",
|
|
66426
|
+
true
|
|
66427
|
+
);
|
|
66428
|
+
} else if (options.demo === void 0 && options.yes) {
|
|
66429
|
+
demoRequested = true;
|
|
66430
|
+
}
|
|
66431
|
+
if (demoRequested) {
|
|
66432
|
+
demoDirectory = resolvePersonaDemoDirectory(options.demoDir);
|
|
66433
|
+
try {
|
|
66434
|
+
ensurePersonaDemoCanWrite(demoDirectory, forceDemoWrite);
|
|
66435
|
+
} catch (e) {
|
|
66436
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
66437
|
+
const ok = await promptConfirm2(rl, `${message} Overwrite it?`, false);
|
|
66438
|
+
if (!ok) {
|
|
66439
|
+
console.log(chalk30.gray("Aborted."));
|
|
66440
|
+
rl.close();
|
|
66441
|
+
process.exit(0);
|
|
66442
|
+
}
|
|
66443
|
+
forceDemoWrite = true;
|
|
66444
|
+
}
|
|
66445
|
+
demoPort = await findAvailablePersonaDemoPort(preferredDemoPort);
|
|
66446
|
+
demoOrigins = buildPersonaDemoOrigins(demoPort);
|
|
66447
|
+
demoLocalUrl = `http://127.0.0.1:${demoPort}/`;
|
|
66448
|
+
}
|
|
65525
66449
|
if (!allowedOrigins?.length) {
|
|
66450
|
+
const defaultOrigins = demoOrigins?.join(" ") ?? "*";
|
|
65526
66451
|
if (options.yes) {
|
|
65527
|
-
allowedOrigins = ["*"];
|
|
66452
|
+
allowedOrigins = demoOrigins ?? ["*"];
|
|
65528
66453
|
} else {
|
|
65529
66454
|
const originsInput = await promptLine(
|
|
65530
66455
|
rl,
|
|
65531
66456
|
"Allowed origins (space-separated URLs, or * for any)",
|
|
65532
|
-
|
|
66457
|
+
defaultOrigins
|
|
65533
66458
|
);
|
|
65534
66459
|
allowedOrigins = originsInput === "*" ? ["*"] : originsInput.split(/\s+/).filter(Boolean);
|
|
65535
66460
|
}
|
|
65536
66461
|
}
|
|
65537
66462
|
if (chosenEnv === "live") {
|
|
65538
|
-
const ok = await promptConfirm2(
|
|
66463
|
+
const ok = await promptConfirm2(
|
|
66464
|
+
rl,
|
|
66465
|
+
chalk30.yellow("Create a LIVE token? This is shown only once."),
|
|
66466
|
+
false
|
|
66467
|
+
);
|
|
65539
66468
|
if (!ok) {
|
|
65540
66469
|
console.log(chalk30.gray("Aborted."));
|
|
65541
66470
|
rl.close();
|
|
@@ -65553,6 +66482,28 @@ personaCommand.command("init").description("Create agent + client token and outp
|
|
|
65553
66482
|
}
|
|
65554
66483
|
}
|
|
65555
66484
|
}
|
|
66485
|
+
if (demoRequested && !demoDirectory) {
|
|
66486
|
+
demoDirectory = resolvePersonaDemoDirectory(options.demoDir);
|
|
66487
|
+
try {
|
|
66488
|
+
ensurePersonaDemoCanWrite(demoDirectory, forceDemoWrite);
|
|
66489
|
+
} catch (e) {
|
|
66490
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
66491
|
+
if (jsonMode) {
|
|
66492
|
+
console.log(
|
|
66493
|
+
JSON.stringify({ status: "error", error: message, code: "DEMO_EXISTS" }, null, 2)
|
|
66494
|
+
);
|
|
66495
|
+
} else {
|
|
66496
|
+
console.error(chalk30.red(message));
|
|
66497
|
+
}
|
|
66498
|
+
process.exit(1);
|
|
66499
|
+
}
|
|
66500
|
+
demoPort = await findAvailablePersonaDemoPort(preferredDemoPort);
|
|
66501
|
+
demoOrigins = buildPersonaDemoOrigins(demoPort);
|
|
66502
|
+
demoLocalUrl = `http://127.0.0.1:${demoPort}/`;
|
|
66503
|
+
}
|
|
66504
|
+
if (demoRequested && demoOrigins) {
|
|
66505
|
+
allowedOrigins = mergePersonaDemoAllowedOrigins(allowedOrigins, demoOrigins);
|
|
66506
|
+
}
|
|
65556
66507
|
if (rl) {
|
|
65557
66508
|
rl.close();
|
|
65558
66509
|
}
|
|
@@ -65604,45 +66555,155 @@ personaCommand.command("init").description("Create agent + client token and outp
|
|
|
65604
66555
|
environment: chosenEnv,
|
|
65605
66556
|
allowedOrigins,
|
|
65606
66557
|
format: formatCli,
|
|
65607
|
-
targetSelector
|
|
66558
|
+
targetSelector,
|
|
66559
|
+
...demoRequested && demoOrigins ? { demo: { origins: demoOrigins, toolNames: [...PERSONA_DEMO_TOOL_NAMES] } } : {}
|
|
65608
66560
|
});
|
|
65609
66561
|
} catch (err) {
|
|
65610
66562
|
const message = err instanceof Error ? err.message : String(err);
|
|
65611
66563
|
if (jsonMode) {
|
|
65612
|
-
console.log(
|
|
66564
|
+
console.log(
|
|
66565
|
+
JSON.stringify({ status: "error", error: message, code: "API_ERROR" }, null, 2)
|
|
66566
|
+
);
|
|
65613
66567
|
} else {
|
|
65614
66568
|
console.error(chalk30.red("Persona init failed"));
|
|
65615
66569
|
console.error(chalk30.red(message));
|
|
65616
66570
|
}
|
|
65617
66571
|
process.exit(1);
|
|
65618
66572
|
}
|
|
66573
|
+
let demoOutput;
|
|
66574
|
+
let demoServer;
|
|
66575
|
+
if (demoRequested && demoDirectory && demoPort && demoOrigins && demoLocalUrl) {
|
|
66576
|
+
const html = generatePersonaDemoHtml({
|
|
66577
|
+
apiUrl,
|
|
66578
|
+
clientToken: success2.clientToken.token,
|
|
66579
|
+
clientTokenId: success2.clientToken.id,
|
|
66580
|
+
agentId: success2.agent.id,
|
|
66581
|
+
agentName: success2.agent.name,
|
|
66582
|
+
dashboardUrl: success2.dashboardUrl,
|
|
66583
|
+
environment: success2.clientToken.environment,
|
|
66584
|
+
localUrl: demoLocalUrl,
|
|
66585
|
+
allowedOrigins: demoOrigins
|
|
66586
|
+
});
|
|
66587
|
+
const readme2 = generatePersonaDemoReadme({
|
|
66588
|
+
apiUrl,
|
|
66589
|
+
clientToken: success2.clientToken.token,
|
|
66590
|
+
clientTokenId: success2.clientToken.id,
|
|
66591
|
+
agentId: success2.agent.id,
|
|
66592
|
+
agentName: success2.agent.name,
|
|
66593
|
+
dashboardUrl: success2.dashboardUrl,
|
|
66594
|
+
environment: success2.clientToken.environment,
|
|
66595
|
+
localUrl: demoLocalUrl,
|
|
66596
|
+
allowedOrigins: demoOrigins
|
|
66597
|
+
});
|
|
66598
|
+
const writeResult = writePersonaDemoPage({
|
|
66599
|
+
directory: demoDirectory,
|
|
66600
|
+
html,
|
|
66601
|
+
readme: readme2,
|
|
66602
|
+
force: forceDemoWrite
|
|
66603
|
+
});
|
|
66604
|
+
demoOutput = {
|
|
66605
|
+
...writeResult,
|
|
66606
|
+
localUrl: demoLocalUrl,
|
|
66607
|
+
port: demoPort,
|
|
66608
|
+
allowedOrigins: demoOrigins,
|
|
66609
|
+
serverRunning: false
|
|
66610
|
+
};
|
|
66611
|
+
const shouldLaunchDemo = !jsonMode && options.open !== false && (interactive || options.open === true);
|
|
66612
|
+
if (shouldLaunchDemo) {
|
|
66613
|
+
try {
|
|
66614
|
+
demoServer = await startPersonaDemoServer({
|
|
66615
|
+
directory: demoDirectory,
|
|
66616
|
+
port: demoPort
|
|
66617
|
+
});
|
|
66618
|
+
demoOutput.serverRunning = true;
|
|
66619
|
+
demoOutput.localUrl = demoServer.url;
|
|
66620
|
+
await openBrowser(demoServer.url);
|
|
66621
|
+
} catch (e) {
|
|
66622
|
+
demoOutput.serverError = e instanceof Error ? e.message : String(e);
|
|
66623
|
+
if (!jsonMode) {
|
|
66624
|
+
console.log(
|
|
66625
|
+
chalk30.yellow(`Could not start/open local demo server: ${demoOutput.serverError}`)
|
|
66626
|
+
);
|
|
66627
|
+
}
|
|
66628
|
+
}
|
|
66629
|
+
}
|
|
66630
|
+
}
|
|
66631
|
+
const output = demoOutput ? {
|
|
66632
|
+
...success2,
|
|
66633
|
+
demo: {
|
|
66634
|
+
...success2.demo,
|
|
66635
|
+
...demoOutput
|
|
66636
|
+
}
|
|
66637
|
+
} : success2;
|
|
65619
66638
|
if (jsonMode) {
|
|
65620
|
-
printJson(
|
|
66639
|
+
printJson(output);
|
|
65621
66640
|
return;
|
|
65622
66641
|
}
|
|
65623
66642
|
if (!tty || options.printSnippet) {
|
|
65624
66643
|
console.log(chalk30.green("\nPersona setup complete\n"));
|
|
65625
|
-
console.log(`${chalk30.bold("Agent ID:")} ${
|
|
65626
|
-
console.log(`${chalk30.bold("Client Token ID:")} ${
|
|
65627
|
-
console.log(`${chalk30.bold("Client Token:")} ${chalk30.yellow(
|
|
65628
|
-
console.log(`${chalk30.bold("Format:")} ${
|
|
66644
|
+
console.log(`${chalk30.bold("Agent ID:")} ${output.agent.id}`);
|
|
66645
|
+
console.log(`${chalk30.bold("Client Token ID:")} ${output.clientToken.id}`);
|
|
66646
|
+
console.log(`${chalk30.bold("Client Token:")} ${chalk30.yellow(output.clientToken.token)}`);
|
|
66647
|
+
console.log(`${chalk30.bold("Format:")} ${output.snippet.format}`);
|
|
65629
66648
|
console.log(chalk30.dim(`
|
|
65630
|
-
Dashboard: ${
|
|
66649
|
+
Dashboard: ${output.dashboardUrl}`));
|
|
66650
|
+
if (demoOutput) {
|
|
66651
|
+
console.log(`${chalk30.bold("Demo HTML:")} ${demoOutput.filePath}`);
|
|
66652
|
+
console.log(`${chalk30.bold("Demo README:")} ${demoOutput.readmePath}`);
|
|
66653
|
+
console.log(`${chalk30.bold("Demo URL:")} ${chalk30.green(demoOutput.localUrl)}`);
|
|
66654
|
+
if (demoOutput.serverRunning) {
|
|
66655
|
+
console.log(chalk30.dim("Local demo server is running. Press Ctrl+C to stop it."));
|
|
66656
|
+
} else {
|
|
66657
|
+
console.log(
|
|
66658
|
+
chalk30.dim(
|
|
66659
|
+
`Run: cd ${demoOutput.directory} && python3 -m http.server ${demoOutput.port} --bind 127.0.0.1`
|
|
66660
|
+
)
|
|
66661
|
+
);
|
|
66662
|
+
}
|
|
66663
|
+
printDemoNextSteps(
|
|
66664
|
+
{
|
|
66665
|
+
url: demoOutput.localUrl,
|
|
66666
|
+
filePath: demoOutput.filePath,
|
|
66667
|
+
readmePath: demoOutput.readmePath
|
|
66668
|
+
},
|
|
66669
|
+
output.dashboardUrl
|
|
66670
|
+
);
|
|
66671
|
+
}
|
|
65631
66672
|
if (success2.warnings?.length) {
|
|
65632
66673
|
for (const w of success2.warnings) {
|
|
65633
66674
|
console.log(chalk30.yellow(`\u26A0 ${w.message}`));
|
|
65634
66675
|
}
|
|
65635
66676
|
}
|
|
65636
|
-
|
|
66677
|
+
if (!demoOutput) {
|
|
66678
|
+
console.log(chalk30.cyan("\nRecommended next step: npm install @runtypelabs/persona"));
|
|
66679
|
+
}
|
|
65637
66680
|
if (options.printSnippet) {
|
|
65638
66681
|
console.log(chalk30.cyan("\n--- snippet ---\n"));
|
|
65639
66682
|
console.log(success2.snippet.code);
|
|
65640
66683
|
} else {
|
|
65641
|
-
console.log(
|
|
66684
|
+
console.log(
|
|
66685
|
+
chalk30.dim(
|
|
66686
|
+
"\nUse --print-snippet to print the embed code, or run interactively for copy shortcuts."
|
|
66687
|
+
)
|
|
66688
|
+
);
|
|
65642
66689
|
}
|
|
65643
66690
|
return;
|
|
65644
66691
|
}
|
|
65645
|
-
|
|
66692
|
+
try {
|
|
66693
|
+
await runSuccessKeyLoop(
|
|
66694
|
+
success2,
|
|
66695
|
+
apiUrl,
|
|
66696
|
+
targetSelector,
|
|
66697
|
+
demoOutput ? {
|
|
66698
|
+
url: demoOutput.localUrl,
|
|
66699
|
+
filePath: demoOutput.filePath,
|
|
66700
|
+
readmePath: demoOutput.readmePath
|
|
66701
|
+
} : void 0
|
|
66702
|
+
);
|
|
66703
|
+
} finally {
|
|
66704
|
+
await demoServer?.close().catch(() => {
|
|
66705
|
+
});
|
|
66706
|
+
}
|
|
65646
66707
|
}
|
|
65647
66708
|
);
|
|
65648
66709
|
|
|
@@ -65814,7 +66875,7 @@ import chalk32 from "chalk";
|
|
|
65814
66875
|
import React23 from "react";
|
|
65815
66876
|
import { render as render23 } from "ink";
|
|
65816
66877
|
import { useState as useState40, useEffect as useEffect34 } from "react";
|
|
65817
|
-
import
|
|
66878
|
+
import open5 from "open";
|
|
65818
66879
|
var billingCommand = new Command25("billing").description("View billing and subscription info");
|
|
65819
66880
|
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) => {
|
|
65820
66881
|
const apiKey = await ensureAuth();
|
|
@@ -65917,7 +66978,7 @@ billingCommand.command("portal").description("Open the billing portal in your br
|
|
|
65917
66978
|
if (data.url) {
|
|
65918
66979
|
console.log("Opening billing portal...");
|
|
65919
66980
|
console.log(data.url);
|
|
65920
|
-
await
|
|
66981
|
+
await open5(data.url);
|
|
65921
66982
|
} else {
|
|
65922
66983
|
console.log("No portal URL returned. You may need to set up billing first.");
|
|
65923
66984
|
}
|
|
@@ -65939,7 +67000,7 @@ billingCommand.command("portal").description("Open the billing portal in your br
|
|
|
65939
67000
|
try {
|
|
65940
67001
|
const data = await client.post("/billing/portal");
|
|
65941
67002
|
if (data.url) {
|
|
65942
|
-
await
|
|
67003
|
+
await open5(data.url);
|
|
65943
67004
|
setMsg("Billing portal opened in browser");
|
|
65944
67005
|
setSuccess(true);
|
|
65945
67006
|
} else {
|
|
@@ -66789,7 +67850,7 @@ var tailCommand = new Command28("tail").description("Stream live execution logs
|
|
|
66789
67850
|
// src/commands/validate-product.ts
|
|
66790
67851
|
import { Command as Command29, Option } from "commander";
|
|
66791
67852
|
import chalk36 from "chalk";
|
|
66792
|
-
import { readFileSync as
|
|
67853
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
66793
67854
|
function createValidateProductCommand() {
|
|
66794
67855
|
return new Command29("validate-product").description("Validate a product (FPO) or FPO template locally (no API call)").argument(
|
|
66795
67856
|
"[input]",
|
|
@@ -66869,7 +67930,7 @@ async function readInput(input) {
|
|
|
66869
67930
|
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
66870
67931
|
return trimmed;
|
|
66871
67932
|
}
|
|
66872
|
-
return
|
|
67933
|
+
return readFileSync18(input, "utf-8");
|
|
66873
67934
|
}
|
|
66874
67935
|
async function readStdin() {
|
|
66875
67936
|
if (process.stdin.isTTY) {
|
|
@@ -66972,7 +68033,7 @@ function printIssues(title, issues, color) {
|
|
|
66972
68033
|
import { Command as Command30 } from "commander";
|
|
66973
68034
|
import chalk37 from "chalk";
|
|
66974
68035
|
import * as fs16 from "fs";
|
|
66975
|
-
import * as
|
|
68036
|
+
import * as path17 from "path";
|
|
66976
68037
|
import { RuntypeApiError as RuntypeApiError4 } from "@runtypelabs/sdk";
|
|
66977
68038
|
function bashSingleQuote(s) {
|
|
66978
68039
|
return "'" + s.replace(/'/g, "'\\''") + "'";
|
|
@@ -67942,8 +69003,8 @@ var deployCommand = new Command30("deploy").description("Export an agent or flow
|
|
|
67942
69003
|
const apiKey = await ensureAuth();
|
|
67943
69004
|
if (!apiKey) return;
|
|
67944
69005
|
const client = createCliClient(apiKey);
|
|
67945
|
-
const outDir =
|
|
67946
|
-
const projectName = options.name ?? slugify2(
|
|
69006
|
+
const outDir = path17.resolve(options.output);
|
|
69007
|
+
const projectName = options.name ?? slugify2(path17.basename(outDir));
|
|
67947
69008
|
console.log(chalk37.cyan(`
|
|
67948
69009
|
Scaffolding ${target} deployment to ${outDir}
|
|
67949
69010
|
`));
|
|
@@ -68008,18 +69069,18 @@ Scaffolding ${target} deployment to ${outDir}
|
|
|
68008
69069
|
}
|
|
68009
69070
|
slugSet.add(slug);
|
|
68010
69071
|
}
|
|
68011
|
-
fs16.mkdirSync(
|
|
68012
|
-
fs16.mkdirSync(
|
|
69072
|
+
fs16.mkdirSync(path17.join(outDir, "agents"), { recursive: true });
|
|
69073
|
+
fs16.mkdirSync(path17.join(outDir, "packages"), { recursive: true });
|
|
68013
69074
|
for (const { name, def } of agentDefs) {
|
|
68014
69075
|
const filename = `${slugify2(name)}.json`;
|
|
68015
|
-
fs16.writeFileSync(
|
|
69076
|
+
fs16.writeFileSync(path17.join(outDir, "agents", filename), JSON.stringify(def, null, 2));
|
|
68016
69077
|
console.log(` Wrote agents/${filename}`);
|
|
68017
69078
|
}
|
|
68018
69079
|
const agentNames = agentDefs.map((a) => a.name);
|
|
68019
69080
|
let monorepoRoot = process.cwd();
|
|
68020
69081
|
for (let i = 0; i < 8; i++) {
|
|
68021
|
-
if (fs16.existsSync(
|
|
68022
|
-
const parent =
|
|
69082
|
+
if (fs16.existsSync(path17.join(monorepoRoot, "pnpm-workspace.yaml"))) break;
|
|
69083
|
+
const parent = path17.dirname(monorepoRoot);
|
|
68023
69084
|
if (parent === monorepoRoot) break;
|
|
68024
69085
|
monorepoRoot = parent;
|
|
68025
69086
|
}
|
|
@@ -68029,35 +69090,35 @@ Scaffolding ${target} deployment to ${outDir}
|
|
|
68029
69090
|
}
|
|
68030
69091
|
const secretNames = Array.from(allSecrets);
|
|
68031
69092
|
if (target === "cloudflare") {
|
|
68032
|
-
fs16.mkdirSync(
|
|
68033
|
-
fs16.writeFileSync(
|
|
68034
|
-
fs16.writeFileSync(
|
|
68035
|
-
fs16.writeFileSync(
|
|
68036
|
-
fs16.writeFileSync(
|
|
68037
|
-
const setupPath =
|
|
69093
|
+
fs16.mkdirSync(path17.join(outDir, "src"), { recursive: true });
|
|
69094
|
+
fs16.writeFileSync(path17.join(outDir, "src", "index.ts"), workerIndexTs(agentSlugs));
|
|
69095
|
+
fs16.writeFileSync(path17.join(outDir, "wrangler.toml"), wranglerToml(projectName));
|
|
69096
|
+
fs16.writeFileSync(path17.join(outDir, "package.json"), workerPackageJson(projectName, "workspace:*"));
|
|
69097
|
+
fs16.writeFileSync(path17.join(outDir, "tsconfig.json"), workerTsconfigJson());
|
|
69098
|
+
const setupPath = path17.join(outDir, "setup.sh");
|
|
68038
69099
|
fs16.writeFileSync(setupPath, workerSetupSh(monorepoRoot));
|
|
68039
69100
|
fs16.chmodSync(setupPath, 493);
|
|
68040
|
-
fs16.writeFileSync(
|
|
69101
|
+
fs16.writeFileSync(path17.join(outDir, "README.md"), workerReadme(agentNames, secretNames));
|
|
68041
69102
|
} else if (target === "vercel") {
|
|
68042
|
-
fs16.mkdirSync(
|
|
68043
|
-
fs16.writeFileSync(
|
|
68044
|
-
fs16.writeFileSync(
|
|
68045
|
-
fs16.writeFileSync(
|
|
68046
|
-
fs16.writeFileSync(
|
|
68047
|
-
const setupPath =
|
|
69103
|
+
fs16.mkdirSync(path17.join(outDir, "api"), { recursive: true });
|
|
69104
|
+
fs16.writeFileSync(path17.join(outDir, "api", "[[...route]].ts"), vercelRouteTs(agentSlugs));
|
|
69105
|
+
fs16.writeFileSync(path17.join(outDir, "vercel.json"), vercelJson());
|
|
69106
|
+
fs16.writeFileSync(path17.join(outDir, "package.json"), vercelPackageJson(projectName, "workspace:*"));
|
|
69107
|
+
fs16.writeFileSync(path17.join(outDir, "tsconfig.json"), vercelTsconfigJson());
|
|
69108
|
+
const setupPath = path17.join(outDir, "setup.sh");
|
|
68048
69109
|
fs16.writeFileSync(setupPath, vercelSetupSh(monorepoRoot));
|
|
68049
69110
|
fs16.chmodSync(setupPath, 493);
|
|
68050
|
-
fs16.writeFileSync(
|
|
69111
|
+
fs16.writeFileSync(path17.join(outDir, "README.md"), vercelReadme(agentNames, secretNames));
|
|
68051
69112
|
} else {
|
|
68052
|
-
fs16.writeFileSync(
|
|
68053
|
-
fs16.writeFileSync(
|
|
68054
|
-
fs16.writeFileSync(
|
|
68055
|
-
fs16.writeFileSync(
|
|
68056
|
-
fs16.writeFileSync(
|
|
68057
|
-
const setupPath =
|
|
69113
|
+
fs16.writeFileSync(path17.join(outDir, "server.ts"), serverTs());
|
|
69114
|
+
fs16.writeFileSync(path17.join(outDir, "Dockerfile"), dockerfile());
|
|
69115
|
+
fs16.writeFileSync(path17.join(outDir, ".dockerignore"), dockerignore());
|
|
69116
|
+
fs16.writeFileSync(path17.join(outDir, "tsconfig.json"), tsconfigJson());
|
|
69117
|
+
fs16.writeFileSync(path17.join(outDir, "package.json"), packageJson(projectName, "workspace:*"));
|
|
69118
|
+
const setupPath = path17.join(outDir, "setup.sh");
|
|
68058
69119
|
fs16.writeFileSync(setupPath, setupSh(monorepoRoot));
|
|
68059
69120
|
fs16.chmodSync(setupPath, 493);
|
|
68060
|
-
fs16.writeFileSync(
|
|
69121
|
+
fs16.writeFileSync(path17.join(outDir, "README.md"), readme(agentNames, secretNames));
|
|
68061
69122
|
}
|
|
68062
69123
|
console.log("");
|
|
68063
69124
|
console.log(chalk37.green(`\u2713 Scaffold written to ${outDir}`));
|
|
@@ -68115,19 +69176,19 @@ import { Command as Command31 } from "commander";
|
|
|
68115
69176
|
import chalk39 from "chalk";
|
|
68116
69177
|
|
|
68117
69178
|
// src/lib/skills-install.ts
|
|
68118
|
-
import { mkdirSync as
|
|
68119
|
-
import
|
|
69179
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync8 } from "fs";
|
|
69180
|
+
import path18 from "path";
|
|
68120
69181
|
import readline4 from "readline";
|
|
68121
69182
|
import chalk38 from "chalk";
|
|
68122
69183
|
var SKILLS_REPO = "runtypelabs/skills";
|
|
68123
69184
|
var SKILLS_INSTALL_RETRY_HINT = "Retry with `runtype skills install`, or install manually: npx skills add runtypelabs/skills";
|
|
68124
69185
|
var METADATA_FILENAME = "agents-skills-install.json";
|
|
68125
69186
|
function metadataPath() {
|
|
68126
|
-
return
|
|
69187
|
+
return path18.join(getRuntypeHomeDir(), METADATA_FILENAME);
|
|
68127
69188
|
}
|
|
68128
69189
|
function readSkillsInstallMetadata() {
|
|
68129
69190
|
try {
|
|
68130
|
-
const raw =
|
|
69191
|
+
const raw = readFileSync19(metadataPath(), "utf8");
|
|
68131
69192
|
const parsed = JSON.parse(raw);
|
|
68132
69193
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && parsed.version === 1 && typeof parsed.accepted === "boolean") {
|
|
68133
69194
|
return parsed;
|
|
@@ -68139,8 +69200,8 @@ function readSkillsInstallMetadata() {
|
|
|
68139
69200
|
}
|
|
68140
69201
|
function writeSkillsInstallMetadata(metadata) {
|
|
68141
69202
|
try {
|
|
68142
|
-
|
|
68143
|
-
|
|
69203
|
+
mkdirSync10(path18.dirname(metadataPath()), { recursive: true });
|
|
69204
|
+
writeFileSync8(metadataPath(), JSON.stringify(metadata, null, 2));
|
|
68144
69205
|
} catch {
|
|
68145
69206
|
}
|
|
68146
69207
|
}
|
|
@@ -68396,7 +69457,7 @@ skillsCommand.command("install").description(`Install Runtype skills (${SKILLS_R
|
|
|
68396
69457
|
);
|
|
68397
69458
|
|
|
68398
69459
|
// src/commands/apps.ts
|
|
68399
|
-
import { readdirSync as readdirSync6, readFileSync as
|
|
69460
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync20, lstatSync, statSync as statSync7, existsSync as existsSync15 } from "fs";
|
|
68400
69461
|
import { join as join12, relative as relative5 } from "path";
|
|
68401
69462
|
import { Command as Command32 } from "commander";
|
|
68402
69463
|
import chalk40 from "chalk";
|
|
@@ -68417,7 +69478,7 @@ function collectBundleFiles(dir) {
|
|
|
68417
69478
|
if (entry === "node_modules") continue;
|
|
68418
69479
|
walk(full);
|
|
68419
69480
|
} else {
|
|
68420
|
-
zippable[relative5(dir, full).split("\\").join("/")] =
|
|
69481
|
+
zippable[relative5(dir, full).split("\\").join("/")] = readFileSync20(full);
|
|
68421
69482
|
}
|
|
68422
69483
|
}
|
|
68423
69484
|
};
|
|
@@ -68498,7 +69559,7 @@ appsCommand.command("deploy <dir>").description("Zip a bundle directory, upload
|
|
|
68498
69559
|
const jsonMode = !!(options.json ?? globals.json);
|
|
68499
69560
|
const apiKey = await ensureAuth();
|
|
68500
69561
|
if (!apiKey) return;
|
|
68501
|
-
if (!
|
|
69562
|
+
if (!existsSync15(dir) || !statSync7(dir).isDirectory()) {
|
|
68502
69563
|
fail(`Not a directory: ${dir}`, jsonMode, "INVALID_DIR");
|
|
68503
69564
|
}
|
|
68504
69565
|
let bundleFiles = {};
|