frappe-builder 1.1.0-dev.22 → 1.1.0-dev.25

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/.fb/state.db CHANGED
Binary file
@@ -2,13 +2,13 @@ feature_id: po-approval
2
2
  feature_name: "PO Approval"
3
3
  mode: full
4
4
  phase: testing
5
- updated_at: 2026-03-28T14:14:28.658Z
5
+ updated_at: 2026-03-28T14:37:54.966Z
6
6
 
7
7
  components:
8
8
  - id: final-comp
9
9
  sort_order: 0
10
10
  status: complete
11
- completed_at: 2026-03-28T14:14:28.658Z
11
+ completed_at: 2026-03-28T14:37:54.965Z
12
12
 
13
13
  progress:
14
14
  done: 1
@@ -0,0 +1,318 @@
1
+ __vite_ssr_exportName__("patchGitignore", () => { try { return patchGitignore } catch {} });
2
+ __vite_ssr_exportName__("runInit", () => { try { return runInit } catch {} });
3
+ __vite_ssr_exportName__("setupContextMode", () => { try { return setupContextMode } catch {} });
4
+ __vite_ssr_exportName__("setupMcp2cli", () => { try { return setupMcp2cli } catch {} });
5
+ const __vite_ssr_import_0__ = await __vite_ssr_import__("node:fs", {"importedNames":["mkdirSync","existsSync","readFileSync","writeFileSync","renameSync"]});
6
+ const __vite_ssr_import_1__ = await __vite_ssr_import__("node:path", {"importedNames":["join"]});
7
+ const __vite_ssr_import_2__ = await __vite_ssr_import__("node:os", {"importedNames":["homedir"]});
8
+ const __vite_ssr_import_3__ = await __vite_ssr_import__("node:readline", {"importedNames":["createInterface"]});
9
+ const __vite_ssr_import_4__ = await __vite_ssr_import__("node:child_process", {"importedNames":["spawnSync"]});
10
+ /**
11
+ * src/init.ts — interactive setup wizard for frappe-builder
12
+ *
13
+ * Handles: global config (~/.frappe-builder/config.json),
14
+ * project config (.frappe-builder-config.json),
15
+ * and .gitignore patching.
16
+ *
17
+ * No imports from state/, extensions/, or gates/.
18
+ * Uses Node.js built-ins only — no external prompt libraries.
19
+ */
20
+
21
+
22
+
23
+
24
+
25
+ let cancelled = false;
26
+ process.on("SIGINT", () => {
27
+ cancelled = true;
28
+ });
29
+ function promptLine(question) {
30
+ return new Promise((resolve) => {
31
+ if (cancelled) {
32
+ resolve("");
33
+ return;
34
+ };
35
+ const rl = (0,__vite_ssr_import_3__.createInterface)({
36
+ input: process.stdin,
37
+ output: process.stdout
38
+ });
39
+ rl.question(question, (answer) => {
40
+ rl.close();
41
+ resolve(answer);
42
+ });
43
+ });
44
+ }
45
+ async function promptYN(question) {
46
+ const answer = await promptLine(question + " (y/N): ");
47
+ return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
48
+ }
49
+ function writeAtomic(filePath, content) {
50
+ const tmp = filePath + ".tmp";
51
+ (0,__vite_ssr_import_0__.writeFileSync)(tmp, content, "utf-8");
52
+ (0,__vite_ssr_import_0__.renameSync)(tmp, filePath);
53
+ }
54
+ /** Patches .gitignore to include the exact entry if not already present. */
55
+ function patchGitignore(projectRoot, entry) {
56
+ const gitignorePath = (0,__vite_ssr_import_1__.join)(projectRoot, ".gitignore");
57
+ if (!(0,__vite_ssr_import_0__.existsSync)(gitignorePath)) {
58
+ (0,__vite_ssr_import_0__.writeFileSync)(gitignorePath, entry + "\n", "utf-8");
59
+ return "created";
60
+ };
61
+ const content = (0,__vite_ssr_import_0__.readFileSync)(gitignorePath, "utf-8");
62
+ const lines = content.split("\n");
63
+ if (lines.includes(entry)) {
64
+ return "already-present";
65
+ };
66
+ const patched = content.endsWith("\n") ? content + entry + "\n" : content + "\n" + entry + "\n";
67
+ (0,__vite_ssr_import_0__.writeFileSync)(gitignorePath, patched, "utf-8");
68
+ return "patched";
69
+ };
70
+ async function runInit(opts = {}) {
71
+ const projectRoot = opts.projectRoot ?? process.cwd();
72
+ const homeDir = (0,__vite_ssr_import_2__.homedir)();
73
+ const globalConfigDir = (0,__vite_ssr_import_1__.join)(homeDir, ".frappe-builder");
74
+ const globalConfigPath = (0,__vite_ssr_import_1__.join)(globalConfigDir, "config.json");
75
+ const projectConfigPath = (0,__vite_ssr_import_1__.join)(projectRoot, ".frappe-builder-config.json");
76
+ console.log("\n=== frappe-builder Setup ===\n");
77
+ // ── Global config ────────────────────────────────────────────────────────
78
+ console.log(`[Global config: ${globalConfigPath}]`);
79
+ let globalConfig = {};
80
+ let globalAction = "written";
81
+ if ((0,__vite_ssr_import_0__.existsSync)(globalConfigPath)) {
82
+ try {
83
+ globalConfig = JSON.parse((0,__vite_ssr_import_0__.readFileSync)(globalConfigPath, "utf-8"));
84
+ } catch {};
85
+ if (!cancelled) {
86
+ const overwrite = await promptYN(`Overwrite existing ${globalConfigPath}?`);
87
+ if (cancelled) {
88
+ printCancelled();
89
+ return;
90
+ };
91
+ if (!overwrite) {
92
+ globalAction = "skipped";
93
+ console.log(" Keeping existing global config.\n");
94
+ }
95
+ }
96
+ };
97
+ if (!cancelled && globalAction === "written") {
98
+ const llmKey = await promptLine("LLM API key (leave blank to skip): ");
99
+ if (cancelled) {
100
+ printCancelled();
101
+ return;
102
+ };
103
+ globalConfig.llm_api_key = llmKey.trim();
104
+ };
105
+ // ── Project config ───────────────────────────────────────────────────────
106
+ console.log(`\n[Project config: ${projectConfigPath}]`);
107
+ let projectConfig = {};
108
+ let projectAction = "written";
109
+ if ((0,__vite_ssr_import_0__.existsSync)(projectConfigPath)) {
110
+ try {
111
+ projectConfig = JSON.parse((0,__vite_ssr_import_0__.readFileSync)(projectConfigPath, "utf-8"));
112
+ } catch {};
113
+ if (!cancelled) {
114
+ const overwrite = await promptYN(`Overwrite existing ${projectConfigPath}?`);
115
+ if (cancelled) {
116
+ printCancelled();
117
+ return;
118
+ };
119
+ if (!overwrite) {
120
+ projectAction = "skipped";
121
+ console.log(" Keeping existing project config.\n");
122
+ }
123
+ }
124
+ };
125
+ if (!cancelled && projectAction === "written") {
126
+ const siteUrl = await promptLine("Frappe site URL (e.g. http://site1.localhost): ");
127
+ if (cancelled) {
128
+ printCancelled();
129
+ return;
130
+ };
131
+ const apiKey = await promptLine("Frappe API key: ");
132
+ if (cancelled) {
133
+ printCancelled();
134
+ return;
135
+ };
136
+ const apiSecret = await promptLine("Frappe API secret: ");
137
+ if (cancelled) {
138
+ printCancelled();
139
+ return;
140
+ };
141
+ projectConfig = {
142
+ site_url: siteUrl.trim(),
143
+ api_key: apiKey.trim(),
144
+ api_secret: apiSecret.trim()
145
+ };
146
+ };
147
+ // ── All prompts collected — now write files ──────────────────────────────
148
+ const written = [];
149
+ const skipped = [];
150
+ // Global config
151
+ if (globalAction === "written") {
152
+ (0,__vite_ssr_import_0__.mkdirSync)(globalConfigDir, { recursive: true });
153
+ writeAtomic(globalConfigPath, JSON.stringify(globalConfig, null, 2) + "\n");
154
+ written.push(`~/.frappe-builder/config.json`);
155
+ } else {
156
+ skipped.push(`~/.frappe-builder/config.json`);
157
+ };
158
+ // Project config
159
+ if (projectAction === "written") {
160
+ writeAtomic(projectConfigPath, JSON.stringify(projectConfig, null, 2) + "\n");
161
+ written.push(`.frappe-builder-config.json`);
162
+ } else {
163
+ skipped.push(`.frappe-builder-config.json`);
164
+ };
165
+ // Gitignore patch
166
+ const gitignoreResult = patchGitignore(projectRoot, ".frappe-builder-config.json");
167
+ if (gitignoreResult === "patched") {
168
+ written.push(".gitignore (patched)");
169
+ } else if (gitignoreResult === "created") {
170
+ written.push(".gitignore (created)");
171
+ } else {
172
+ skipped.push(".gitignore (entry already present)");
173
+ };
174
+ // ── context-mode MCP extension ───────────────────────────────────────────
175
+ await setupContextMode(homeDir);
176
+ // ── mcp2cli skill + context-mode bake ────────────────────────────────────
177
+ setupMcp2cli(homeDir);
178
+ // ── Summary ──────────────────────────────────────────────────────────────
179
+ console.log("\nFiles written:");
180
+ for (const f of written) {
181
+ console.log(` ✓ ${f}`);
182
+ };
183
+ if (skipped.length > 0) {
184
+ console.log("Skipped:");
185
+ for (const f of skipped) {
186
+ console.log(` - ${f}`);
187
+ }
188
+ };
189
+ console.log("\nReady. Run: frappe-builder\n");
190
+ };
191
+ function printCancelled() {
192
+ console.log("\nSetup cancelled. No files were written.\n");
193
+ }
194
+ /**
195
+ * Installs and configures the context-mode pi MCP extension.
196
+ * Clones https://github.com/mksglu/context-mode into ~/.pi/extensions/context-mode,
197
+ * builds it, and patches ~/.pi/settings/mcp.json with the server entry.
198
+ *
199
+ * Non-fatal — failures are logged as warnings, never abort init.
200
+ */
201
+ async function setupContextMode(homeDir) {
202
+ const extDir = (0,__vite_ssr_import_1__.join)(homeDir, ".pi", "extensions", "context-mode");
203
+ const mcpSettingsDir = (0,__vite_ssr_import_1__.join)(homeDir, ".pi", "settings");
204
+ const mcpSettingsPath = (0,__vite_ssr_import_1__.join)(mcpSettingsDir, "mcp.json");
205
+ const startScript = (0,__vite_ssr_import_1__.join)(extDir, "node_modules", "context-mode", "start.mjs");
206
+ console.log("\n[context-mode MCP extension]");
207
+ // ── Already installed? ──────────────────────────────────────────────────
208
+ if ((0,__vite_ssr_import_0__.existsSync)(extDir)) {
209
+ console.log(" ✓ context-mode already installed at ~/.pi/extensions/context-mode");
210
+ } else {
211
+ console.log(" context-mode not found — installing (requires git + Node.js)...");
212
+ (0,__vite_ssr_import_0__.mkdirSync)((0,__vite_ssr_import_1__.join)(homeDir, ".pi", "extensions"), { recursive: true });
213
+ const clone = (0,__vite_ssr_import_4__.spawnSync)("git", [
214
+ "clone",
215
+ "https://github.com/mksglu/context-mode.git",
216
+ extDir
217
+ ], { stdio: "pipe" });
218
+ if (clone.status !== 0) {
219
+ console.warn(` ⚠ git clone failed: ${clone.stderr?.toString().trim()}`);
220
+ console.warn(" Skipping context-mode setup. Install manually: https://github.com/mksglu/context-mode");
221
+ return;
222
+ };
223
+ const install = (0,__vite_ssr_import_4__.spawnSync)("npm", ["install"], {
224
+ cwd: extDir,
225
+ stdio: "pipe"
226
+ });
227
+ if (install.status !== 0) {
228
+ console.warn(` ⚠ npm install failed: ${install.stderr?.toString().trim()}`);
229
+ return;
230
+ };
231
+ const build = (0,__vite_ssr_import_4__.spawnSync)("npm", ["run", "build"], {
232
+ cwd: extDir,
233
+ stdio: "pipe"
234
+ });
235
+ if (build.status !== 0) {
236
+ console.warn(` ⚠ npm run build failed: ${build.stderr?.toString().trim()}`);
237
+ return;
238
+ };
239
+ console.log(" ✓ context-mode installed and built");
240
+ };
241
+ // ── Patch ~/.pi/settings/mcp.json ──────────────────────────────────────
242
+ (0,__vite_ssr_import_0__.mkdirSync)(mcpSettingsDir, { recursive: true });
243
+ let mcpConfig = {};
244
+ if ((0,__vite_ssr_import_0__.existsSync)(mcpSettingsPath)) {
245
+ try {
246
+ mcpConfig = JSON.parse((0,__vite_ssr_import_0__.readFileSync)(mcpSettingsPath, "utf-8"));
247
+ } catch {}
248
+ };
249
+ const servers = mcpConfig.mcpServers ?? {};
250
+ if (servers["context-mode"]) {
251
+ console.log(" ✓ context-mode already in ~/.pi/settings/mcp.json");
252
+ return;
253
+ };
254
+ servers["context-mode"] = {
255
+ command: "node",
256
+ args: [startScript]
257
+ };
258
+ mcpConfig.mcpServers = servers;
259
+ writeAtomic(mcpSettingsPath, JSON.stringify(mcpConfig, null, 2) + "\n");
260
+ console.log(" ✓ Added context-mode to ~/.pi/settings/mcp.json");
261
+ console.log(" Restart pi (or frappe-builder) for context-mode to activate.");
262
+ };
263
+ /**
264
+ * Installs the mcp2cli Claude Code skill and bakes the context-mode connection
265
+ * so the agent can call `mcp2cli @context-mode <tool>` without repeating flags.
266
+ *
267
+ * Non-fatal — failures are logged as warnings, never abort init.
268
+ */
269
+ function setupMcp2cli(homeDir) {
270
+ const startScript = (0,__vite_ssr_import_1__.join)(homeDir, ".pi", "extensions", "context-mode", "node_modules", "context-mode", "start.mjs");
271
+ console.log("\n[mcp2cli skill + context-mode bake]");
272
+ // ── Install mcp2cli Claude Code skill ───────────────────────────────────
273
+ const skillAdd = (0,__vite_ssr_import_4__.spawnSync)("npx", [
274
+ "skills",
275
+ "add",
276
+ "knowsuchagency/mcp2cli",
277
+ "--skill",
278
+ "mcp2cli"
279
+ ], { stdio: "pipe" });
280
+ if (skillAdd.status !== 0) {
281
+ console.warn(` ⚠ mcp2cli skill install failed: ${skillAdd.stderr?.toString().trim()}`);
282
+ console.warn(" Install manually: npx skills add knowsuchagency/mcp2cli --skill mcp2cli");
283
+ } else {
284
+ console.log(" ✓ mcp2cli skill installed");
285
+ };
286
+ // ── Bake context-mode connection ─────────────────────────────────────────
287
+ // Check if already baked
288
+ const bakeShow = (0,__vite_ssr_import_4__.spawnSync)("mcp2cli", [
289
+ "bake",
290
+ "show",
291
+ "context-mode"
292
+ ], { stdio: "pipe" });
293
+ if (bakeShow.status === 0) {
294
+ console.log(" ✓ mcp2cli @context-mode already baked");
295
+ return;
296
+ };
297
+ if (!(0,__vite_ssr_import_0__.existsSync)(startScript)) {
298
+ console.warn(" ⚠ context-mode start.mjs not found — skipping bake (run init again after context-mode installs)");
299
+ return;
300
+ };
301
+ const bakeCreate = (0,__vite_ssr_import_4__.spawnSync)("mcp2cli", [
302
+ "bake",
303
+ "create",
304
+ "context-mode",
305
+ "--mcp-stdio",
306
+ `node ${startScript}`
307
+ ], { stdio: "pipe" });
308
+ if (bakeCreate.status !== 0) {
309
+ console.warn(` ⚠ mcp2cli bake failed: ${bakeCreate.stderr?.toString().trim()}`);
310
+ console.warn(" Install mcp2cli first: pip install mcp2cli");
311
+ } else {
312
+ console.log(" ✓ mcp2cli @context-mode baked — agent can now call: mcp2cli @context-mode <tool>");
313
+ }
314
+ }
315
+ //# sourceMappingSource=vite-generated
316
+ //# sourceMappingURL=data:application/json;base64,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LEdBQUc7QUFDekIsVUFBUSxLQUFLLHFDQUFxQyxTQUFTLFFBQVEsVUFBVSxDQUFDLE1BQU0sR0FBRztBQUN2RixVQUFRLEtBQUssNEVBQTRFO1FBQ3BGO0FBQ0wsVUFBUSxJQUFJLDhCQUE4Qjs7OztDQUs1QyxNQUFNLGNBQVcsaUNBQVUsV0FBVztFQUFDO0VBQVE7RUFBUTtFQUFlLEVBQUUsRUFBRSxPQUFPLFFBQVEsQ0FBQztBQUMxRixLQUFJLFNBQVMsV0FBVyxHQUFHO0FBQ3pCLFVBQVEsSUFBSSwwQ0FBMEM7QUFDdEQ7O0FBR0YsS0FBSSxJQUFDLGtDQUFXLFlBQVksRUFBRTtBQUM1QixVQUFRLEtBQUssb0dBQW9HO0FBQ2pIOztDQUdGLE1BQU0sZ0JBQWEsaUNBQ2pCLFdBQ0E7RUFBQztFQUFRO0VBQVU7RUFBZ0I7RUFBZSxRQUFRO0VBQWMsRUFDeEUsRUFBRSxPQUFPLFFBQVEsQ0FDbEI7QUFDRCxLQUFJLFdBQVcsV0FBVyxHQUFHO0FBQzNCLFVBQVEsS0FBSyw0QkFBNEIsV0FBVyxRQUFRLFVBQVUsQ0FBQyxNQUFNLEdBQUc7QUFDaEYsVUFBUSxLQUFLLCtDQUErQztRQUN2RDtBQUNMLFVBQVEsSUFBSSxxRkFBcUYiLCJuYW1lcyI6W10sImlnbm9yZUxpc3QiOltdLCJzb3VyY2VzIjpbImluaXQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBzcmMvaW5pdC50cyDigJQgaW50ZXJhY3RpdmUgc2V0dXAgd2l6YXJkIGZvciBmcmFwcGUtYnVpbGRlclxuICpcbiAqIEhhbmRsZXM6IGdsb2JhbCBjb25maWcgKH4vLmZyYXBwZS1idWlsZGVyL2NvbmZpZy5qc29uKSxcbiAqICAgICAgICAgIHByb2plY3QgY29uZmlnICguZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb24pLFxuICogICAgICAgICAgYW5kIC5naXRpZ25vcmUgcGF0Y2hpbmcuXG4gKlxuICogTm8gaW1wb3J0cyBmcm9tIHN0YXRlLywgZXh0ZW5zaW9ucy8sIG9yIGdhdGVzLy5cbiAqIFVzZXMgTm9kZS5qcyBidWlsdC1pbnMgb25seSDigJQgbm8gZXh0ZXJuYWwgcHJvbXB0IGxpYnJhcmllcy5cbiAqL1xuXG5pbXBvcnQgeyBta2RpclN5bmMsIGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYywgcmVuYW1lU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgaG9tZWRpciB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBjcmVhdGVJbnRlcmZhY2UgfSBmcm9tIFwibm9kZTpyZWFkbGluZVwiO1xuaW1wb3J0IHsgc3Bhd25TeW5jIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuXG5sZXQgY2FuY2VsbGVkID0gZmFsc2U7XG5cbnByb2Nlc3Mub24oXCJTSUdJTlRcIiwgKCkgPT4ge1xuICBjYW5jZWxsZWQgPSB0cnVlO1xufSk7XG5cbmZ1bmN0aW9uIHByb21wdExpbmUocXVlc3Rpb246IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGlmIChjYW5jZWxsZWQpIHsgcmVzb2x2ZShcIlwiKTsgcmV0dXJuOyB9XG4gICAgY29uc3QgcmwgPSBjcmVhdGVJbnRlcmZhY2UoeyBpbnB1dDogcHJvY2Vzcy5zdGRpbiwgb3V0cHV0OiBwcm9jZXNzLnN0ZG91dCB9KTtcbiAgICBybC5xdWVzdGlvbihxdWVzdGlvbiwgKGFuc3dlcikgPT4ge1xuICAgICAgcmwuY2xvc2UoKTtcbiAgICAgIHJlc29sdmUoYW5zd2VyKTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHByb21wdFlOKHF1ZXN0aW9uOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgYW5zd2VyID0gYXdhaXQgcHJvbXB0TGluZShxdWVzdGlvbiArIFwiICh5L04pOiBcIik7XG4gIHJldHVybiBhbnN3ZXIudHJpbSgpLnRvTG93ZXJDYXNlKCkgPT09IFwieVwiIHx8IGFuc3dlci50cmltKCkudG9Mb3dlckNhc2UoKSA9PT0gXCJ5ZXNcIjtcbn1cblxuZnVuY3Rpb24gd3JpdGVBdG9taWMoZmlsZVBhdGg6IHN0cmluZywgY29udGVudDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IHRtcCA9IGZpbGVQYXRoICsgXCIudG1wXCI7XG4gIHdyaXRlRmlsZVN5bmModG1wLCBjb250ZW50LCBcInV0Zi04XCIpO1xuICByZW5hbWVTeW5jKHRtcCwgZmlsZVBhdGgpO1xufVxuXG4vKiogUGF0Y2hlcyAuZ2l0aWdub3JlIHRvIGluY2x1ZGUgdGhlIGV4YWN0IGVudHJ5IGlmIG5vdCBhbHJlYWR5IHByZXNlbnQuICovXG5leHBvcnQgZnVuY3Rpb24gcGF0Y2hHaXRpZ25vcmUocHJvamVjdFJvb3Q6IHN0cmluZywgZW50cnk6IHN0cmluZyk6IFwicGF0Y2hlZFwiIHwgXCJhbHJlYWR5LXByZXNlbnRcIiB8IFwiY3JlYXRlZFwiIHtcbiAgY29uc3QgZ2l0aWdub3JlUGF0aCA9IGpvaW4ocHJvamVjdFJvb3QsIFwiLmdpdGlnbm9yZVwiKTtcbiAgaWYgKCFleGlzdHNTeW5jKGdpdGlnbm9yZVBhdGgpKSB7XG4gICAgd3JpdGVGaWxlU3luYyhnaXRpZ25vcmVQYXRoLCBlbnRyeSArIFwiXFxuXCIsIFwidXRmLThcIik7XG4gICAgcmV0dXJuIFwiY3JlYXRlZFwiO1xuICB9XG4gIGNvbnN0IGNvbnRlbnQgPSByZWFkRmlsZVN5bmMoZ2l0aWdub3JlUGF0aCwgXCJ1dGYtOFwiKTtcbiAgY29uc3QgbGluZXMgPSBjb250ZW50LnNwbGl0KFwiXFxuXCIpO1xuICBpZiAobGluZXMuaW5jbHVkZXMoZW50cnkpKSB7XG4gICAgcmV0dXJuIFwiYWxyZWFkeS1wcmVzZW50XCI7XG4gIH1cbiAgY29uc3QgcGF0Y2hlZCA9IGNvbnRlbnQuZW5kc1dpdGgoXCJcXG5cIikgPyBjb250ZW50ICsgZW50cnkgKyBcIlxcblwiIDogY29udGVudCArIFwiXFxuXCIgKyBlbnRyeSArIFwiXFxuXCI7XG4gIHdyaXRlRmlsZVN5bmMoZ2l0aWdub3JlUGF0aCwgcGF0Y2hlZCwgXCJ1dGYtOFwiKTtcbiAgcmV0dXJuIFwicGF0Y2hlZFwiO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuSW5pdChvcHRzOiB7IHByb2plY3RSb290Pzogc3RyaW5nIH0gPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBwcm9qZWN0Um9vdCA9IG9wdHMucHJvamVjdFJvb3QgPz8gcHJvY2Vzcy5jd2QoKTtcbiAgY29uc3QgaG9tZURpciA9IGhvbWVkaXIoKTtcbiAgY29uc3QgZ2xvYmFsQ29uZmlnRGlyID0gam9pbihob21lRGlyLCBcIi5mcmFwcGUtYnVpbGRlclwiKTtcbiAgY29uc3QgZ2xvYmFsQ29uZmlnUGF0aCA9IGpvaW4oZ2xvYmFsQ29uZmlnRGlyLCBcImNvbmZpZy5qc29uXCIpO1xuICBjb25zdCBwcm9qZWN0Q29uZmlnUGF0aCA9IGpvaW4ocHJvamVjdFJvb3QsIFwiLmZyYXBwZS1idWlsZGVyLWNvbmZpZy5qc29uXCIpO1xuXG4gIGNvbnNvbGUubG9nKFwiXFxuPT09IGZyYXBwZS1idWlsZGVyIFNldHVwID09PVxcblwiKTtcblxuICAvLyDilIDilIAgR2xvYmFsIGNvbmZpZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgY29uc29sZS5sb2coYFtHbG9iYWwgY29uZmlnOiAke2dsb2JhbENvbmZpZ1BhdGh9XWApO1xuXG4gIGxldCBnbG9iYWxDb25maWc6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gIGxldCBnbG9iYWxBY3Rpb246IFwid3JpdHRlblwiIHwgXCJza2lwcGVkXCIgPSBcIndyaXR0ZW5cIjtcblxuICBpZiAoZXhpc3RzU3luYyhnbG9iYWxDb25maWdQYXRoKSkge1xuICAgIHRyeSB7XG4gICAgICBnbG9iYWxDb25maWcgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhnbG9iYWxDb25maWdQYXRoLCBcInV0Zi04XCIpKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB9IGNhdGNoIHsgLyogaWdub3JlIG1hbGZvcm1lZCBmaWxlIOKAlCBvdmVyd3JpdGUgKi8gfVxuICAgIGlmICghY2FuY2VsbGVkKSB7XG4gICAgICBjb25zdCBvdmVyd3JpdGUgPSBhd2FpdCBwcm9tcHRZTihgT3ZlcndyaXRlIGV4aXN0aW5nICR7Z2xvYmFsQ29uZmlnUGF0aH0/YCk7XG4gICAgICBpZiAoY2FuY2VsbGVkKSB7IHByaW50Q2FuY2VsbGVkKCk7IHJldHVybjsgfVxuICAgICAgaWYgKCFvdmVyd3JpdGUpIHtcbiAgICAgICAgZ2xvYmFsQWN0aW9uID0gXCJza2lwcGVkXCI7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiICBLZWVwaW5nIGV4aXN0aW5nIGdsb2JhbCBjb25maWcuXFxuXCIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmICghY2FuY2VsbGVkICYmIGdsb2JhbEFjdGlvbiA9PT0gXCJ3cml0dGVuXCIpIHtcbiAgICBjb25zdCBsbG1LZXkgPSBhd2FpdCBwcm9tcHRMaW5lKFwiTExNIEFQSSBrZXkgKGxlYXZlIGJsYW5rIHRvIHNraXApOiBcIik7XG4gICAgaWYgKGNhbmNlbGxlZCkgeyBwcmludENhbmNlbGxlZCgpOyByZXR1cm47IH1cbiAgICBnbG9iYWxDb25maWcubGxtX2FwaV9rZXkgPSBsbG1LZXkudHJpbSgpO1xuICB9XG5cbiAgLy8g4pSA4pSAIFByb2plY3QgY29uZmlnIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBjb25zb2xlLmxvZyhgXFxuW1Byb2plY3QgY29uZmlnOiAke3Byb2plY3RDb25maWdQYXRofV1gKTtcblxuICBsZXQgcHJvamVjdENvbmZpZzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgbGV0IHByb2plY3RBY3Rpb246IFwid3JpdHRlblwiIHwgXCJza2lwcGVkXCIgPSBcIndyaXR0ZW5cIjtcblxuICBpZiAoZXhpc3RzU3luYyhwcm9qZWN0Q29uZmlnUGF0aCkpIHtcbiAgICB0cnkge1xuICAgICAgcHJvamVjdENvbmZpZyA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHByb2plY3RDb25maWdQYXRoLCBcInV0Zi04XCIpKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICB9IGNhdGNoIHsgLyogaWdub3JlIG1hbGZvcm1lZCBmaWxlIOKAlCBvdmVyd3JpdGUgKi8gfVxuICAgIGlmICghY2FuY2VsbGVkKSB7XG4gICAgICBjb25zdCBvdmVyd3JpdGUgPSBhd2FpdCBwcm9tcHRZTihgT3ZlcndyaXRlIGV4aXN0aW5nICR7cHJvamVjdENvbmZpZ1BhdGh9P2ApO1xuICAgICAgaWYgKGNhbmNlbGxlZCkgeyBwcmludENhbmNlbGxlZCgpOyByZXR1cm47IH1cbiAgICAgIGlmICghb3ZlcndyaXRlKSB7XG4gICAgICAgIHByb2plY3RBY3Rpb24gPSBcInNraXBwZWRcIjtcbiAgICAgICAgY29uc29sZS5sb2coXCIgIEtlZXBpbmcgZXhpc3RpbmcgcHJvamVjdCBjb25maWcuXFxuXCIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmICghY2FuY2VsbGVkICYmIHByb2plY3RBY3Rpb24gPT09IFwid3JpdHRlblwiKSB7XG4gICAgY29uc3Qgc2l0ZVVybCA9IGF3YWl0IHByb21wdExpbmUoXCJGcmFwcGUgc2l0ZSBVUkwgKGUuZy4gaHR0cDovL3NpdGUxLmxvY2FsaG9zdCk6IFwiKTtcbiAgICBpZiAoY2FuY2VsbGVkKSB7IHByaW50Q2FuY2VsbGVkKCk7IHJldHVybjsgfVxuICAgIGNvbnN0IGFwaUtleSA9IGF3YWl0IHByb21wdExpbmUoXCJGcmFwcGUgQVBJIGtleTogXCIpO1xuICAgIGlmIChjYW5jZWxsZWQpIHsgcHJpbnRDYW5jZWxsZWQoKTsgcmV0dXJuOyB9XG4gICAgY29uc3QgYXBpU2VjcmV0ID0gYXdhaXQgcHJvbXB0TGluZShcIkZyYXBwZSBBUEkgc2VjcmV0OiBcIik7XG4gICAgaWYgKGNhbmNlbGxlZCkgeyBwcmludENhbmNlbGxlZCgpOyByZXR1cm47IH1cbiAgICBwcm9qZWN0Q29uZmlnID0ge1xuICAgICAgc2l0ZV91cmw6IHNpdGVVcmwudHJpbSgpLFxuICAgICAgYXBpX2tleTogYXBpS2V5LnRyaW0oKSxcbiAgICAgIGFwaV9zZWNyZXQ6IGFwaVNlY3JldC50cmltKCksXG4gICAgfTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBBbGwgcHJvbXB0cyBjb2xsZWN0ZWQg4oCUIG5vdyB3cml0ZSBmaWxlcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgY29uc3Qgd3JpdHRlbjogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgc2tpcHBlZDogc3RyaW5nW10gPSBbXTtcblxuICAvLyBHbG9iYWwgY29uZmlnXG4gIGlmIChnbG9iYWxBY3Rpb24gPT09IFwid3JpdHRlblwiKSB7XG4gICAgbWtkaXJTeW5jKGdsb2JhbENvbmZpZ0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgd3JpdGVBdG9taWMoZ2xvYmFsQ29uZmlnUGF0aCwgSlNPTi5zdHJpbmdpZnkoZ2xvYmFsQ29uZmlnLCBudWxsLCAyKSArIFwiXFxuXCIpO1xuICAgIHdyaXR0ZW4ucHVzaChgfi8uZnJhcHBlLWJ1aWxkZXIvY29uZmlnLmpzb25gKTtcbiAgfSBlbHNlIHtcbiAgICBza2lwcGVkLnB1c2goYH4vLmZyYXBwZS1idWlsZGVyL2NvbmZpZy5qc29uYCk7XG4gIH1cblxuICAvLyBQcm9qZWN0IGNvbmZpZ1xuICBpZiAocHJvamVjdEFjdGlvbiA9PT0gXCJ3cml0dGVuXCIpIHtcbiAgICB3cml0ZUF0b21pYyhwcm9qZWN0Q29uZmlnUGF0aCwgSlNPTi5zdHJpbmdpZnkocHJvamVjdENvbmZpZywgbnVsbCwgMikgKyBcIlxcblwiKTtcbiAgICB3cml0dGVuLnB1c2goYC5mcmFwcGUtYnVpbGRlci1jb25maWcuanNvbmApO1xuICB9IGVsc2Uge1xuICAgIHNraXBwZWQucHVzaChgLmZyYXBwZS1idWlsZGVyLWNvbmZpZy5qc29uYCk7XG4gIH1cblxuICAvLyBHaXRpZ25vcmUgcGF0Y2hcbiAgY29uc3QgZ2l0aWdub3JlUmVzdWx0ID0gcGF0Y2hHaXRpZ25vcmUocHJvamVjdFJvb3QsIFwiLmZyYXBwZS1idWlsZGVyLWNvbmZpZy5qc29uXCIpO1xuICBpZiAoZ2l0aWdub3JlUmVzdWx0ID09PSBcInBhdGNoZWRcIikge1xuICAgIHdyaXR0ZW4ucHVzaChcIi5naXRpZ25vcmUgKHBhdGNoZWQpXCIpO1xuICB9IGVsc2UgaWYgKGdpdGlnbm9yZVJlc3VsdCA9PT0gXCJjcmVhdGVkXCIpIHtcbiAgICB3cml0dGVuLnB1c2goXCIuZ2l0aWdub3JlIChjcmVhdGVkKVwiKTtcbiAgfSBlbHNlIHtcbiAgICBza2lwcGVkLnB1c2goXCIuZ2l0aWdub3JlIChlbnRyeSBhbHJlYWR5IHByZXNlbnQpXCIpO1xuICB9XG5cbiAgLy8g4pSA4pSAIGNvbnRleHQtbW9kZSBNQ1AgZXh0ZW5zaW9uIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBhd2FpdCBzZXR1cENvbnRleHRNb2RlKGhvbWVEaXIpO1xuXG4gIC8vIOKUgOKUgCBtY3AyY2xpIHNraWxsICsgY29udGV4dC1tb2RlIGJha2Ug4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHNldHVwTWNwMmNsaShob21lRGlyKTtcblxuICAvLyDilIDilIAgU3VtbWFyeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgY29uc29sZS5sb2coXCJcXG5GaWxlcyB3cml0dGVuOlwiKTtcbiAgZm9yIChjb25zdCBmIG9mIHdyaXR0ZW4pIHtcbiAgICBjb25zb2xlLmxvZyhgICDinJMgJHtmfWApO1xuICB9XG4gIGlmIChza2lwcGVkLmxlbmd0aCA+IDApIHtcbiAgICBjb25zb2xlLmxvZyhcIlNraXBwZWQ6XCIpO1xuICAgIGZvciAoY29uc3QgZiBvZiBza2lwcGVkKSB7XG4gICAgICBjb25zb2xlLmxvZyhgICAtICR7Zn1gKTtcbiAgICB9XG4gIH1cblxuICBjb25zb2xlLmxvZyhcIlxcblJlYWR5LiBSdW46IGZyYXBwZS1idWlsZGVyXFxuXCIpO1xufVxuXG5mdW5jdGlvbiBwcmludENhbmNlbGxlZCgpOiB2b2lkIHtcbiAgY29uc29sZS5sb2coXCJcXG5TZXR1cCBjYW5jZWxsZWQuIE5vIGZpbGVzIHdlcmUgd3JpdHRlbi5cXG5cIik7XG59XG5cbi8qKlxuICogSW5zdGFsbHMgYW5kIGNvbmZpZ3VyZXMgdGhlIGNvbnRleHQtbW9kZSBwaSBNQ1AgZXh0ZW5zaW9uLlxuICogQ2xvbmVzIGh0dHBzOi8vZ2l0aHViLmNvbS9ta3NnbHUvY29udGV4dC1tb2RlIGludG8gfi8ucGkvZXh0ZW5zaW9ucy9jb250ZXh0LW1vZGUsXG4gKiBidWlsZHMgaXQsIGFuZCBwYXRjaGVzIH4vLnBpL3NldHRpbmdzL21jcC5qc29uIHdpdGggdGhlIHNlcnZlciBlbnRyeS5cbiAqXG4gKiBOb24tZmF0YWwg4oCUIGZhaWx1cmVzIGFyZSBsb2dnZWQgYXMgd2FybmluZ3MsIG5ldmVyIGFib3J0IGluaXQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZXR1cENvbnRleHRNb2RlKGhvbWVEaXI6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBleHREaXIgPSBqb2luKGhvbWVEaXIsIFwiLnBpXCIsIFwiZXh0ZW5zaW9uc1wiLCBcImNvbnRleHQtbW9kZVwiKTtcbiAgY29uc3QgbWNwU2V0dGluZ3NEaXIgPSBqb2luKGhvbWVEaXIsIFwiLnBpXCIsIFwic2V0dGluZ3NcIik7XG4gIGNvbnN0IG1jcFNldHRpbmdzUGF0aCA9IGpvaW4obWNwU2V0dGluZ3NEaXIsIFwibWNwLmpzb25cIik7XG4gIGNvbnN0IHN0YXJ0U2NyaXB0ID0gam9pbihleHREaXIsIFwibm9kZV9tb2R1bGVzXCIsIFwiY29udGV4dC1tb2RlXCIsIFwic3RhcnQubWpzXCIpO1xuXG4gIGNvbnNvbGUubG9nKFwiXFxuW2NvbnRleHQtbW9kZSBNQ1AgZXh0ZW5zaW9uXVwiKTtcblxuICAvLyDilIDilIAgQWxyZWFkeSBpbnN0YWxsZWQ/IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBpZiAoZXhpc3RzU3luYyhleHREaXIpKSB7XG4gICAgY29uc29sZS5sb2coXCIgIOKckyBjb250ZXh0LW1vZGUgYWxyZWFkeSBpbnN0YWxsZWQgYXQgfi8ucGkvZXh0ZW5zaW9ucy9jb250ZXh0LW1vZGVcIik7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coXCIgIGNvbnRleHQtbW9kZSBub3QgZm91bmQg4oCUIGluc3RhbGxpbmcgKHJlcXVpcmVzIGdpdCArIE5vZGUuanMpLi4uXCIpO1xuICAgIG1rZGlyU3luYyhqb2luKGhvbWVEaXIsIFwiLnBpXCIsIFwiZXh0ZW5zaW9uc1wiKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICBjb25zdCBjbG9uZSA9IHNwYXduU3luYyhcImdpdFwiLCBbXG4gICAgICBcImNsb25lXCIsIFwiaHR0cHM6Ly9naXRodWIuY29tL21rc2dsdS9jb250ZXh0LW1vZGUuZ2l0XCIsIGV4dERpcixcbiAgICBdLCB7IHN0ZGlvOiBcInBpcGVcIiB9KTtcblxuICAgIGlmIChjbG9uZS5zdGF0dXMgIT09IDApIHtcbiAgICAgIGNvbnNvbGUud2FybihgICDimqAgZ2l0IGNsb25lIGZhaWxlZDogJHtjbG9uZS5zdGRlcnI/LnRvU3RyaW5nKCkudHJpbSgpfWApO1xuICAgICAgY29uc29sZS53YXJuKFwiICBTa2lwcGluZyBjb250ZXh0LW1vZGUgc2V0dXAuIEluc3RhbGwgbWFudWFsbHk6IGh0dHBzOi8vZ2l0aHViLmNvbS9ta3NnbHUvY29udGV4dC1tb2RlXCIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGluc3RhbGwgPSBzcGF3blN5bmMoXCJucG1cIiwgW1wiaW5zdGFsbFwiXSwgeyBjd2Q6IGV4dERpciwgc3RkaW86IFwicGlwZVwiIH0pO1xuICAgIGlmIChpbnN0YWxsLnN0YXR1cyAhPT0gMCkge1xuICAgICAgY29uc29sZS53YXJuKGAgIOKaoCBucG0gaW5zdGFsbCBmYWlsZWQ6ICR7aW5zdGFsbC5zdGRlcnI/LnRvU3RyaW5nKCkudHJpbSgpfWApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGJ1aWxkID0gc3Bhd25TeW5jKFwibnBtXCIsIFtcInJ1blwiLCBcImJ1aWxkXCJdLCB7IGN3ZDogZXh0RGlyLCBzdGRpbzogXCJwaXBlXCIgfSk7XG4gICAgaWYgKGJ1aWxkLnN0YXR1cyAhPT0gMCkge1xuICAgICAgY29uc29sZS53YXJuKGAgIOKaoCBucG0gcnVuIGJ1aWxkIGZhaWxlZDogJHtidWlsZC5zdGRlcnI/LnRvU3RyaW5nKCkudHJpbSgpfWApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKFwiICDinJMgY29udGV4dC1tb2RlIGluc3RhbGxlZCBhbmQgYnVpbHRcIik7XG4gIH1cblxuICAvLyDilIDilIAgUGF0Y2ggfi8ucGkvc2V0dGluZ3MvbWNwLmpzb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIG1rZGlyU3luYyhtY3BTZXR0aW5nc0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgbGV0IG1jcENvbmZpZzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgaWYgKGV4aXN0c1N5bmMobWNwU2V0dGluZ3NQYXRoKSkge1xuICAgIHRyeSB7XG4gICAgICBtY3BDb25maWcgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtY3BTZXR0aW5nc1BhdGgsIFwidXRmLThcIikpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIH0gY2F0Y2ggeyAvKiBvdmVyd3JpdGUgbWFsZm9ybWVkIGZpbGUgKi8gfVxuICB9XG5cbiAgY29uc3Qgc2VydmVycyA9IChtY3BDb25maWcubWNwU2VydmVycyA/PyB7fSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGlmIChzZXJ2ZXJzW1wiY29udGV4dC1tb2RlXCJdKSB7XG4gICAgY29uc29sZS5sb2coXCIgIOKckyBjb250ZXh0LW1vZGUgYWxyZWFkeSBpbiB+Ly5waS9zZXR0aW5ncy9tY3AuanNvblwiKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBzZXJ2ZXJzW1wiY29udGV4dC1tb2RlXCJdID0ge1xuICAgIGNvbW1hbmQ6IFwibm9kZVwiLFxuICAgIGFyZ3M6IFtzdGFydFNjcmlwdF0sXG4gIH07XG4gIG1jcENvbmZpZy5tY3BTZXJ2ZXJzID0gc2VydmVycztcblxuICB3cml0ZUF0b21pYyhtY3BTZXR0aW5nc1BhdGgsIEpTT04uc3RyaW5naWZ5KG1jcENvbmZpZywgbnVsbCwgMikgKyBcIlxcblwiKTtcbiAgY29uc29sZS5sb2coXCIgIOKckyBBZGRlZCBjb250ZXh0LW1vZGUgdG8gfi8ucGkvc2V0dGluZ3MvbWNwLmpzb25cIik7XG4gIGNvbnNvbGUubG9nKFwiICBSZXN0YXJ0IHBpIChvciBmcmFwcGUtYnVpbGRlcikgZm9yIGNvbnRleHQtbW9kZSB0byBhY3RpdmF0ZS5cIik7XG59XG5cbi8qKlxuICogSW5zdGFsbHMgdGhlIG1jcDJjbGkgQ2xhdWRlIENvZGUgc2tpbGwgYW5kIGJha2VzIHRoZSBjb250ZXh0LW1vZGUgY29ubmVjdGlvblxuICogc28gdGhlIGFnZW50IGNhbiBjYWxsIGBtY3AyY2xpIEBjb250ZXh0LW1vZGUgPHRvb2w+YCB3aXRob3V0IHJlcGVhdGluZyBmbGFncy5cbiAqXG4gKiBOb24tZmF0YWwg4oCUIGZhaWx1cmVzIGFyZSBsb2dnZWQgYXMgd2FybmluZ3MsIG5ldmVyIGFib3J0IGluaXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cE1jcDJjbGkoaG9tZURpcjogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IHN0YXJ0U2NyaXB0ID0gam9pbihcbiAgICBob21lRGlyLCBcIi5waVwiLCBcImV4dGVuc2lvbnNcIiwgXCJjb250ZXh0LW1vZGVcIixcbiAgICBcIm5vZGVfbW9kdWxlc1wiLCBcImNvbnRleHQtbW9kZVwiLCBcInN0YXJ0Lm1qc1wiXG4gICk7XG5cbiAgY29uc29sZS5sb2coXCJcXG5bbWNwMmNsaSBza2lsbCArIGNvbnRleHQtbW9kZSBiYWtlXVwiKTtcblxuICAvLyDilIDilIAgSW5zdGFsbCBtY3AyY2xpIENsYXVkZSBDb2RlIHNraWxsIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBjb25zdCBza2lsbEFkZCA9IHNwYXduU3luYyhcbiAgICBcIm5weFwiLFxuICAgIFtcInNraWxsc1wiLCBcImFkZFwiLCBcImtub3dzdWNoYWdlbmN5L21jcDJjbGlcIiwgXCItLXNraWxsXCIsIFwibWNwMmNsaVwiXSxcbiAgICB7IHN0ZGlvOiBcInBpcGVcIiB9XG4gICk7XG4gIGlmIChza2lsbEFkZC5zdGF0dXMgIT09IDApIHtcbiAgICBjb25zb2xlLndhcm4oYCAg4pqgIG1jcDJjbGkgc2tpbGwgaW5zdGFsbCBmYWlsZWQ6ICR7c2tpbGxBZGQuc3RkZXJyPy50b1N0cmluZygpLnRyaW0oKX1gKTtcbiAgICBjb25zb2xlLndhcm4oXCIgIEluc3RhbGwgbWFudWFsbHk6IG5weCBza2lsbHMgYWRkIGtub3dzdWNoYWdlbmN5L21jcDJjbGkgLS1za2lsbCBtY3AyY2xpXCIpO1xuICB9IGVsc2Uge1xuICAgIGNvbnNvbGUubG9nKFwiICDinJMgbWNwMmNsaSBza2lsbCBpbnN0YWxsZWRcIik7XG4gIH1cblxuICAvLyDilIDilIAgQmFrZSBjb250ZXh0LW1vZGUgY29ubmVjdGlvbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gQ2hlY2sgaWYgYWxyZWFkeSBiYWtlZFxuICBjb25zdCBiYWtlU2hvdyA9IHNwYXduU3luYyhcIm1jcDJjbGlcIiwgW1wiYmFrZVwiLCBcInNob3dcIiwgXCJjb250ZXh0LW1vZGVcIl0sIHsgc3RkaW86IFwicGlwZVwiIH0pO1xuICBpZiAoYmFrZVNob3cuc3RhdHVzID09PSAwKSB7XG4gICAgY29uc29sZS5sb2coXCIgIOKckyBtY3AyY2xpIEBjb250ZXh0LW1vZGUgYWxyZWFkeSBiYWtlZFwiKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoIWV4aXN0c1N5bmMoc3RhcnRTY3JpcHQpKSB7XG4gICAgY29uc29sZS53YXJuKFwiICDimqAgY29udGV4dC1tb2RlIHN0YXJ0Lm1qcyBub3QgZm91bmQg4oCUIHNraXBwaW5nIGJha2UgKHJ1biBpbml0IGFnYWluIGFmdGVyIGNvbnRleHQtbW9kZSBpbnN0YWxscylcIik7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgYmFrZUNyZWF0ZSA9IHNwYXduU3luYyhcbiAgICBcIm1jcDJjbGlcIixcbiAgICBbXCJiYWtlXCIsIFwiY3JlYXRlXCIsIFwiY29udGV4dC1tb2RlXCIsIFwiLS1tY3Atc3RkaW9cIiwgYG5vZGUgJHtzdGFydFNjcmlwdH1gXSxcbiAgICB7IHN0ZGlvOiBcInBpcGVcIiB9XG4gICk7XG4gIGlmIChiYWtlQ3JlYXRlLnN0YXR1cyAhPT0gMCkge1xuICAgIGNvbnNvbGUud2FybihgICDimqAgbWNwMmNsaSBiYWtlIGZhaWxlZDogJHtiYWtlQ3JlYXRlLnN0ZGVycj8udG9TdHJpbmcoKS50cmltKCl9YCk7XG4gICAgY29uc29sZS53YXJuKFwiICBJbnN0YWxsIG1jcDJjbGkgZmlyc3Q6IHBpcCBpbnN0YWxsIG1jcDJjbGlcIik7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coXCIgIOKckyBtY3AyY2xpIEBjb250ZXh0LW1vZGUgYmFrZWQg4oCUIGFnZW50IGNhbiBub3cgY2FsbDogbWNwMmNsaSBAY29udGV4dC1tb2RlIDx0b29sPlwiKTtcbiAgfVxufVxuIl0sImZpbGUiOiIvc3JjL2luaXQudHMifQ==
317
+
318
+ //# vitestCache=W3siZmlsZSI6IjEiLCJpZCI6IjEiLCJ1cmwiOiIyIiwiaW1wb3J0ZWRVcmxzIjoiMyIsIm1hcHBpbmdzIjpmYWxzZX0sIi9ob21lL3Jpei9mcmFwcGUtYnVpbGRlci9zcmMvaW5pdC50cyIsIi9zcmMvaW5pdC50cyIsW11d
@@ -0,0 +1,207 @@
1
+ const __vite_ssr_import_0__ = await __vite_ssr_import__("/node_modules/vitest/dist/index.js", {"importedNames":["describe","it","expect","vi","beforeEach","afterEach"]});
2
+ __vite_ssr_import_0__.vi.mock("node:os", async (importOriginal) => {
3
+ const actual = await importOriginal();
4
+ return {
5
+ ...actual,
6
+ homedir: __vite_ssr_import_0__.vi.fn(() => actual.homedir())
7
+ };
8
+ });
9
+ __vite_ssr_import_0__.vi.mock("node:readline", () => ({ createInterface: __vite_ssr_import_0__.vi.fn(() => ({
10
+ question: __vite_ssr_import_0__.vi.fn((_q, cb) => {
11
+ cb(mockAnswers.shift() ?? "");
12
+ }),
13
+ close: __vite_ssr_import_0__.vi.fn()
14
+ })) }));
15
+ const __vi_import_0__ = await __vite_ssr_dynamic_import__("node:fs");
16
+ const __vi_import_1__ = await __vite_ssr_dynamic_import__("node:path");
17
+ const __vi_import_2__ = await __vite_ssr_dynamic_import__("node:os");
18
+ const __vi_import_3__ = await __vite_ssr_dynamic_import__("/src/init.ts");
19
+
20
+
21
+
22
+ // ── Top-level mocks — must be hoisted before any imports that use them ───────
23
+ // Shared answer queue — tests push answers before calling runInit
24
+ const mockAnswers = [];
25
+
26
+
27
+ // ── patchGitignore ───────────────────────────────────────────────────────────
28
+ (0,__vite_ssr_import_0__.describe)("patchGitignore", () => {
29
+ let tmpDir;
30
+ (0,__vite_ssr_import_0__.beforeEach)(() => {
31
+ tmpDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-gitignore-"));
32
+ });
33
+ (0,__vite_ssr_import_0__.afterEach)(() => {
34
+ __vi_import_0__.rmSync(tmpDir, {
35
+ recursive: true,
36
+ force: true
37
+ });
38
+ });
39
+ (0,__vite_ssr_import_0__.it)("creates .gitignore from scratch when absent and adds the entry", () => {
40
+ const result = __vi_import_3__.patchGitignore(tmpDir, ".frappe-builder-config.json");
41
+ (0,__vite_ssr_import_0__.expect)(result).toBe("created");
42
+ const content = __vi_import_0__.readFileSync(__vi_import_1__.join(tmpDir, ".gitignore"), "utf-8");
43
+ (0,__vite_ssr_import_0__.expect)(content).toContain(".frappe-builder-config.json");
44
+ });
45
+ (0,__vite_ssr_import_0__.it)("appends line when .gitignore exists but entry is absent", () => {
46
+ __vi_import_0__.writeFileSync(__vi_import_1__.join(tmpDir, ".gitignore"), "node_modules\n.env\n", "utf-8");
47
+ const result = __vi_import_3__.patchGitignore(tmpDir, ".frappe-builder-config.json");
48
+ (0,__vite_ssr_import_0__.expect)(result).toBe("patched");
49
+ const content = __vi_import_0__.readFileSync(__vi_import_1__.join(tmpDir, ".gitignore"), "utf-8");
50
+ const lines = content.split("\n");
51
+ (0,__vite_ssr_import_0__.expect)(lines).toContain(".frappe-builder-config.json");
52
+ (0,__vite_ssr_import_0__.expect)(lines).toContain("node_modules");
53
+ (0,__vite_ssr_import_0__.expect)(lines).toContain(".env");
54
+ });
55
+ (0,__vite_ssr_import_0__.it)("does NOT duplicate entry when already present", () => {
56
+ __vi_import_0__.writeFileSync(__vi_import_1__.join(tmpDir, ".gitignore"), "node_modules\n.frappe-builder-config.json\n.env\n", "utf-8");
57
+ const result = __vi_import_3__.patchGitignore(tmpDir, ".frappe-builder-config.json");
58
+ (0,__vite_ssr_import_0__.expect)(result).toBe("already-present");
59
+ const content = __vi_import_0__.readFileSync(__vi_import_1__.join(tmpDir, ".gitignore"), "utf-8");
60
+ const count = content.split("\n").filter((l) => l === ".frappe-builder-config.json").length;
61
+ (0,__vite_ssr_import_0__.expect)(count).toBe(1);
62
+ });
63
+ (0,__vite_ssr_import_0__.it)("does NOT accept a glob pattern as a match — requires exact filename", () => {
64
+ __vi_import_0__.writeFileSync(__vi_import_1__.join(tmpDir, ".gitignore"), "*.json\n", "utf-8");
65
+ const result = __vi_import_3__.patchGitignore(tmpDir, ".frappe-builder-config.json");
66
+ (0,__vite_ssr_import_0__.expect)(result).toBe("patched");
67
+ });
68
+ });
69
+ // ── runInit — file writes ────────────────────────────────────────────────────
70
+ (0,__vite_ssr_import_0__.describe)("runInit — file writes", () => {
71
+ let projectDir;
72
+ let homeDir;
73
+ (0,__vite_ssr_import_0__.beforeEach)(() => {
74
+ projectDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-proj-"));
75
+ homeDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-home-"));
76
+ __vite_ssr_import_0__.vi.mocked(__vi_import_2__.homedir).mockReturnValue(homeDir);
77
+ mockAnswers.length = 0;
78
+ });
79
+ (0,__vite_ssr_import_0__.afterEach)(() => {
80
+ __vite_ssr_import_0__.vi.clearAllMocks();
81
+ __vi_import_0__.rmSync(projectDir, {
82
+ recursive: true,
83
+ force: true
84
+ });
85
+ __vi_import_0__.rmSync(homeDir, {
86
+ recursive: true,
87
+ force: true
88
+ });
89
+ });
90
+ (0,__vite_ssr_import_0__.it)("writes global config to ~/.frappe-builder/config.json", async () => {
91
+ // Answers: llm_api_key, site_url, api_key, api_secret
92
+ mockAnswers.push("sk-test", "http://erp.localhost", "key123", "secret456");
93
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
94
+ const configPath = __vi_import_1__.join(homeDir, ".frappe-builder", "config.json");
95
+ (0,__vite_ssr_import_0__.expect)(__vi_import_0__.existsSync(configPath)).toBe(true);
96
+ const cfg = JSON.parse(__vi_import_0__.readFileSync(configPath, "utf-8"));
97
+ (0,__vite_ssr_import_0__.expect)(cfg.llm_api_key).toBe("sk-test");
98
+ });
99
+ (0,__vite_ssr_import_0__.it)("writes project config to {projectRoot}/.frappe-builder-config.json", async () => {
100
+ mockAnswers.push("sk-test", "http://erp.localhost", "key123", "secret456");
101
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
102
+ const configPath = __vi_import_1__.join(projectDir, ".frappe-builder-config.json");
103
+ (0,__vite_ssr_import_0__.expect)(__vi_import_0__.existsSync(configPath)).toBe(true);
104
+ const cfg = JSON.parse(__vi_import_0__.readFileSync(configPath, "utf-8"));
105
+ (0,__vite_ssr_import_0__.expect)(cfg.site_url).toBe("http://erp.localhost");
106
+ (0,__vite_ssr_import_0__.expect)(cfg.api_key).toBe("key123");
107
+ (0,__vite_ssr_import_0__.expect)(cfg.api_secret).toBe("secret456");
108
+ });
109
+ (0,__vite_ssr_import_0__.it)("patches .gitignore automatically", async () => {
110
+ mockAnswers.push("sk-test", "http://erp.localhost", "key123", "secret456");
111
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
112
+ const content = __vi_import_0__.readFileSync(__vi_import_1__.join(projectDir, ".gitignore"), "utf-8");
113
+ (0,__vite_ssr_import_0__.expect)(content).toContain(".frappe-builder-config.json");
114
+ });
115
+ (0,__vite_ssr_import_0__.it)("creates ~/.frappe-builder/ directory if it does not exist", async () => {
116
+ mockAnswers.push("", "http://site.localhost", "k", "s");
117
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
118
+ (0,__vite_ssr_import_0__.expect)(__vi_import_0__.existsSync(__vi_import_1__.join(homeDir, ".frappe-builder"))).toBe(true);
119
+ });
120
+ });
121
+ // ── runInit — overwrite guard ────────────────────────────────────────────────
122
+ (0,__vite_ssr_import_0__.describe)("runInit — overwrite guard", () => {
123
+ let projectDir;
124
+ let homeDir;
125
+ (0,__vite_ssr_import_0__.beforeEach)(() => {
126
+ projectDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-guard-proj-"));
127
+ homeDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-guard-home-"));
128
+ __vite_ssr_import_0__.vi.mocked(__vi_import_2__.homedir).mockReturnValue(homeDir);
129
+ mockAnswers.length = 0;
130
+ });
131
+ (0,__vite_ssr_import_0__.afterEach)(() => {
132
+ __vite_ssr_import_0__.vi.clearAllMocks();
133
+ __vi_import_0__.rmSync(projectDir, {
134
+ recursive: true,
135
+ force: true
136
+ });
137
+ __vi_import_0__.rmSync(homeDir, {
138
+ recursive: true,
139
+ force: true
140
+ });
141
+ });
142
+ (0,__vite_ssr_import_0__.it)("does NOT overwrite existing global config when user declines", async () => {
143
+ const configDir = __vi_import_1__.join(homeDir, ".frappe-builder");
144
+ __vi_import_0__.mkdirSync(configDir, { recursive: true });
145
+ const globalPath = __vi_import_1__.join(configDir, "config.json");
146
+ __vi_import_0__.writeFileSync(globalPath, JSON.stringify({ llm_api_key: "original-key" }), "utf-8");
147
+ // Overwrite global? → "n" | Overwrite project? → "n"
148
+ mockAnswers.push("n", "n");
149
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
150
+ const cfg = JSON.parse(__vi_import_0__.readFileSync(globalPath, "utf-8"));
151
+ (0,__vite_ssr_import_0__.expect)(cfg.llm_api_key).toBe("original-key");
152
+ });
153
+ (0,__vite_ssr_import_0__.it)("overwrites existing global config when user confirms", async () => {
154
+ const configDir = __vi_import_1__.join(homeDir, ".frappe-builder");
155
+ __vi_import_0__.mkdirSync(configDir, { recursive: true });
156
+ const globalPath = __vi_import_1__.join(configDir, "config.json");
157
+ __vi_import_0__.writeFileSync(globalPath, JSON.stringify({ llm_api_key: "old-key" }), "utf-8");
158
+ // Overwrite global? → "y", new llm_key, site_url, api_key, api_secret
159
+ mockAnswers.push("y", "new-key", "http://site.localhost", "k", "s");
160
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
161
+ const cfg = JSON.parse(__vi_import_0__.readFileSync(globalPath, "utf-8"));
162
+ (0,__vite_ssr_import_0__.expect)(cfg.llm_api_key).toBe("new-key");
163
+ });
164
+ (0,__vite_ssr_import_0__.it)("does NOT overwrite existing project config when user declines", async () => {
165
+ const projConfigPath = __vi_import_1__.join(projectDir, ".frappe-builder-config.json");
166
+ __vi_import_0__.writeFileSync(projConfigPath, JSON.stringify({
167
+ site_url: "http://original.localhost",
168
+ api_key: "orig",
169
+ api_secret: "s"
170
+ }), "utf-8");
171
+ // llm_api_key prompt (no existing global), overwrite project? → "n"
172
+ mockAnswers.push("sk-new", "n");
173
+ await __vi_import_3__.runInit({ projectRoot: projectDir });
174
+ const cfg = JSON.parse(__vi_import_0__.readFileSync(projConfigPath, "utf-8"));
175
+ (0,__vite_ssr_import_0__.expect)(cfg.site_url).toBe("http://original.localhost");
176
+ });
177
+ });
178
+ // ── runInit — clean exit ─────────────────────────────────────────────────────
179
+ (0,__vite_ssr_import_0__.describe)("runInit — clean exit", () => {
180
+ let projectDir;
181
+ let homeDir;
182
+ (0,__vite_ssr_import_0__.beforeEach)(() => {
183
+ projectDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-exit-"));
184
+ homeDir = __vi_import_0__.mkdtempSync(__vi_import_1__.join("/tmp", "fb-init-exit-home-"));
185
+ __vite_ssr_import_0__.vi.mocked(__vi_import_2__.homedir).mockReturnValue(homeDir);
186
+ mockAnswers.length = 0;
187
+ });
188
+ (0,__vite_ssr_import_0__.afterEach)(() => {
189
+ __vite_ssr_import_0__.vi.clearAllMocks();
190
+ __vi_import_0__.rmSync(projectDir, {
191
+ recursive: true,
192
+ force: true
193
+ });
194
+ __vi_import_0__.rmSync(homeDir, {
195
+ recursive: true,
196
+ force: true
197
+ });
198
+ });
199
+ (0,__vite_ssr_import_0__.it)("resolves without throwing when all prompts return empty strings", async () => {
200
+ mockAnswers.push("", "", "", "");
201
+ await (0,__vite_ssr_import_0__.expect)(__vi_import_3__.runInit({ projectRoot: projectDir })).resolves.toBeUndefined();
202
+ });
203
+ });
204
+ //# sourceMappingSource=vite-generated
205
+ //# sourceMappingURL=data:application/json;base64,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b3JlTGlzdCI6W10sInNvdXJjZXMiOlsiaW5pdC50ZXN0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRlc2NyaWJlLCBpdCwgZXhwZWN0LCB2aSwgYmVmb3JlRWFjaCwgYWZ0ZXJFYWNoIH0gZnJvbSBcInZpdGVzdFwiO1xuaW1wb3J0IHsgbWtkdGVtcFN5bmMsIHJtU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcblxuLy8g4pSA4pSAIFRvcC1sZXZlbCBtb2NrcyDigJQgbXVzdCBiZSBob2lzdGVkIGJlZm9yZSBhbnkgaW1wb3J0cyB0aGF0IHVzZSB0aGVtIOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG52aS5tb2NrKFwibm9kZTpvc1wiLCBhc3luYyAoaW1wb3J0T3JpZ2luYWwpID0+IHtcbiAgY29uc3QgYWN0dWFsID0gYXdhaXQgaW1wb3J0T3JpZ2luYWw8dHlwZW9mIGltcG9ydChcIm5vZGU6b3NcIik+KCk7XG4gIHJldHVybiB7IC4uLmFjdHVhbCwgaG9tZWRpcjogdmkuZm4oKCkgPT4gYWN0dWFsLmhvbWVkaXIoKSkgfTtcbn0pO1xuXG4vLyBTaGFyZWQgYW5zd2VyIHF1ZXVlIOKAlCB0ZXN0cyBwdXNoIGFuc3dlcnMgYmVmb3JlIGNhbGxpbmcgcnVuSW5pdFxuY29uc3QgbW9ja0Fuc3dlcnM6IHN0cmluZ1tdID0gW107XG5cbnZpLm1vY2soXCJub2RlOnJlYWRsaW5lXCIsICgpID0+ICh7XG4gIGNyZWF0ZUludGVyZmFjZTogdmkuZm4oKCkgPT4gKHtcbiAgICBxdWVzdGlvbjogdmkuZm4oKF9xOiBzdHJpbmcsIGNiOiAoYTogc3RyaW5nKSA9PiB2b2lkKSA9PiB7XG4gICAgICBjYihtb2NrQW5zd2Vycy5zaGlmdCgpID8/IFwiXCIpO1xuICAgIH0pLFxuICAgIGNsb3NlOiB2aS5mbigpLFxuICB9KSksXG59KSk7XG5cbmltcG9ydCAqIGFzIG9zIGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBwYXRjaEdpdGlnbm9yZSwgcnVuSW5pdCB9IGZyb20gXCIuL2luaXQuanNcIjtcblxuLy8g4pSA4pSAIHBhdGNoR2l0aWdub3JlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5kZXNjcmliZShcInBhdGNoR2l0aWdub3JlXCIsICgpID0+IHtcbiAgbGV0IHRtcERpcjogc3RyaW5nO1xuXG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIHRtcERpciA9IG1rZHRlbXBTeW5jKGpvaW4oXCIvdG1wXCIsIFwiZmItaW5pdC1naXRpZ25vcmUtXCIpKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBybVN5bmModG1wRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gIH0pO1xuXG4gIGl0KFwiY3JlYXRlcyAuZ2l0aWdub3JlIGZyb20gc2NyYXRjaCB3aGVuIGFic2VudCBhbmQgYWRkcyB0aGUgZW50cnlcIiwgKCkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IHBhdGNoR2l0aWdub3JlKHRtcERpciwgXCIuZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb25cIik7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9CZShcImNyZWF0ZWRcIik7XG4gICAgY29uc3QgY29udGVudCA9IHJlYWRGaWxlU3luYyhqb2luKHRtcERpciwgXCIuZ2l0aWdub3JlXCIpLCBcInV0Zi04XCIpO1xuICAgIGV4cGVjdChjb250ZW50KS50b0NvbnRhaW4oXCIuZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb25cIik7XG4gIH0pO1xuXG4gIGl0KFwiYXBwZW5kcyBsaW5lIHdoZW4gLmdpdGlnbm9yZSBleGlzdHMgYnV0IGVudHJ5IGlzIGFic2VudFwiLCAoKSA9PiB7XG4gICAgd3JpdGVGaWxlU3luYyhqb2luKHRtcERpciwgXCIuZ2l0aWdub3JlXCIpLCBcIm5vZGVfbW9kdWxlc1xcbi5lbnZcXG5cIiwgXCJ1dGYtOFwiKTtcbiAgICBjb25zdCByZXN1bHQgPSBwYXRjaEdpdGlnbm9yZSh0bXBEaXIsIFwiLmZyYXBwZS1idWlsZGVyLWNvbmZpZy5qc29uXCIpO1xuICAgIGV4cGVjdChyZXN1bHQpLnRvQmUoXCJwYXRjaGVkXCIpO1xuICAgIGNvbnN0IGNvbnRlbnQgPSByZWFkRmlsZVN5bmMoam9pbih0bXBEaXIsIFwiLmdpdGlnbm9yZVwiKSwgXCJ1dGYtOFwiKTtcbiAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoXCJcXG5cIik7XG4gICAgZXhwZWN0KGxpbmVzKS50b0NvbnRhaW4oXCIuZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb25cIik7XG4gICAgZXhwZWN0KGxpbmVzKS50b0NvbnRhaW4oXCJub2RlX21vZHVsZXNcIik7XG4gICAgZXhwZWN0KGxpbmVzKS50b0NvbnRhaW4oXCIuZW52XCIpO1xuICB9KTtcblxuICBpdChcImRvZXMgTk9UIGR1cGxpY2F0ZSBlbnRyeSB3aGVuIGFscmVhZHkgcHJlc2VudFwiLCAoKSA9PiB7XG4gICAgd3JpdGVGaWxlU3luYyhcbiAgICAgIGpvaW4odG1wRGlyLCBcIi5naXRpZ25vcmVcIiksXG4gICAgICBcIm5vZGVfbW9kdWxlc1xcbi5mcmFwcGUtYnVpbGRlci1jb25maWcuanNvblxcbi5lbnZcXG5cIixcbiAgICAgIFwidXRmLThcIlxuICAgICk7XG4gICAgY29uc3QgcmVzdWx0ID0gcGF0Y2hHaXRpZ25vcmUodG1wRGlyLCBcIi5mcmFwcGUtYnVpbGRlci1jb25maWcuanNvblwiKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0JlKFwiYWxyZWFkeS1wcmVzZW50XCIpO1xuICAgIGNvbnN0IGNvbnRlbnQgPSByZWFkRmlsZVN5bmMoam9pbih0bXBEaXIsIFwiLmdpdGlnbm9yZVwiKSwgXCJ1dGYtOFwiKTtcbiAgICBjb25zdCBjb3VudCA9IGNvbnRlbnQuc3BsaXQoXCJcXG5cIikuZmlsdGVyKChsKSA9PiBsID09PSBcIi5mcmFwcGUtYnVpbGRlci1jb25maWcuanNvblwiKS5sZW5ndGg7XG4gICAgZXhwZWN0KGNvdW50KS50b0JlKDEpO1xuICB9KTtcblxuICBpdChcImRvZXMgTk9UIGFjY2VwdCBhIGdsb2IgcGF0dGVybiBhcyBhIG1hdGNoIOKAlCByZXF1aXJlcyBleGFjdCBmaWxlbmFtZVwiLCAoKSA9PiB7XG4gICAgd3JpdGVGaWxlU3luYyhqb2luKHRtcERpciwgXCIuZ2l0aWdub3JlXCIpLCBcIiouanNvblxcblwiLCBcInV0Zi04XCIpO1xuICAgIGNvbnN0IHJlc3VsdCA9IHBhdGNoR2l0aWdub3JlKHRtcERpciwgXCIuZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb25cIik7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9CZShcInBhdGNoZWRcIik7XG4gIH0pO1xufSk7XG5cbi8vIOKUgOKUgCBydW5Jbml0IOKAlCBmaWxlIHdyaXRlcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuZGVzY3JpYmUoXCJydW5Jbml0IOKAlCBmaWxlIHdyaXRlc1wiLCAoKSA9PiB7XG4gIGxldCBwcm9qZWN0RGlyOiBzdHJpbmc7XG4gIGxldCBob21lRGlyOiBzdHJpbmc7XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgcHJvamVjdERpciA9IG1rZHRlbXBTeW5jKGpvaW4oXCIvdG1wXCIsIFwiZmItaW5pdC1wcm9qLVwiKSk7XG4gICAgaG9tZURpciA9IG1rZHRlbXBTeW5jKGpvaW4oXCIvdG1wXCIsIFwiZmItaW5pdC1ob21lLVwiKSk7XG4gICAgdmkubW9ja2VkKG9zLmhvbWVkaXIpLm1vY2tSZXR1cm5WYWx1ZShob21lRGlyKTtcbiAgICBtb2NrQW5zd2Vycy5sZW5ndGggPSAwO1xuICB9KTtcblxuICBhZnRlckVhY2goKCkgPT4ge1xuICAgIHZpLmNsZWFyQWxsTW9ja3MoKTtcbiAgICBybVN5bmMocHJvamVjdERpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIHJtU3luYyhob21lRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gIH0pO1xuXG4gIGl0KFwid3JpdGVzIGdsb2JhbCBjb25maWcgdG8gfi8uZnJhcHBlLWJ1aWxkZXIvY29uZmlnLmpzb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEFuc3dlcnM6IGxsbV9hcGlfa2V5LCBzaXRlX3VybCwgYXBpX2tleSwgYXBpX3NlY3JldFxuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJzay10ZXN0XCIsIFwiaHR0cDovL2VycC5sb2NhbGhvc3RcIiwgXCJrZXkxMjNcIiwgXCJzZWNyZXQ0NTZcIik7XG4gICAgYXdhaXQgcnVuSW5pdCh7IHByb2plY3RSb290OiBwcm9qZWN0RGlyIH0pO1xuXG4gICAgY29uc3QgY29uZmlnUGF0aCA9IGpvaW4oaG9tZURpciwgXCIuZnJhcHBlLWJ1aWxkZXJcIiwgXCJjb25maWcuanNvblwiKTtcbiAgICBleHBlY3QoZXhpc3RzU3luYyhjb25maWdQYXRoKSkudG9CZSh0cnVlKTtcbiAgICBjb25zdCBjZmcgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdQYXRoLCBcInV0Zi04XCIpKSBhcyB7IGxsbV9hcGlfa2V5OiBzdHJpbmcgfTtcbiAgICBleHBlY3QoY2ZnLmxsbV9hcGlfa2V5KS50b0JlKFwic2stdGVzdFwiKTtcbiAgfSk7XG5cbiAgaXQoXCJ3cml0ZXMgcHJvamVjdCBjb25maWcgdG8ge3Byb2plY3RSb290fS8uZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJzay10ZXN0XCIsIFwiaHR0cDovL2VycC5sb2NhbGhvc3RcIiwgXCJrZXkxMjNcIiwgXCJzZWNyZXQ0NTZcIik7XG4gICAgYXdhaXQgcnVuSW5pdCh7IHByb2plY3RSb290OiBwcm9qZWN0RGlyIH0pO1xuXG4gICAgY29uc3QgY29uZmlnUGF0aCA9IGpvaW4ocHJvamVjdERpciwgXCIuZnJhcHBlLWJ1aWxkZXItY29uZmlnLmpzb25cIik7XG4gICAgZXhwZWN0KGV4aXN0c1N5bmMoY29uZmlnUGF0aCkpLnRvQmUodHJ1ZSk7XG4gICAgY29uc3QgY2ZnID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgXCJ1dGYtOFwiKSkgYXMge1xuICAgICAgc2l0ZV91cmw6IHN0cmluZztcbiAgICAgIGFwaV9rZXk6IHN0cmluZztcbiAgICAgIGFwaV9zZWNyZXQ6IHN0cmluZztcbiAgICB9O1xuICAgIGV4cGVjdChjZmcuc2l0ZV91cmwpLnRvQmUoXCJodHRwOi8vZXJwLmxvY2FsaG9zdFwiKTtcbiAgICBleHBlY3QoY2ZnLmFwaV9rZXkpLnRvQmUoXCJrZXkxMjNcIik7XG4gICAgZXhwZWN0KGNmZy5hcGlfc2VjcmV0KS50b0JlKFwic2VjcmV0NDU2XCIpO1xuICB9KTtcblxuICBpdChcInBhdGNoZXMgLmdpdGlnbm9yZSBhdXRvbWF0aWNhbGx5XCIsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrQW5zd2Vycy5wdXNoKFwic2stdGVzdFwiLCBcImh0dHA6Ly9lcnAubG9jYWxob3N0XCIsIFwia2V5MTIzXCIsIFwic2VjcmV0NDU2XCIpO1xuICAgIGF3YWl0IHJ1bkluaXQoeyBwcm9qZWN0Um9vdDogcHJvamVjdERpciB9KTtcblxuICAgIGNvbnN0IGNvbnRlbnQgPSByZWFkRmlsZVN5bmMoam9pbihwcm9qZWN0RGlyLCBcIi5naXRpZ25vcmVcIiksIFwidXRmLThcIik7XG4gICAgZXhwZWN0KGNvbnRlbnQpLnRvQ29udGFpbihcIi5mcmFwcGUtYnVpbGRlci1jb25maWcuanNvblwiKTtcbiAgfSk7XG5cbiAgaXQoXCJjcmVhdGVzIH4vLmZyYXBwZS1idWlsZGVyLyBkaXJlY3RvcnkgaWYgaXQgZG9lcyBub3QgZXhpc3RcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJcIiwgXCJodHRwOi8vc2l0ZS5sb2NhbGhvc3RcIiwgXCJrXCIsIFwic1wiKTtcbiAgICBhd2FpdCBydW5Jbml0KHsgcHJvamVjdFJvb3Q6IHByb2plY3REaXIgfSk7XG5cbiAgICBleHBlY3QoZXhpc3RzU3luYyhqb2luKGhvbWVEaXIsIFwiLmZyYXBwZS1idWlsZGVyXCIpKSkudG9CZSh0cnVlKTtcbiAgfSk7XG59KTtcblxuLy8g4pSA4pSAIHJ1bkluaXQg4oCUIG92ZXJ3cml0ZSBndWFyZCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuZGVzY3JpYmUoXCJydW5Jbml0IOKAlCBvdmVyd3JpdGUgZ3VhcmRcIiwgKCkgPT4ge1xuICBsZXQgcHJvamVjdERpcjogc3RyaW5nO1xuICBsZXQgaG9tZURpcjogc3RyaW5nO1xuXG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIHByb2plY3REaXIgPSBta2R0ZW1wU3luYyhqb2luKFwiL3RtcFwiLCBcImZiLWluaXQtZ3VhcmQtcHJvai1cIikpO1xuICAgIGhvbWVEaXIgPSBta2R0ZW1wU3luYyhqb2luKFwiL3RtcFwiLCBcImZiLWluaXQtZ3VhcmQtaG9tZS1cIikpO1xuICAgIHZpLm1vY2tlZChvcy5ob21lZGlyKS5tb2NrUmV0dXJuVmFsdWUoaG9tZURpcik7XG4gICAgbW9ja0Fuc3dlcnMubGVuZ3RoID0gMDtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICB2aS5jbGVhckFsbE1vY2tzKCk7XG4gICAgcm1TeW5jKHByb2plY3REaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBybVN5bmMoaG9tZURpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICB9KTtcblxuICBpdChcImRvZXMgTk9UIG92ZXJ3cml0ZSBleGlzdGluZyBnbG9iYWwgY29uZmlnIHdoZW4gdXNlciBkZWNsaW5lc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgY29uZmlnRGlyID0gam9pbihob21lRGlyLCBcIi5mcmFwcGUtYnVpbGRlclwiKTtcbiAgICBta2RpclN5bmMoY29uZmlnRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBjb25zdCBnbG9iYWxQYXRoID0gam9pbihjb25maWdEaXIsIFwiY29uZmlnLmpzb25cIik7XG4gICAgd3JpdGVGaWxlU3luYyhnbG9iYWxQYXRoLCBKU09OLnN0cmluZ2lmeSh7IGxsbV9hcGlfa2V5OiBcIm9yaWdpbmFsLWtleVwiIH0pLCBcInV0Zi04XCIpO1xuXG4gICAgLy8gT3ZlcndyaXRlIGdsb2JhbD8g4oaSIFwiblwiIHwgT3ZlcndyaXRlIHByb2plY3Q/IOKGkiBcIm5cIlxuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJuXCIsIFwiblwiKTtcbiAgICBhd2FpdCBydW5Jbml0KHsgcHJvamVjdFJvb3Q6IHByb2plY3REaXIgfSk7XG5cbiAgICBjb25zdCBjZmcgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhnbG9iYWxQYXRoLCBcInV0Zi04XCIpKSBhcyB7IGxsbV9hcGlfa2V5OiBzdHJpbmcgfTtcbiAgICBleHBlY3QoY2ZnLmxsbV9hcGlfa2V5KS50b0JlKFwib3JpZ2luYWwta2V5XCIpO1xuICB9KTtcblxuICBpdChcIm92ZXJ3cml0ZXMgZXhpc3RpbmcgZ2xvYmFsIGNvbmZpZyB3aGVuIHVzZXIgY29uZmlybXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGNvbmZpZ0RpciA9IGpvaW4oaG9tZURpciwgXCIuZnJhcHBlLWJ1aWxkZXJcIik7XG4gICAgbWtkaXJTeW5jKGNvbmZpZ0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgY29uc3QgZ2xvYmFsUGF0aCA9IGpvaW4oY29uZmlnRGlyLCBcImNvbmZpZy5qc29uXCIpO1xuICAgIHdyaXRlRmlsZVN5bmMoZ2xvYmFsUGF0aCwgSlNPTi5zdHJpbmdpZnkoeyBsbG1fYXBpX2tleTogXCJvbGQta2V5XCIgfSksIFwidXRmLThcIik7XG5cbiAgICAvLyBPdmVyd3JpdGUgZ2xvYmFsPyDihpIgXCJ5XCIsIG5ldyBsbG1fa2V5LCBzaXRlX3VybCwgYXBpX2tleSwgYXBpX3NlY3JldFxuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJ5XCIsIFwibmV3LWtleVwiLCBcImh0dHA6Ly9zaXRlLmxvY2FsaG9zdFwiLCBcImtcIiwgXCJzXCIpO1xuICAgIGF3YWl0IHJ1bkluaXQoeyBwcm9qZWN0Um9vdDogcHJvamVjdERpciB9KTtcblxuICAgIGNvbnN0IGNmZyA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGdsb2JhbFBhdGgsIFwidXRmLThcIikpIGFzIHsgbGxtX2FwaV9rZXk6IHN0cmluZyB9O1xuICAgIGV4cGVjdChjZmcubGxtX2FwaV9rZXkpLnRvQmUoXCJuZXcta2V5XCIpO1xuICB9KTtcblxuICBpdChcImRvZXMgTk9UIG92ZXJ3cml0ZSBleGlzdGluZyBwcm9qZWN0IGNvbmZpZyB3aGVuIHVzZXIgZGVjbGluZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHByb2pDb25maWdQYXRoID0gam9pbihwcm9qZWN0RGlyLCBcIi5mcmFwcGUtYnVpbGRlci1jb25maWcuanNvblwiKTtcbiAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgcHJvakNvbmZpZ1BhdGgsXG4gICAgICBKU09OLnN0cmluZ2lmeSh7IHNpdGVfdXJsOiBcImh0dHA6Ly9vcmlnaW5hbC5sb2NhbGhvc3RcIiwgYXBpX2tleTogXCJvcmlnXCIsIGFwaV9zZWNyZXQ6IFwic1wiIH0pLFxuICAgICAgXCJ1dGYtOFwiXG4gICAgKTtcblxuICAgIC8vIGxsbV9hcGlfa2V5IHByb21wdCAobm8gZXhpc3RpbmcgZ2xvYmFsKSwgb3ZlcndyaXRlIHByb2plY3Q/IOKGkiBcIm5cIlxuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJzay1uZXdcIiwgXCJuXCIpO1xuICAgIGF3YWl0IHJ1bkluaXQoeyBwcm9qZWN0Um9vdDogcHJvamVjdERpciB9KTtcblxuICAgIGNvbnN0IGNmZyA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHByb2pDb25maWdQYXRoLCBcInV0Zi04XCIpKSBhcyB7IHNpdGVfdXJsOiBzdHJpbmcgfTtcbiAgICBleHBlY3QoY2ZnLnNpdGVfdXJsKS50b0JlKFwiaHR0cDovL29yaWdpbmFsLmxvY2FsaG9zdFwiKTtcbiAgfSk7XG59KTtcblxuLy8g4pSA4pSAIHJ1bkluaXQg4oCUIGNsZWFuIGV4aXQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbmRlc2NyaWJlKFwicnVuSW5pdCDigJQgY2xlYW4gZXhpdFwiLCAoKSA9PiB7XG4gIGxldCBwcm9qZWN0RGlyOiBzdHJpbmc7XG4gIGxldCBob21lRGlyOiBzdHJpbmc7XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgcHJvamVjdERpciA9IG1rZHRlbXBTeW5jKGpvaW4oXCIvdG1wXCIsIFwiZmItaW5pdC1leGl0LVwiKSk7XG4gICAgaG9tZURpciA9IG1rZHRlbXBTeW5jKGpvaW4oXCIvdG1wXCIsIFwiZmItaW5pdC1leGl0LWhvbWUtXCIpKTtcbiAgICB2aS5tb2NrZWQob3MuaG9tZWRpcikubW9ja1JldHVyblZhbHVlKGhvbWVEaXIpO1xuICAgIG1vY2tBbnN3ZXJzLmxlbmd0aCA9IDA7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgdmkuY2xlYXJBbGxNb2NrcygpO1xuICAgIHJtU3luYyhwcm9qZWN0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgcm1TeW5jKGhvbWVEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgfSk7XG5cbiAgaXQoXCJyZXNvbHZlcyB3aXRob3V0IHRocm93aW5nIHdoZW4gYWxsIHByb21wdHMgcmV0dXJuIGVtcHR5IHN0cmluZ3NcIiwgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tBbnN3ZXJzLnB1c2goXCJcIiwgXCJcIiwgXCJcIiwgXCJcIik7XG4gICAgYXdhaXQgZXhwZWN0KHJ1bkluaXQoeyBwcm9qZWN0Um9vdDogcHJvamVjdERpciB9KSkucmVzb2x2ZXMudG9CZVVuZGVmaW5lZCgpO1xuICB9KTtcbn0pO1xuIl0sImZpbGUiOiIvc3JjL2luaXQudGVzdC50cyJ9
206
+
207
+ //# vitestCache=W3siZmlsZSI6IjEiLCJpZCI6IjEiLCJ1cmwiOiIyIiwiaW1wb3J0ZWRVcmxzIjoiMyIsIm1hcHBpbmdzIjpmYWxzZX0sIi9ob21lL3Jpei9mcmFwcGUtYnVpbGRlci9zcmMvaW5pdC50ZXN0LnRzIiwiL3NyYy9pbml0LnRlc3QudHMiLFtdXQ==
@@ -11,7 +11,6 @@ export interface AppConfig {
11
11
  allowSubAgents: boolean;
12
12
  requirePermission: boolean;
13
13
  rules: SpawnRule[];
14
- frappeMcpUrl?: string; // URL of Frappe MCP server for frappe_query (e.g. "http://localhost:8000")
15
14
  defaultMode?: "full" | "quick"; // default feature mode: "quick" skips planning phases
16
15
  chainModel?: string; // model for chain subprocess agents (inherits parent model when unset)
17
16
  permissionMode?: PermissionMode; // agent autonomy level: auto | default | plan