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 +0 -0
- package/.frappe-builder/po-approval/implementation-artifacts/sprint-status.yaml +2 -2
- package/VrWyV9740LA8sENuDokCo/ssr/196abb03d76072784b62b46fb8bc3145b285d048 +318 -0
- package/VrWyV9740LA8sENuDokCo/ssr/38bf1c2ec078b4df1b452507602034ccf39ce1b1 +207 -0
- package/config/defaults.ts +0 -1
- package/config/loader.ts +18 -84
- package/dist/cli.mjs +7 -6
- package/dist/{init-BUkSYk2l.mjs → init-CkLSZ_3g.mjs} +57 -123
- package/extensions/frappe-state.ts +0 -13
- package/extensions/frappe-tools.ts +25 -3
- package/extensions/frappe-workflow.ts +1 -1
- package/package.json +1 -1
- package/state/db.ts +14 -2
- package/state/schema.ts +6 -0
- package/tools/frappe-context7.ts +28 -32
- package/tools/frappe-query-tools.ts +36 -20
- package/tools/project-tools.ts +12 -11
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:
|
|
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:
|
|
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==
|
package/config/defaults.ts
CHANGED
|
@@ -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
|