@adminide-stack/yantra-mobile 12.0.142 → 12.0.145-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/features/attachments/displayUserMessageText.js +2 -2
- package/lib/features/attachments/displayUserMessageText.js.map +1 -1
- package/lib/features/devices/readings.js.map +1 -1
- package/lib/features/devices/session.js +2 -22
- package/lib/features/devices/session.js.map +1 -1
- package/lib/features/notion/NotionAgentPanel.js +987 -0
- package/lib/features/notion/NotionAgentPanel.js.map +1 -0
- package/lib/features/notion/NotionAskAiSheet.js +362 -0
- package/lib/features/notion/NotionAskAiSheet.js.map +1 -0
- package/lib/features/notion/NotionBlockView.js +4 -3
- package/lib/features/notion/NotionBlockView.js.map +1 -1
- package/lib/features/notion/NotionConnectionsSheet.js +47 -13
- package/lib/features/notion/NotionConnectionsSheet.js.map +1 -1
- package/lib/features/notion/NotionPageView.js +68 -8
- package/lib/features/notion/NotionPageView.js.map +1 -1
- package/lib/features/notion/NotionSidebarSections.js +1 -1
- package/lib/features/notion/NotionSidebarSections.js.map +1 -1
- package/lib/features/notion/NotionWorkspaceView.js +14 -9
- package/lib/features/notion/NotionWorkspaceView.js.map +1 -1
- package/lib/features/notion/database/DatabaseCells.js +3 -1
- package/lib/features/notion/database/DatabaseCells.js.map +1 -1
- package/lib/features/notion/database/DatabaseDateLayouts.js +1 -1
- package/lib/features/notion/database/DatabaseDateLayouts.js.map +1 -1
- package/lib/features/notion/database/NotionDatabaseView.js +1 -1
- package/lib/features/notion/database/NotionDatabaseView.js.map +1 -1
- package/lib/features/notion/notionAgentRunStatus.js +2 -2
- package/lib/features/notion/notionAgentRunStatus.js.map +1 -1
- package/lib/features/notion/notionAgentRuns.js +57 -0
- package/lib/features/notion/notionAgentRuns.js.map +1 -0
- package/lib/features/notion/notionAiContext.js +91 -0
- package/lib/features/notion/notionAiContext.js.map +1 -0
- package/lib/features/notion/notionConnections.js +42 -4
- package/lib/features/notion/notionConnections.js.map +1 -1
- package/lib/features/notion/notionDocuments.js +61 -1
- package/lib/features/notion/notionDocuments.js.map +1 -1
- package/lib/features/notion/notionNotesAgent.js +173 -3
- package/lib/features/notion/notionNotesAgent.js.map +1 -1
- package/lib/features/notion/notionPageKinds.js +1 -1
- package/lib/features/webbuilder/WebBuilderExperience.js +229 -97
- package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
- package/lib/features/webbuilder/buildFragments.js +33 -7
- package/lib/features/webbuilder/buildFragments.js.map +1 -1
- package/lib/features/webbuilder/buildJob.js +2 -2
- package/lib/features/webbuilder/buildJob.js.map +1 -1
- package/lib/features/webbuilder/codeFiles.js +18 -1
- package/lib/features/webbuilder/codeFiles.js.map +1 -1
- package/lib/features/webbuilder/components/BottomTabs.js.map +1 -1
- package/lib/features/webbuilder/components/CodeView.js +134 -56
- package/lib/features/webbuilder/components/CodeView.js.map +1 -1
- package/lib/features/webbuilder/components/Composer.js +2 -2
- package/lib/features/webbuilder/components/Composer.js.map +1 -1
- package/lib/features/webbuilder/components/PreviewFrame.js +19 -3
- package/lib/features/webbuilder/components/PreviewFrame.js.map +1 -1
- package/lib/features/webbuilder/components/PreviewScreen.js +310 -46
- package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -1
- package/lib/features/webbuilder/components/ProjectChat.js +141 -12
- package/lib/features/webbuilder/components/ProjectChat.js.map +1 -1
- package/lib/features/webbuilder/components/ProjectSheets.js +792 -0
- package/lib/features/webbuilder/components/ProjectSheets.js.map +1 -0
- package/lib/features/webbuilder/components/ProjectsScreen.js +14 -2
- package/lib/features/webbuilder/components/ProjectsScreen.js.map +1 -1
- package/lib/features/webbuilder/components/PublishSheet.js +914 -58
- package/lib/features/webbuilder/components/PublishSheet.js.map +1 -1
- package/lib/features/webbuilder/components/TemplateCard.js +9 -6
- package/lib/features/webbuilder/components/TemplateCard.js.map +1 -1
- package/lib/features/webbuilder/components/TemplatesSheet.js +5 -17
- package/lib/features/webbuilder/components/TemplatesSheet.js.map +1 -1
- package/lib/features/webbuilder/connectorTemplates.js +171 -0
- package/lib/features/webbuilder/connectorTemplates.js.map +1 -0
- package/lib/features/webbuilder/fileTree.js +163 -0
- package/lib/features/webbuilder/fileTree.js.map +1 -0
- package/lib/features/webbuilder/followUps.js +67 -0
- package/lib/features/webbuilder/followUps.js.map +1 -0
- package/lib/features/webbuilder/previewProbe.js +49 -0
- package/lib/features/webbuilder/previewProbe.js.map +1 -0
- package/lib/features/webbuilder/previewRoutes.js +156 -0
- package/lib/features/webbuilder/previewRoutes.js.map +1 -0
- package/lib/features/webbuilder/projectTools.js +341 -0
- package/lib/features/webbuilder/projectTools.js.map +1 -0
- package/lib/features/webbuilder/publishTools.js +475 -0
- package/lib/features/webbuilder/publishTools.js.map +1 -0
- package/lib/features/webbuilder/sleepNotice.js +13 -0
- package/lib/features/webbuilder/sleepNotice.js.map +1 -0
- package/lib/features/webbuilder/stepLabels.js +37 -7
- package/lib/features/webbuilder/stepLabels.js.map +1 -1
- package/lib/features/webbuilder/studioCatalog.js +5 -1
- package/lib/features/webbuilder/studioCatalog.js.map +1 -1
- package/lib/features/webbuilder/templateCatalog.js +140 -0
- package/lib/features/webbuilder/templateCatalog.js.map +1 -0
- package/lib/features/webbuilder/webbuilderPrompts.js +31 -5
- package/lib/features/webbuilder/webbuilderPrompts.js.map +1 -1
- package/lib/features/webbuilder/workflow.js +8 -4
- package/lib/features/webbuilder/workflow.js.map +1 -1
- package/lib/screens/Devices/index.js +3 -205
- package/lib/screens/Devices/index.js.map +1 -1
- package/lib/screens/WebBuilderNative/codeWorkspaceApi.js +9 -6
- package/lib/screens/WebBuilderNative/codeWorkspaceApi.js.map +1 -1
- package/lib/screens/WebBuilderNative/index.js +1 -1
- package/lib/screens/WebBuilderNative/index.js.map +1 -1
- package/lib/screens/WebBuilderNative/keepAlive.js +53 -3
- package/lib/screens/WebBuilderNative/keepAlive.js.map +1 -1
- package/lib/screens/WebBuilderNative/unreachableRetry.js +23 -0
- package/lib/screens/WebBuilderNative/unreachableRetry.js.map +1 -0
- package/lib/screens/WebBuilderNative/useConnectorTemplates.js +37 -0
- package/lib/screens/WebBuilderNative/useConnectorTemplates.js.map +1 -0
- package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js +6 -0
- package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js.map +1 -1
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js +302 -40
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
- package/lib/screens/WebBuilderNative/useWebBuilderJobs.js +2 -2
- package/lib/screens/WebBuilderNative/useWebBuilderJobs.js.map +1 -1
- package/lib/screens/WebBuilderNative/versionUndo.js +1 -1
- package/lib/screens/WebBuilderNative/versionUndo.js.map +1 -1
- package/lib/screens/WebBuilderNative/webbuilderTransport.js +147 -77
- package/lib/screens/WebBuilderNative/webbuilderTransport.js.map +1 -1
- package/package.json +4 -4
- package/lib/features/devices/bodyComposition.js +0 -116
- package/lib/features/devices/bodyComposition.js.map +0 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {knownTemplateCategory}from'./templateCatalog.js';var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
const WEBBUILDER_LIST_TEMPLATES_ACTION = "WEBBUILDER_LIST_TEMPLATES";
|
|
21
|
+
const CONNECTOR_CATEGORIES = {
|
|
22
|
+
"landing-page": "Landing Page",
|
|
23
|
+
portfolio: "Portfolio",
|
|
24
|
+
blog: "Blog",
|
|
25
|
+
events: "Events",
|
|
26
|
+
store: "Ecommerce",
|
|
27
|
+
business: "Internal Tools",
|
|
28
|
+
app: "SaaS"
|
|
29
|
+
};
|
|
30
|
+
const PIPELINE_TAGS = /* @__PURE__ */ new Set(["pages", "yantra", "e2b", "webbuilder", "vite"]);
|
|
31
|
+
function str(v) {
|
|
32
|
+
return typeof v === "string" ? v.trim() : "";
|
|
33
|
+
}
|
|
34
|
+
function rec(v) {
|
|
35
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
36
|
+
}
|
|
37
|
+
function connectorCategoryLabel(raw) {
|
|
38
|
+
var _a;
|
|
39
|
+
const key = str(raw).toLowerCase();
|
|
40
|
+
return (_a = CONNECTOR_CATEGORIES[key]) != null ? _a : knownTemplateCategory(key);
|
|
41
|
+
}
|
|
42
|
+
function stackFromBuilder(builder) {
|
|
43
|
+
if (/^next/i.test(builder)) return "nextjs";
|
|
44
|
+
return /^vue/i.test(builder) ? "vue" : "vite-react";
|
|
45
|
+
}
|
|
46
|
+
function cardsFromConnectorCatalog(data) {
|
|
47
|
+
const root = rec(data);
|
|
48
|
+
let list = [];
|
|
49
|
+
if (Array.isArray(data)) list = data;
|
|
50
|
+
else if (Array.isArray(root.templates)) list = root.templates;
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const item of list) {
|
|
53
|
+
const t = rec(item);
|
|
54
|
+
const id = str(t.id) || str(t.templateId);
|
|
55
|
+
if (!id || str(t.category).toLowerCase() === "blank") continue;
|
|
56
|
+
const start = rec(rec(t.start).params);
|
|
57
|
+
const category = connectorCategoryLabel(t.category);
|
|
58
|
+
const tags = (Array.isArray(t.tags) ? t.tags : []).map(str).filter((x) => x && !PIPELINE_TAGS.has(x.toLowerCase()));
|
|
59
|
+
const snapshotId = str(t.snapshotId) || str(start.snapshotId);
|
|
60
|
+
const previewUrl = str(t.previewUrl);
|
|
61
|
+
const deployUrl = str(t.deployUrl);
|
|
62
|
+
const cover = str(t.thumbnail) || str(t.coverImageUrl);
|
|
63
|
+
out.push(__spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
64
|
+
id,
|
|
65
|
+
title: str(t.title) || id
|
|
66
|
+
}, str(t.description) ? {
|
|
67
|
+
description: str(t.description)
|
|
68
|
+
} : {}), category ? {
|
|
69
|
+
category
|
|
70
|
+
} : {}), tags.length ? {
|
|
71
|
+
tags
|
|
72
|
+
} : {}), cover ? {
|
|
73
|
+
cover
|
|
74
|
+
} : {}), {
|
|
75
|
+
templateName: stackFromBuilder(str(t.builder) || str(start.builder)),
|
|
76
|
+
formTemplateId: id
|
|
77
|
+
}), snapshotId ? {
|
|
78
|
+
snapshotId
|
|
79
|
+
} : {}), previewUrl ? {
|
|
80
|
+
previewUrl
|
|
81
|
+
} : {}), deployUrl ? {
|
|
82
|
+
deployUrl
|
|
83
|
+
} : {}), {
|
|
84
|
+
usesSupabase: t.usesSupabase === true
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
function slug(s) {
|
|
90
|
+
return (s != null ? s : "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-by-yantra$/, "");
|
|
91
|
+
}
|
|
92
|
+
function matchKeys(t, withTags) {
|
|
93
|
+
var _a;
|
|
94
|
+
return [t.id && `id:${t.id}`, t.formTemplateId && `id:${t.formTemplateId}`, t.snapshotId && `snap:${t.snapshotId}`, t.deployUrl && `url:${t.deployUrl}`, t.previewUrl && `url:${t.previewUrl}`, slug(t.id) && `slug:${slug(t.id)}`, slug(t.formTemplateId) && `slug:${slug(t.formTemplateId)}`, slug(t.title) && `slug:${slug(t.title)}`, ...(withTags ? (_a = t.tags) != null ? _a : [] : []).map((tag) => slug(tag) && `slug:${slug(tag)}`)].filter((k) => Boolean(k));
|
|
95
|
+
}
|
|
96
|
+
const WORKFLOW_FIELDS = ["formExtensionId", "formId", "formFunctionId", "domain", "apiKey", "metadata"];
|
|
97
|
+
function workflowFields(card) {
|
|
98
|
+
const out = {};
|
|
99
|
+
if (!card) return out;
|
|
100
|
+
for (const k of WORKFLOW_FIELDS) if (card[k] !== void 0) Object.assign(out, {
|
|
101
|
+
[k]: card[k]
|
|
102
|
+
});
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
function mergeWithSettingsCards(fromConnector, fromSettings) {
|
|
106
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
107
|
+
for (const card of fromSettings) for (const k of matchKeys(card, false)) if (!byKey.has(k)) byKey.set(k, card);
|
|
108
|
+
const anyWorkflow = fromSettings.find((c) => c.formExtensionId);
|
|
109
|
+
return fromConnector.map((card) => {
|
|
110
|
+
const twin = matchKeys(card, true).map((k) => byKey.get(k)).find(Boolean);
|
|
111
|
+
return __spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues({}, workflowFields((twin == null ? void 0 : twin.formExtensionId) ? twin : anyWorkflow)), card), {
|
|
112
|
+
cover: card.cover || (twin == null ? void 0 : twin.cover),
|
|
113
|
+
snapshotId: card.snapshotId || (twin == null ? void 0 : twin.snapshotId),
|
|
114
|
+
deployUrl: card.deployUrl || (twin == null ? void 0 : twin.deployUrl),
|
|
115
|
+
previewUrl: card.previewUrl || (twin == null ? void 0 : twin.previewUrl),
|
|
116
|
+
formTemplateId: (twin == null ? void 0 : twin.formTemplateId) || card.formTemplateId
|
|
117
|
+
}), (twin == null ? void 0 : twin.chatPrompt) ? {
|
|
118
|
+
chatPrompt: twin.chatPrompt
|
|
119
|
+
} : {}), (twin == null ? void 0 : twin.skill) ? {
|
|
120
|
+
skill: twin.skill
|
|
121
|
+
} : {});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function versioned(title) {
|
|
125
|
+
const m = /^(.*?)\s+v(\d+)$/i.exec(title.trim());
|
|
126
|
+
return m ? {
|
|
127
|
+
base: m[1].trim(),
|
|
128
|
+
version: Number(m[2])
|
|
129
|
+
} : {
|
|
130
|
+
base: title.trim(),
|
|
131
|
+
version: 1
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function newestConnectorVersions(list) {
|
|
135
|
+
var _a;
|
|
136
|
+
const newest = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const card of list) {
|
|
138
|
+
const {
|
|
139
|
+
base,
|
|
140
|
+
version
|
|
141
|
+
} = versioned(card.title);
|
|
142
|
+
const key = `${(_a = card.category) != null ? _a : ""}|${base.toLowerCase()}`;
|
|
143
|
+
const seen = newest.get(key);
|
|
144
|
+
if (!seen) newest.set(key, {
|
|
145
|
+
card,
|
|
146
|
+
version,
|
|
147
|
+
base,
|
|
148
|
+
count: 1
|
|
149
|
+
});
|
|
150
|
+
else {
|
|
151
|
+
seen.count += 1;
|
|
152
|
+
if (version > seen.version) Object.assign(seen, {
|
|
153
|
+
card,
|
|
154
|
+
version
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const keep = new Map([...newest.values()].map((g) => [g.card, g]));
|
|
159
|
+
return list.flatMap((card) => {
|
|
160
|
+
const g = keep.get(card);
|
|
161
|
+
if (!g) return [];
|
|
162
|
+
return [g.count > 1 ? __spreadProps(__spreadValues({}, card), {
|
|
163
|
+
title: g.base
|
|
164
|
+
}) : card];
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function galleryTemplates(connectorData, fromSettings) {
|
|
168
|
+
const fromConnector = cardsFromConnectorCatalog(connectorData);
|
|
169
|
+
if (!fromConnector.length) return fromSettings;
|
|
170
|
+
return newestConnectorVersions(mergeWithSettingsCards(fromConnector, fromSettings));
|
|
171
|
+
}export{WEBBUILDER_LIST_TEMPLATES_ACTION,cardsFromConnectorCatalog,connectorCategoryLabel,galleryTemplates,mergeWithSettingsCards,newestConnectorVersions};//# sourceMappingURL=connectorTemplates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectorTemplates.js","sources":["../../../src/features/webbuilder/connectorTemplates.ts"],"sourcesContent":["/**\n * The template gallery from the yantra-webbuilder `WEBBUILDER_LIST_TEMPLATES` catalog (the one the agent\n * picks from), merged with the org's pageSettings cards for what a pick still needs from them - the web\n * `standalone/domain/connectorTemplates.ts`. Pure.\n */\nimport type { WebBuilderTemplate as WebBuilderTemplateOption } from './workflow';\nimport { knownTemplateCategory } from './templateCatalog';\n\nexport const WEBBUILDER_LIST_TEMPLATES_ACTION = 'WEBBUILDER_LIST_TEMPLATES';\n\n// The connector's own category names, as the shelves people know.\nconst CONNECTOR_CATEGORIES: Record<string, string> = {\n 'landing-page': 'Landing Page',\n portfolio: 'Portfolio',\n blog: 'Blog',\n events: 'Events',\n store: 'Ecommerce',\n business: 'Internal Tools',\n app: 'SaaS',\n};\n\n// Tags every connector template carries; they would make a search for \"pages\" match them all.\nconst PIPELINE_TAGS = new Set(['pages', 'yantra', 'e2b', 'webbuilder', 'vite']);\n\ntype Rec = Record<string, unknown>;\n\nfunction str(v: unknown): string {\n return typeof v === 'string' ? v.trim() : '';\n}\n\nfunction rec(v: unknown): Rec {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Rec) : {};\n}\n\n/** The shelf label for a connector category; '' for `blank` and anything unknown (no chip). */\nexport function connectorCategoryLabel(raw: unknown): string {\n const key = str(raw).toLowerCase();\n return CONNECTOR_CATEGORIES[key] ?? knownTemplateCategory(key);\n}\n\nfunction stackFromBuilder(builder: string): string {\n if (/^next/i.test(builder)) return 'nextjs';\n return /^vue/i.test(builder) ? 'vue' : 'vite-react';\n}\n\n/** The connector's templates as cards; the from-scratch `blank` starter is not a card. */\nexport function cardsFromConnectorCatalog(data: unknown): WebBuilderTemplateOption[] {\n const root = rec(data);\n let list: unknown[] = [];\n if (Array.isArray(data)) list = data;\n else if (Array.isArray(root.templates)) list = root.templates;\n const out: WebBuilderTemplateOption[] = [];\n for (const item of list) {\n const t = rec(item);\n const id = str(t.id) || str(t.templateId);\n // eslint-disable-next-line no-continue -- the from-scratch starter is not a card\n if (!id || str(t.category).toLowerCase() === 'blank') continue;\n const start = rec(rec(t.start).params);\n const category = connectorCategoryLabel(t.category);\n const tags = (Array.isArray(t.tags) ? t.tags : [])\n .map(str)\n .filter((x) => x && !PIPELINE_TAGS.has(x.toLowerCase()));\n const snapshotId = str(t.snapshotId) || str(start.snapshotId);\n const previewUrl = str(t.previewUrl);\n const deployUrl = str(t.deployUrl);\n const cover = str(t.thumbnail) || str(t.coverImageUrl);\n out.push({\n id,\n title: str(t.title) || id,\n ...(str(t.description) ? { description: str(t.description) } : {}),\n ...(category ? { category } : {}),\n ...(tags.length ? { tags } : {}),\n ...(cover ? { cover } : {}),\n templateName: stackFromBuilder(str(t.builder) || str(start.builder)),\n formTemplateId: id,\n ...(snapshotId ? { snapshotId } : {}),\n ...(previewUrl ? { previewUrl } : {}),\n ...(deployUrl ? { deployUrl } : {}),\n usesSupabase: t.usesSupabase === true,\n });\n }\n return out;\n}\n\n/** \"Arch Studio by Yantra\", \"arch-studio-by-yantra\" -> \"arch-studio\". */\nfunction slug(s: string | undefined): string {\n return (s ?? '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .replace(/-by-yantra$/, '');\n}\n\nfunction matchKeys(t: WebBuilderTemplateOption, withTags: boolean): string[] {\n return [\n t.id && `id:${t.id}`,\n t.formTemplateId && `id:${t.formTemplateId}`,\n t.snapshotId && `snap:${t.snapshotId}`,\n t.deployUrl && `url:${t.deployUrl}`,\n t.previewUrl && `url:${t.previewUrl}`,\n slug(t.id) && `slug:${slug(t.id)}`,\n slug(t.formTemplateId) && `slug:${slug(t.formTemplateId)}`,\n slug(t.title) && `slug:${slug(t.title)}`,\n ...(withTags ? (t.tags ?? []) : []).map((tag) => slug(tag) && `slug:${slug(tag)}`),\n ].filter((k): k is string => Boolean(k));\n}\n\nconst WORKFLOW_FIELDS = ['formExtensionId', 'formId', 'formFunctionId', 'domain', 'apiKey', 'metadata'] as const;\n\nfunction workflowFields(card: WebBuilderTemplateOption | undefined): Partial<WebBuilderTemplateOption> {\n const out: Partial<WebBuilderTemplateOption> = {};\n if (!card) return out;\n for (const k of WORKFLOW_FIELDS) if (card[k] !== undefined) Object.assign(out, { [k]: card[k] });\n return out;\n}\n\n/**\n * Each connector card takes from its pageSettings twin (same id, slug, snapshot, live URL or tag) what a pick\n * sends on: the build workflow's ids, the seed prompt, the skill. pageSettings cards without a twin are stale\n * repo entries and are left out.\n */\nexport function mergeWithSettingsCards(\n fromConnector: WebBuilderTemplateOption[],\n fromSettings: WebBuilderTemplateOption[],\n): WebBuilderTemplateOption[] {\n const byKey = new Map<string, WebBuilderTemplateOption>();\n for (const card of fromSettings) for (const k of matchKeys(card, false)) if (!byKey.has(k)) byKey.set(k, card);\n // The workflow ids are the org's, not the card's: any card that has them lends them to an unmatched one.\n const anyWorkflow = fromSettings.find((c) => c.formExtensionId);\n return fromConnector.map((card) => {\n const twin = matchKeys(card, true)\n .map((k) => byKey.get(k))\n .find(Boolean);\n return {\n ...workflowFields(twin?.formExtensionId ? twin : anyWorkflow),\n ...card,\n cover: card.cover || twin?.cover,\n snapshotId: card.snapshotId || twin?.snapshotId,\n deployUrl: card.deployUrl || twin?.deployUrl,\n previewUrl: card.previewUrl || twin?.previewUrl,\n formTemplateId: twin?.formTemplateId || card.formTemplateId,\n ...(twin?.chatPrompt ? { chatPrompt: twin.chatPrompt } : {}),\n ...(twin?.skill ? { skill: twin.skill } : {}),\n };\n });\n}\n\nfunction versioned(title: string): { base: string; version: number } {\n const m = /^(.*?)\\s+v(\\d+)$/i.exec(title.trim());\n return m ? { base: m[1].trim(), version: Number(m[2]) } : { base: title.trim(), version: 1 };\n}\n\n/** \"X\" and \"X V2\" in one category are one template: the newest is kept, named \"X\". */\nexport function newestConnectorVersions(list: WebBuilderTemplateOption[]): WebBuilderTemplateOption[] {\n const newest = new Map<string, { card: WebBuilderTemplateOption; version: number; base: string; count: number }>();\n for (const card of list) {\n const { base, version } = versioned(card.title);\n const key = `${card.category ?? ''}|${base.toLowerCase()}`;\n const seen = newest.get(key);\n if (!seen) newest.set(key, { card, version, base, count: 1 });\n else {\n seen.count += 1;\n if (version > seen.version) Object.assign(seen, { card, version });\n }\n }\n const keep = new Map([...newest.values()].map((g) => [g.card, g]));\n return list.flatMap((card) => {\n const g = keep.get(card);\n if (!g) return [];\n return [g.count > 1 ? { ...card, title: g.base } : card];\n });\n}\n\n/** The gallery: the connector's catalog when it has templates, else the pageSettings cards as they are. */\nexport function galleryTemplates(\n connectorData: unknown,\n fromSettings: WebBuilderTemplateOption[],\n): WebBuilderTemplateOption[] {\n const fromConnector = cardsFromConnectorCatalog(connectorData);\n if (!fromConnector.length) return fromSettings;\n return newestConnectorVersions(mergeWithSettingsCards(fromConnector, fromSettings));\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
function compareNames(a, b) {
|
|
3
|
+
const byName = a.localeCompare(b, void 0, {
|
|
4
|
+
sensitivity: "base"
|
|
5
|
+
});
|
|
6
|
+
if (byName) return byName;
|
|
7
|
+
if (a === b) return 0;
|
|
8
|
+
return a < b ? -1 : 1;
|
|
9
|
+
}
|
|
10
|
+
function baseName(path) {
|
|
11
|
+
return path.slice(path.lastIndexOf("/") + 1);
|
|
12
|
+
}
|
|
13
|
+
function buildFileTree(paths, opts = {}) {
|
|
14
|
+
const compact = opts.compact !== false;
|
|
15
|
+
const root = {
|
|
16
|
+
folders: /* @__PURE__ */ new Map(),
|
|
17
|
+
files: []
|
|
18
|
+
};
|
|
19
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20
|
+
for (const raw of paths) {
|
|
21
|
+
const path = raw.trim();
|
|
22
|
+
const parts = path.split("/").filter(Boolean);
|
|
23
|
+
if (!path || seen.has(path) || !parts.length) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
seen.add(path);
|
|
27
|
+
let dir = root;
|
|
28
|
+
for (const part of parts.slice(0, -1)) {
|
|
29
|
+
let next = dir.folders.get(part);
|
|
30
|
+
if (!next) {
|
|
31
|
+
next = {
|
|
32
|
+
folders: /* @__PURE__ */ new Map(),
|
|
33
|
+
files: []
|
|
34
|
+
};
|
|
35
|
+
dir.folders.set(part, next);
|
|
36
|
+
}
|
|
37
|
+
dir = next;
|
|
38
|
+
}
|
|
39
|
+
dir.files.push(parts.join("/"));
|
|
40
|
+
}
|
|
41
|
+
const toNode = (draft, name, path) => {
|
|
42
|
+
const folders = [...draft.folders.entries()].sort(([a], [b]) => compareNames(a, b)).map(([child, d]) => toNode(d, child, path ? `${path}/${child}` : child));
|
|
43
|
+
const files = draft.files.map((p) => ({
|
|
44
|
+
kind: "file",
|
|
45
|
+
name: baseName(p),
|
|
46
|
+
path: p
|
|
47
|
+
})).sort((a, b) => compareNames(a.name, b.name));
|
|
48
|
+
const node = {
|
|
49
|
+
kind: "folder",
|
|
50
|
+
name,
|
|
51
|
+
path,
|
|
52
|
+
segments: path ? [path] : [],
|
|
53
|
+
children: [...folders, ...files]
|
|
54
|
+
};
|
|
55
|
+
if (compact && path && !files.length && folders.length === 1) {
|
|
56
|
+
const only = folders[0];
|
|
57
|
+
return {
|
|
58
|
+
kind: "folder",
|
|
59
|
+
name: `${name}/${only.name}`,
|
|
60
|
+
path: only.path,
|
|
61
|
+
segments: [path, ...only.segments],
|
|
62
|
+
children: only.children
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return node;
|
|
66
|
+
};
|
|
67
|
+
return toNode(root, "", "");
|
|
68
|
+
}
|
|
69
|
+
function isExpanded(node, expanded) {
|
|
70
|
+
return expanded === "all" || expanded.has(node.path);
|
|
71
|
+
}
|
|
72
|
+
function visibleRows(root, expanded) {
|
|
73
|
+
const rows = [];
|
|
74
|
+
const walk = (children, level, parent) => {
|
|
75
|
+
children.forEach((node, i) => {
|
|
76
|
+
const open = node.kind === "folder" && isExpanded(node, expanded);
|
|
77
|
+
rows.push({
|
|
78
|
+
node,
|
|
79
|
+
level,
|
|
80
|
+
expanded: open,
|
|
81
|
+
parent,
|
|
82
|
+
posInSet: i + 1,
|
|
83
|
+
setSize: children.length
|
|
84
|
+
});
|
|
85
|
+
if (open && node.kind === "folder") walk(node.children, level + 1, node.path);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
walk(root.children, 1, null);
|
|
89
|
+
return rows;
|
|
90
|
+
}
|
|
91
|
+
function ancestorFolders(path) {
|
|
92
|
+
const parts = path.split("/").filter(Boolean);
|
|
93
|
+
const out = [];
|
|
94
|
+
for (let i = 1; i < parts.length; i++) out.push(parts.slice(0, i).join("/"));
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
function withRevealed(expanded, path) {
|
|
98
|
+
const missing = ancestorFolders(path).filter((f) => !expanded.has(f));
|
|
99
|
+
if (!missing.length) return expanded;
|
|
100
|
+
return /* @__PURE__ */ new Set([...expanded, ...missing]);
|
|
101
|
+
}
|
|
102
|
+
function withFolder(expanded, folder, open) {
|
|
103
|
+
const next = new Set(expanded);
|
|
104
|
+
for (const seg of folder.segments) {
|
|
105
|
+
if (open) next.add(seg);
|
|
106
|
+
else next.delete(seg);
|
|
107
|
+
}
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
function queryTerms(query) {
|
|
111
|
+
return query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
112
|
+
}
|
|
113
|
+
function filterPaths(paths, query) {
|
|
114
|
+
const terms = queryTerms(query);
|
|
115
|
+
if (!terms.length) return [...paths];
|
|
116
|
+
return paths.filter((p) => {
|
|
117
|
+
const lower = p.toLowerCase();
|
|
118
|
+
return terms.every((t) => lower.includes(t));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function nameMatch(name, query) {
|
|
122
|
+
const terms = queryTerms(query);
|
|
123
|
+
const lower = name.toLowerCase();
|
|
124
|
+
for (const t of terms) {
|
|
125
|
+
const start = lower.indexOf(t);
|
|
126
|
+
if (start >= 0) return {
|
|
127
|
+
start,
|
|
128
|
+
end: start + t.length
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
function rollUp(entries) {
|
|
134
|
+
const out = /* @__PURE__ */ new Map();
|
|
135
|
+
for (const [path, value] of entries) {
|
|
136
|
+
for (const folder of ancestorFolders(path)) {
|
|
137
|
+
const list = out.get(folder);
|
|
138
|
+
if (list) list.push(value);
|
|
139
|
+
else out.set(folder, [value]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
let AsyncStorage = null;
|
|
145
|
+
try {
|
|
146
|
+
AsyncStorage = (_a = require("@react-native-async-storage/async-storage").default) != null ? _a : null;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
AsyncStorage = null;
|
|
149
|
+
}
|
|
150
|
+
const MAX_KEPT_FOLDERS = 200;
|
|
151
|
+
const expandedKey = (projectKey) => `yantra.webbuilder.codeTreeExpanded.${projectKey}`;
|
|
152
|
+
async function readExpandedFolders(projectKey) {
|
|
153
|
+
try {
|
|
154
|
+
const raw = await (AsyncStorage == null ? void 0 : AsyncStorage.getItem(expandedKey(projectKey)));
|
|
155
|
+
const list = raw ? JSON.parse(raw) : [];
|
|
156
|
+
return new Set(Array.isArray(list) ? list.filter((x) => typeof x === "string") : []);
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return /* @__PURE__ */ new Set();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function writeExpandedFolders(projectKey, expanded) {
|
|
162
|
+
AsyncStorage == null ? void 0 : AsyncStorage.setItem(expandedKey(projectKey), JSON.stringify([...expanded].slice(0, MAX_KEPT_FOLDERS))).catch(() => void 0);
|
|
163
|
+
}export{ancestorFolders,buildFileTree,filterPaths,isExpanded,nameMatch,readExpandedFolders,rollUp,visibleRows,withFolder,withRevealed,writeExpandedFolders};//# sourceMappingURL=fileTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileTree.js","sources":["../../../src/features/webbuilder/fileTree.ts"],"sourcesContent":["/**\n * The Code view's file explorer as data - the web `code/fileTree.ts`: nested folders from the\n * flat path list, VS Code-style compacted folder chains, the visible rows for an expanded set,\n * filtering and folder roll-ups. Pure; the open folders are kept per project on this device.\n */\n\nexport interface FolderNode {\n kind: 'folder';\n /** The label: one name, or a compacted chain (\"src/components\"). */\n name: string;\n /** The deepest folder of the chain ('' for the root). */\n path: string;\n /** Each folder of a compacted chain, outermost first. */\n segments: string[];\n children: TreeNode[];\n}\n\nexport interface FileNode {\n kind: 'file';\n name: string;\n path: string;\n}\n\nexport type TreeNode = FolderNode | FileNode;\n\nexport interface TreeRow {\n node: TreeNode;\n /** 1-based depth. */\n level: number;\n expanded: boolean;\n /** The parent row's path (null at the top level). */\n parent: string | null;\n posInSet: number;\n setSize: number;\n}\n\ninterface Draft {\n folders: Map<string, Draft>;\n files: string[];\n}\n\nfunction compareNames(a: string, b: string): number {\n const byName = a.localeCompare(b, undefined, { sensitivity: 'base' });\n if (byName) return byName;\n if (a === b) return 0;\n return a < b ? -1 : 1;\n}\n\nfunction baseName(path: string): string {\n return path.slice(path.lastIndexOf('/') + 1);\n}\n\n/** Nested nodes from paths: folders first, then files, case-insensitive (the `sortTree` order). */\nexport function buildFileTree(paths: readonly string[], opts: { compact?: boolean } = {}): FolderNode {\n const compact = opts.compact !== false;\n const root: Draft = { folders: new Map(), files: [] };\n const seen = new Set<string>();\n for (const raw of paths) {\n const path = raw.trim();\n const parts = path.split('/').filter(Boolean);\n if (!path || seen.has(path) || !parts.length) {\n // eslint-disable-next-line no-continue -- a blank or repeated path adds nothing\n continue;\n }\n seen.add(path);\n let dir = root;\n for (const part of parts.slice(0, -1)) {\n let next = dir.folders.get(part);\n if (!next) {\n next = { folders: new Map(), files: [] };\n dir.folders.set(part, next);\n }\n dir = next;\n }\n dir.files.push(parts.join('/'));\n }\n\n const toNode = (draft: Draft, name: string, path: string): FolderNode => {\n const folders = [...draft.folders.entries()]\n .sort(([a], [b]) => compareNames(a, b))\n .map(([child, d]) => toNode(d, child, path ? `${path}/${child}` : child));\n const files = draft.files\n .map((p): FileNode => ({ kind: 'file', name: baseName(p), path: p }))\n .sort((a, b) => compareNames(a.name, b.name));\n const node: FolderNode = {\n kind: 'folder',\n name,\n path,\n segments: path ? [path] : [],\n children: [...folders, ...files],\n };\n // A folder whose only child is a folder shows as one row; the root never merges.\n if (compact && path && !files.length && folders.length === 1) {\n const only = folders[0];\n return {\n kind: 'folder',\n name: `${name}/${only.name}`,\n path: only.path,\n segments: [path, ...only.segments],\n children: only.children,\n };\n }\n return node;\n };\n return toNode(root, '', '');\n}\n\n/** Every file path and every folder segment -> the node that shows it. */\nexport function indexTree(root: FolderNode): Map<string, TreeNode> {\n const out = new Map<string, TreeNode>();\n const walk = (node: TreeNode) => {\n if (node.kind === 'file') {\n out.set(node.path, node);\n return;\n }\n for (const seg of node.segments) out.set(seg, node);\n for (const child of node.children) walk(child);\n };\n walk(root);\n return out;\n}\n\nexport type Expansion = ReadonlySet<string> | 'all';\n\nexport function isExpanded(node: FolderNode, expanded: Expansion): boolean {\n return expanded === 'all' || expanded.has(node.path);\n}\n\n/** The rows on screen: depth-first, descending only into expanded folders. */\nexport function visibleRows(root: FolderNode, expanded: Expansion): TreeRow[] {\n const rows: TreeRow[] = [];\n const walk = (children: TreeNode[], level: number, parent: string | null) => {\n children.forEach((node, i) => {\n const open = node.kind === 'folder' && isExpanded(node, expanded);\n rows.push({ node, level, expanded: open, parent, posInSet: i + 1, setSize: children.length });\n if (open && node.kind === 'folder') walk(node.children, level + 1, node.path);\n });\n };\n walk(root.children, 1, null);\n return rows;\n}\n\n/** Folders that contain a path, outermost first ('src/a/b.ts' -> ['src', 'src/a']). */\nexport function ancestorFolders(path: string): string[] {\n const parts = path.split('/').filter(Boolean);\n const out: string[] = [];\n for (let i = 1; i < parts.length; i++) out.push(parts.slice(0, i).join('/'));\n return out;\n}\n\n/** The expanded set with a path's folders opened (a no-op returns the same set). */\nexport function withRevealed(expanded: ReadonlySet<string>, path: string): ReadonlySet<string> {\n const missing = ancestorFolders(path).filter((f) => !expanded.has(f));\n if (!missing.length) return expanded;\n return new Set([...expanded, ...missing]);\n}\n\n/** Open or close a folder row; every segment of a compacted chain moves together, so it holds if the chain splits later. */\nexport function withFolder(expanded: ReadonlySet<string>, folder: FolderNode, open: boolean): ReadonlySet<string> {\n const next = new Set(expanded);\n for (const seg of folder.segments) {\n if (open) next.add(seg);\n else next.delete(seg);\n }\n return next;\n}\n\nfunction queryTerms(query: string): string[] {\n return query.trim().toLowerCase().split(/\\s+/).filter(Boolean);\n}\n\n/** Paths whose name or path holds every word of the query (case-insensitive); all of them for an empty query. */\nexport function filterPaths(paths: readonly string[], query: string): string[] {\n const terms = queryTerms(query);\n if (!terms.length) return [...paths];\n return paths.filter((p) => {\n const lower = p.toLowerCase();\n return terms.every((t) => lower.includes(t));\n });\n}\n\n/** Where the query's first word sits in a name, for highlighting; null when it isn't in the name. */\nexport function nameMatch(name: string, query: string): { start: number; end: number } | null {\n const terms = queryTerms(query);\n const lower = name.toLowerCase();\n for (const t of terms) {\n const start = lower.indexOf(t);\n if (start >= 0) return { start, end: start + t.length };\n }\n return null;\n}\n\n/** Folder -> the values of every file under it (the unsaved dot and peer marks on collapsed folders). */\nexport function rollUp<T>(entries: Iterable<readonly [path: string, value: T]>): Map<string, T[]> {\n const out = new Map<string, T[]>();\n for (const [path, value] of entries) {\n for (const folder of ancestorFolders(path)) {\n const list = out.get(folder);\n if (list) list.push(value);\n else out.set(folder, [value]);\n }\n }\n return out;\n}\n\n/** Files grouped by their folder in tree order (the phone picker's optgroups); '' is the top level, last. */\nexport function groupByFolder(paths: readonly string[]): Array<{ folder: string; files: string[] }> {\n const byFolder = new Map<string, string[]>();\n const walk = (node: FolderNode) => {\n const files = node.children.filter((c): c is FileNode => c.kind === 'file').map((f) => f.path);\n for (const child of node.children) if (child.kind === 'folder') walk(child);\n if (files.length) byFolder.set(node.path, files);\n };\n walk(buildFileTree(paths, { compact: false }));\n return [...byFolder.entries()].map(([folder, files]) => ({ folder, files }));\n}\n\n// ── The open folders, per project on this device (the web keeps them per tab) ──\ntype StorageLike = {\n getItem: (key: string) => Promise<string | null>;\n setItem: (key: string, value: string) => Promise<void>;\n};\n\nlet AsyncStorage: StorageLike | null = null;\ntry {\n // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require\n AsyncStorage = require('@react-native-async-storage/async-storage').default ?? null;\n} catch {\n AsyncStorage = null;\n}\n\n/** Folders kept per project: a big tree opened all the way is not worth more. */\nconst MAX_KEPT_FOLDERS = 200;\n\nconst expandedKey = (projectKey: string) => `yantra.webbuilder.codeTreeExpanded.${projectKey}`;\n\nexport async function readExpandedFolders(projectKey: string): Promise<ReadonlySet<string>> {\n try {\n const raw = await AsyncStorage?.getItem(expandedKey(projectKey));\n const list: unknown = raw ? JSON.parse(raw) : [];\n return new Set(Array.isArray(list) ? list.filter((x): x is string => typeof x === 'string') : []);\n } catch {\n return new Set();\n }\n}\n\nexport function writeExpandedFolders(projectKey: string, expanded: ReadonlySet<string>): void {\n AsyncStorage?.setItem(expandedKey(projectKey), JSON.stringify([...expanded].slice(0, MAX_KEPT_FOLDERS))).catch(\n () => undefined,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const MAX = 3;
|
|
2
|
+
const MAX_NEXT = 4;
|
|
3
|
+
const CONFIRM_HEADING = /^\s*(?:#{1,6}\s*)?\**\s*(?:still\s+)?to\s+confirm\s*(?::\s*\**|\**\s*:|\**\s*$)\s*(.*)$/i;
|
|
4
|
+
const NEXT_LINE = /^\s*(?:#{1,6}\s*)?\**\s*(?:next(?:\s+steps?)?|what'?s\s+next)\s*\**\s*:\s*\**\s*(.*)$/i;
|
|
5
|
+
const NEXT_HEADING = /^\s*(?:#{1,6}\s*)?\**\s*(?:next\s+steps?|what'?s\s+next)\s*\**\s*$/i;
|
|
6
|
+
const BULLET = /^\s*(?:[-*•]|\d+[.)])\s+(.*)$/;
|
|
7
|
+
function clean(s) {
|
|
8
|
+
return s.replace(/\*\*|__|`/g, "").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/\s+/g, " ").replace(/[.;:,]+$/, "").trim();
|
|
9
|
+
}
|
|
10
|
+
function capitalize(s) {
|
|
11
|
+
return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
|
|
12
|
+
}
|
|
13
|
+
function short(s, n = 48) {
|
|
14
|
+
return s.length > n ? `${s.slice(0, n - 1).trimEnd()}\u2026` : s;
|
|
15
|
+
}
|
|
16
|
+
function splitSteps(line) {
|
|
17
|
+
return line.split(/,|;|\s+or\s+(?=[a-z]+\s)|\.\s+/i).map((p) => clean(p.replace(/^(?:and|or|then)\s+/i, ""))).filter((p) => p.length > 2 && !/^(?:change anything|anything else)$/i.test(p));
|
|
18
|
+
}
|
|
19
|
+
function bulletsAfter(lines, i) {
|
|
20
|
+
const out = [];
|
|
21
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
22
|
+
const b = BULLET.exec(lines[j]);
|
|
23
|
+
if (b) out.push(clean(b[1]));
|
|
24
|
+
else if (lines[j].trim()) break;
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
function followUpSuggestions(reply) {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
if (!(reply == null ? void 0 : reply.trim())) return [];
|
|
31
|
+
const lines = reply.split("\n");
|
|
32
|
+
const confirm = [];
|
|
33
|
+
const next = [];
|
|
34
|
+
for (let i = 0; i < lines.length; i++) {
|
|
35
|
+
const heading = CONFIRM_HEADING.exec(lines[i]);
|
|
36
|
+
const nextLine = heading ? null : NEXT_LINE.exec(lines[i]);
|
|
37
|
+
if (heading) {
|
|
38
|
+
if ((_a = heading[1]) == null ? void 0 : _a.trim()) confirm.push(...splitSteps(heading[1]));
|
|
39
|
+
confirm.push(...bulletsAfter(lines, i));
|
|
40
|
+
} else if ((_b = nextLine == null ? void 0 : nextLine[1]) == null ? void 0 : _b.trim()) next.push(...splitSteps(nextLine[1]));
|
|
41
|
+
else if (nextLine || NEXT_HEADING.test(lines[i])) next.push(...bulletsAfter(lines, i));
|
|
42
|
+
}
|
|
43
|
+
const out = [];
|
|
44
|
+
const seen = /* @__PURE__ */ new Set();
|
|
45
|
+
const add = (f, max) => {
|
|
46
|
+
const key = f.label.toLowerCase();
|
|
47
|
+
if (out.length >= max || seen.has(key) || !f.label) return;
|
|
48
|
+
seen.add(key);
|
|
49
|
+
out.push(f);
|
|
50
|
+
};
|
|
51
|
+
const steps = next.filter(Boolean);
|
|
52
|
+
if (steps.length) {
|
|
53
|
+
for (const step of steps) add({
|
|
54
|
+
label: short(capitalize(step)),
|
|
55
|
+
prompt: capitalize(step)
|
|
56
|
+
}, MAX_NEXT);
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
for (const item of confirm) {
|
|
60
|
+
const fact = clean(item.replace(/\s*\(.*?\)\s*/g, " "));
|
|
61
|
+
if (fact) add({
|
|
62
|
+
label: short(capitalize(fact)),
|
|
63
|
+
prompt: `${capitalize(fact)}: `
|
|
64
|
+
}, MAX);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}export{followUpSuggestions};//# sourceMappingURL=followUps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"followUps.js","sources":["../../../src/features/webbuilder/followUps.ts"],"sourcesContent":["/**\n * Follow-up chips under the agent's last reply - the web `chat/followUps.ts`: the reply's\n * \"Next steps\" (a line or a list); without one, its \"To confirm\" list. Pure.\n */\n\nexport interface FollowUp {\n /** The chip label. */\n label: string;\n /** What the chip puts in the composer. */\n prompt: string;\n}\n\nconst MAX = 3;\n/** Next steps are the reply's own suggested actions: up to four. */\nconst MAX_NEXT = 4;\nconst CONFIRM_HEADING = /^\\s*(?:#{1,6}\\s*)?\\**\\s*(?:still\\s+)?to\\s+confirm\\s*(?::\\s*\\**|\\**\\s*:|\\**\\s*$)\\s*(.*)$/i;\nconst NEXT_LINE = /^\\s*(?:#{1,6}\\s*)?\\**\\s*(?:next(?:\\s+steps?)?|what'?s\\s+next)\\s*\\**\\s*:\\s*\\**\\s*(.*)$/i;\n/** \"## Next steps\" / \"**Next steps**\" on its own line, a list below it. */\nconst NEXT_HEADING = /^\\s*(?:#{1,6}\\s*)?\\**\\s*(?:next\\s+steps?|what'?s\\s+next)\\s*\\**\\s*$/i;\nconst BULLET = /^\\s*(?:[-*•]|\\d+[.)])\\s+(.*)$/;\n\nfunction clean(s: string): string {\n return s\n .replace(/\\*\\*|__|`/g, '')\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\s+/g, ' ')\n .replace(/[.;:,]+$/, '')\n .trim();\n}\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;\n}\n\nfunction short(s: string, n = 48): string {\n return s.length > n ? `${s.slice(0, n - 1).trimEnd()}…` : s;\n}\n\n/** \"change anything, add your photos or logo, publish it\" -> three steps. */\nfunction splitSteps(line: string): string[] {\n return line\n .split(/,|;|\\s+or\\s+(?=[a-z]+\\s)|\\.\\s+/i)\n .map((p) => clean(p.replace(/^(?:and|or|then)\\s+/i, '')))\n .filter((p) => p.length > 2 && !/^(?:change anything|anything else)$/i.test(p));\n}\n\n/** The list items right under line `i` (blank lines allowed), up to the first other line. */\nfunction bulletsAfter(lines: string[], i: number): string[] {\n const out: string[] = [];\n for (let j = i + 1; j < lines.length; j++) {\n const b = BULLET.exec(lines[j]);\n if (b) out.push(clean(b[1]));\n else if (lines[j].trim()) break;\n }\n return out;\n}\n\nexport function followUpSuggestions(reply: string | null | undefined): FollowUp[] {\n if (!reply?.trim()) return [];\n const lines = reply.split('\\n');\n const confirm: string[] = [];\n const next: string[] = [];\n for (let i = 0; i < lines.length; i++) {\n const heading = CONFIRM_HEADING.exec(lines[i]);\n const nextLine = heading ? null : NEXT_LINE.exec(lines[i]);\n if (heading) {\n if (heading[1]?.trim()) confirm.push(...splitSteps(heading[1]));\n confirm.push(...bulletsAfter(lines, i));\n } else if (nextLine?.[1]?.trim()) next.push(...splitSteps(nextLine[1]));\n else if (nextLine || NEXT_HEADING.test(lines[i])) next.push(...bulletsAfter(lines, i));\n }\n const out: FollowUp[] = [];\n const seen = new Set<string>();\n const add = (f: FollowUp, max: number) => {\n const key = f.label.toLowerCase();\n if (out.length >= max || seen.has(key) || !f.label) return;\n seen.add(key);\n out.push(f);\n };\n // The reply's own next steps are what to tap; the facts to confirm only stand in when it gives none.\n const steps = next.filter(Boolean);\n if (steps.length) {\n for (const step of steps) add({ label: short(capitalize(step)), prompt: capitalize(step) }, MAX_NEXT);\n return out;\n }\n // A missing fact reads best as a question to answer.\n for (const item of confirm) {\n const fact = clean(item.replace(/\\s*\\(.*?\\)\\s*/g, ' '));\n if (fact) add({ label: short(capitalize(fact)), prompt: `${capitalize(fact)}: ` }, MAX);\n }\n return out;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
const CLOSED_PORT_RE = /Closed Port Error|Update Port Error|Could Not Find|Connection refused on port|no service (running|listening|waiting)|THERE'?S NO SERVICE LISTENING|Port 3000 is no longer|is no longer running|no longer active/i;
|
|
18
|
+
const SANDBOX_GONE_RE = /\bSANDBOX_GONE\b|Sandbox Not Found|Paused sandbox .+ not found|sandbox \S+ not found|sandbox .*wasn'?t found|not found \(404\)|no sandbox found|does not exist|sandbox.*expired|sandbox.*killed|probably not running anymore|not running anymore|cannot be resumed|was (?:killed|deleted|destroyed)/i;
|
|
19
|
+
const SNIFF_CHARS = 6e3;
|
|
20
|
+
const PROBE_TIMEOUT_MS = 8e3;
|
|
21
|
+
function classifyPreviewAnswer(status, body) {
|
|
22
|
+
const head = String(body || "").slice(0, SNIFF_CHARS);
|
|
23
|
+
if (SANDBOX_GONE_RE.test(head)) return "gone";
|
|
24
|
+
if (CLOSED_PORT_RE.test(head)) return "port-closed";
|
|
25
|
+
if (status >= 500) return "port-closed";
|
|
26
|
+
if (status === 404 && /e2b|sandbox/i.test(head)) return "gone";
|
|
27
|
+
return "open";
|
|
28
|
+
}
|
|
29
|
+
async function probePreview(url, fetchImpl = fetch) {
|
|
30
|
+
if (!/^https?:\/\//i.test(url)) return "unknown";
|
|
31
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
32
|
+
const timer = controller ? setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS) : null;
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetchImpl(url, __spreadValues({
|
|
35
|
+
method: "GET"
|
|
36
|
+
}, controller ? {
|
|
37
|
+
signal: controller.signal
|
|
38
|
+
} : {}));
|
|
39
|
+
const body = await res.text().catch(() => "");
|
|
40
|
+
return classifyPreviewAnswer(res.status, body);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
return "unknown";
|
|
43
|
+
} finally {
|
|
44
|
+
if (timer) clearTimeout(timer);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function mayFrame(probe) {
|
|
48
|
+
return probe === "open" || probe === "unknown";
|
|
49
|
+
}export{CLOSED_PORT_RE,SANDBOX_GONE_RE,classifyPreviewAnswer,mayFrame,probePreview};//# sourceMappingURL=previewProbe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewProbe.js","sources":["../../../src/features/webbuilder/previewProbe.ts"],"sourcesContent":["/**\n * Is a sandbox preview actually serving? (web `sandbox/previewProbe.ts`, #f99bd580, #fbd72c42)\n * e2b - and the platform's sandbox domain in front of it - answers a stopped dev server\n * or an expired sandbox with its own page, sometimes as HTTP 200, which a WebView shows\n * raw. So a preview is framed only once a probe saw the site itself answer.\n *\n * A phone has no CORS: the body is always readable, so the classification is exact.\n */\n\nexport const CLOSED_PORT_RE =\n /Closed Port Error|Update Port Error|Could Not Find|Connection refused on port|no service (running|listening|waiting)|THERE'?S NO SERVICE LISTENING|Port 3000 is no longer|is no longer running|no longer active/i;\nexport const SANDBOX_GONE_RE =\n /\\bSANDBOX_GONE\\b|Sandbox Not Found|Paused sandbox .+ not found|sandbox \\S+ not found|sandbox .*wasn'?t found|not found \\(404\\)|no sandbox found|does not exist|sandbox.*expired|sandbox.*killed|probably not running anymore|not running anymore|cannot be resumed|was (?:killed|deleted|destroyed)/i;\n\n/** `open`: the site answered; `port-closed`: the sandbox runs, its dev server does not; `gone`: no sandbox; `unknown`: no answer. */\nexport type PreviewProbe = 'open' | 'port-closed' | 'gone' | 'unknown';\n\n/** Only the start of a page is read: e2b's own pages say what they are near the top. */\nconst SNIFF_CHARS = 6_000;\nconst PROBE_TIMEOUT_MS = 8_000;\n\n/** What an HTTP answer from a preview URL means. */\nexport function classifyPreviewAnswer(status: number, body: string): PreviewProbe {\n const head = String(body || '').slice(0, SNIFF_CHARS);\n if (SANDBOX_GONE_RE.test(head)) return 'gone';\n if (CLOSED_PORT_RE.test(head)) return 'port-closed';\n if (status >= 500) return 'port-closed';\n if (status === 404 && /e2b|sandbox/i.test(head)) return 'gone';\n return 'open';\n}\n\n/** One probe of a preview URL (GET, short timeout). Never throws. */\nexport async function probePreview(url: string, fetchImpl: typeof fetch = fetch): Promise<PreviewProbe> {\n if (!/^https?:\\/\\//i.test(url)) return 'unknown';\n const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;\n const timer = controller ? setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS) : null;\n try {\n const res = await fetchImpl(url, { method: 'GET', ...(controller ? { signal: controller.signal } : {}) });\n const body = await res.text().catch(() => '');\n return classifyPreviewAnswer(res.status, body);\n } catch {\n return 'unknown';\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** The site answered, or nothing did (no network to judge by): frame it. A known-dead page is never framed. */\nexport function mayFrame(probe: PreviewProbe): boolean {\n return probe === 'open' || probe === 'unknown';\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AASO,MAAM,cAAiB,GAAA;AACvB,MAAM,eAAkB,GAAA;AAM/B,MAAM,WAAc,GAAA,GAAA;AACpB,MAAM,gBAAmB,GAAA,GAAA;AAGT,SAAA,qBAAA,CAAsB,QAAgB,IAA4B,EAAA;AAChF,EAAA,MAAM,OAAO,MAAO,CAAA,IAAA,IAAQ,EAAE,CAAE,CAAA,KAAA,CAAM,GAAG,WAAW,CAAA;AACpD,EAAA,IAAI,eAAgB,CAAA,IAAA,CAAK,IAAI,CAAA,EAAU,OAAA,MAAA;AACvC,EAAA,IAAI,cAAe,CAAA,IAAA,CAAK,IAAI,CAAA,EAAU,OAAA,aAAA;AACtC,EAAI,IAAA,MAAA,IAAU,KAAY,OAAA,aAAA;AAC1B,EAAA,IAAI,WAAW,GAAO,IAAA,cAAA,CAAe,IAAK,CAAA,IAAI,GAAU,OAAA,MAAA;AACxD,EAAO,OAAA,MAAA;AACT;AAGsB,eAAA,YAAA,CAAa,GAAa,EAAA,SAAA,GAA0B,KAA8B,EAAA;AACtG,EAAA,IAAI,CAAC,eAAA,CAAgB,IAAK,CAAA,GAAG,GAAU,OAAA,SAAA;AACvC,EAAA,MAAM,aAAa,OAAO,eAAA,KAAoB,WAAc,GAAA,IAAI,iBAAoB,GAAA,IAAA;AACpF,EAAM,MAAA,KAAA,GAAQ,aAAa,UAAW,CAAA,MAAM,WAAW,KAAM,EAAA,EAAG,gBAAgB,CAAI,GAAA,IAAA;AACpF,EAAI,IAAA;AACF,IAAM,MAAA,GAAA,GAAM,MAAM,SAAA,CAAU,GAAK,EAAA,cAAA,CAAA;AAAA,MAC/B,MAAQ,EAAA;AAAA,KAAA,EACJ,UAAa,GAAA;AAAA,MACf,QAAQ,UAAW,CAAA;AAAA,KACrB,GAAI,EACL,CAAA,CAAA;AACD,IAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAO,CAAA,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,IAAO,OAAA,qBAAA,CAAsB,GAAI,CAAA,MAAA,EAAQ,IAAI,CAAA;AAAA,GACvC,CAAA,OAAA,CAAA,EAAA;AACN,IAAO,OAAA,SAAA;AAAA,GACP,SAAA;AACA,IAAI,IAAA,KAAA,eAAoB,KAAK,CAAA;AAAA;AAEjC;AAGO,SAAS,SAAS,KAA8B,EAAA;AACrD,EAAO,OAAA,KAAA,KAAU,UAAU,KAAU,KAAA,SAAA;AACvC"}
|