@lumenflow/cli 3.13.2 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-2D2VOCA4.js +37 -0
- package/dist/chunk-2D5KFYGX.js +284 -0
- package/dist/chunk-2GXVIN57.js +14072 -0
- package/dist/chunk-2MQ7HZWZ.js +26 -0
- package/dist/chunk-2UFQ3A3C.js +643 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-4N74J3UT.js +15 -0
- package/dist/chunk-5GTOXFYR.js +392 -0
- package/dist/chunk-5VY6MQMC.js +240 -0
- package/dist/chunk-67XVPMRY.js +1297 -0
- package/dist/chunk-6HO4GWJE.js +164 -0
- package/dist/chunk-6W5XHWYV.js +1890 -0
- package/dist/chunk-6X4EMYJQ.js +64 -0
- package/dist/chunk-6XYXI2NQ.js +772 -0
- package/dist/chunk-7ANSOV6Q.js +285 -0
- package/dist/chunk-A624LFLB.js +1380 -0
- package/dist/chunk-ADN5NHG4.js +126 -0
- package/dist/chunk-B7YJYJKG.js +33 -0
- package/dist/chunk-CCLHCPKG.js +210 -0
- package/dist/chunk-CK36VROC.js +1584 -0
- package/dist/chunk-D3UOFRSB.js +81 -0
- package/dist/chunk-DFR4DJBM.js +230 -0
- package/dist/chunk-DSYBDHYH.js +79 -0
- package/dist/chunk-DWMLTXKQ.js +1176 -0
- package/dist/chunk-E3REJTAJ.js +28 -0
- package/dist/chunk-EA3IVO64.js +633 -0
- package/dist/chunk-EK2AKZKD.js +55 -0
- package/dist/chunk-ELD7JTTT.js +343 -0
- package/dist/chunk-EX6TT2XI.js +195 -0
- package/dist/chunk-EXINSFZE.js +82 -0
- package/dist/chunk-EZ6ZBYBM.js +510 -0
- package/dist/chunk-FBKAPTJ2.js +16 -0
- package/dist/chunk-FVLV5RYH.js +1118 -0
- package/dist/chunk-GDNSBQVK.js +2485 -0
- package/dist/chunk-GPQHMBNN.js +278 -0
- package/dist/chunk-GTFJB67L.js +68 -0
- package/dist/chunk-HANJXVKW.js +1127 -0
- package/dist/chunk-HEVS5YLD.js +269 -0
- package/dist/chunk-HMEVZKPQ.js +9 -0
- package/dist/chunk-HRGSYNLM.js +3511 -0
- package/dist/chunk-ISZR5N4K.js +60 -0
- package/dist/chunk-J6SUPR2C.js +226 -0
- package/dist/chunk-JERYVEIZ.js +244 -0
- package/dist/chunk-JHHWGL2N.js +87 -0
- package/dist/chunk-JONWQUB5.js +775 -0
- package/dist/chunk-K2DIWWDM.js +1766 -0
- package/dist/chunk-KY4PGL5V.js +969 -0
- package/dist/chunk-L737LQ4C.js +1285 -0
- package/dist/chunk-LFTWYIB2.js +497 -0
- package/dist/chunk-LV47RFNJ.js +41 -0
- package/dist/chunk-MKSAITI7.js +15 -0
- package/dist/chunk-MZ7RKIX4.js +212 -0
- package/dist/chunk-NAP6CFSO.js +84 -0
- package/dist/chunk-ND6MY37M.js +16 -0
- package/dist/chunk-NMG736UR.js +683 -0
- package/dist/chunk-NRAXROED.js +32 -0
- package/dist/chunk-NRIZR3A7.js +690 -0
- package/dist/chunk-NX43BG3M.js +233 -0
- package/dist/chunk-O645XLSI.js +297 -0
- package/dist/chunk-OMJD6A3S.js +235 -0
- package/dist/chunk-QB6SJD4T.js +430 -0
- package/dist/chunk-QFSTL4J3.js +276 -0
- package/dist/chunk-QLGDFMFX.js +212 -0
- package/dist/chunk-RIAAGL2E.js +13 -0
- package/dist/chunk-RWO5XMZ6.js +86 -0
- package/dist/chunk-RXRKBBSM.js +149 -0
- package/dist/chunk-RZOZMML6.js +363 -0
- package/dist/chunk-U7I7FS7T.js +113 -0
- package/dist/chunk-UI42RODY.js +717 -0
- package/dist/chunk-UTVMVSCO.js +519 -0
- package/dist/chunk-V6OJGLBA.js +1746 -0
- package/dist/chunk-W2JHVH7D.js +152 -0
- package/dist/chunk-WD3Y7VQN.js +280 -0
- package/dist/chunk-WOCTQ5MS.js +303 -0
- package/dist/chunk-WZR3ZUNN.js +696 -0
- package/dist/chunk-XGI665H7.js +150 -0
- package/dist/chunk-XKY65P2T.js +304 -0
- package/dist/chunk-Y4CQZY65.js +57 -0
- package/dist/chunk-YFEXKLVE.js +194 -0
- package/dist/chunk-YHO3HS5X.js +287 -0
- package/dist/chunk-YLS7AZSX.js +738 -0
- package/dist/chunk-ZE473AO6.js +49 -0
- package/dist/chunk-ZF747T3O.js +644 -0
- package/dist/chunk-ZHCZHZH3.js +43 -0
- package/dist/chunk-ZZNZX2XY.js +87 -0
- package/dist/constants-7QAP3VQ4.js +23 -0
- package/dist/dist-IY3UUMWK.js +33 -0
- package/dist/docs-sync.js +60 -25
- package/dist/docs-sync.js.map +1 -1
- package/dist/gates-runners.js +43 -2
- package/dist/gates-runners.js.map +1 -1
- package/dist/init-templates.js +26 -219
- package/dist/init-templates.js.map +1 -1
- package/dist/invariants-runner-W5RGHCSU.js +27 -0
- package/dist/lane-lock-6J36HD5O.js +35 -0
- package/dist/lumenflow-upgrade.js +60 -0
- package/dist/lumenflow-upgrade.js.map +1 -1
- package/dist/mem-checkpoint-core-EANG2GVN.js +14 -0
- package/dist/mem-signal-core-2LZ2WYHW.js +19 -0
- package/dist/memory-store-OLB5FO7K.js +18 -0
- package/dist/plan-edit.js +19 -24
- package/dist/plan-edit.js.map +1 -1
- package/dist/plan-promote.js +15 -23
- package/dist/plan-promote.js.map +1 -1
- package/dist/plan-resolve.js +111 -0
- package/dist/plan-resolve.js.map +1 -0
- package/dist/public-manifest.js +2 -2
- package/dist/public-manifest.js.map +1 -1
- package/dist/service-6BYCOCO5.js +13 -0
- package/dist/spawn-policy-resolver-NTSZYQ6R.js +17 -0
- package/dist/spawn-task-builder-R4E2BHSW.js +22 -0
- package/dist/sync-templates.js +12 -0
- package/dist/sync-templates.js.map +1 -1
- package/dist/wu-brief.js +1 -1
- package/dist/wu-brief.js.map +1 -1
- package/dist/wu-claim-validation.js +9 -1
- package/dist/wu-claim-validation.js.map +1 -1
- package/dist/wu-done-policies.js +78 -33
- package/dist/wu-done-policies.js.map +1 -1
- package/dist/wu-done-pr-WLFFFEPJ.js +25 -0
- package/dist/wu-done-validation-3J5E36FE.js +30 -0
- package/dist/wu-done.js +42 -1
- package/dist/wu-done.js.map +1 -1
- package/dist/wu-duplicate-id-detector-5S7JHELK.js +232 -0
- package/dist/wu-edit-operations.js +7 -6
- package/dist/wu-edit-operations.js.map +1 -1
- package/dist/wu-edit.js +23 -3
- package/dist/wu-edit.js.map +1 -1
- package/dist/wu-spawn-prompt-builders.js +38 -1
- package/dist/wu-spawn-prompt-builders.js.map +1 -1
- package/dist/wu-spawn-strategy-resolver.js +30 -11
- package/dist/wu-spawn-strategy-resolver.js.map +1 -1
- package/package.json +8 -8
- package/packs/sidekick/.turbo/turbo-build.log +1 -1
- package/packs/sidekick/.turbo/turbo-typecheck.log +4 -0
- package/packs/sidekick/package.json +1 -1
- package/packs/software-delivery/.turbo/turbo-build.log +1 -1
- package/packs/software-delivery/.turbo/turbo-typecheck.log +4 -0
- package/packs/software-delivery/package.json +1 -1
- package/templates/core/AGENTS.md.template +19 -0
- package/templates/core/LUMENFLOW.md.template +13 -2
- package/templates/core/UPGRADING.md.template +6 -6
- package/templates/core/ai/onboarding/agent-invocation-guide.md.template +6 -5
- package/templates/core/ai/onboarding/first-15-mins.md.template +1 -1
- package/templates/core/ai/onboarding/first-wu-mistakes.md.template +10 -0
- package/templates/core/ai/onboarding/initiative-orchestration.md.template +5 -7
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +11 -9
- package/templates/core/ai/onboarding/release-process.md.template +1 -1
- package/templates/core/ai/onboarding/starting-prompt.md.template +5 -6
- package/templates/core/ai/onboarding/wu-sizing-guide.md.template +11 -2
- package/templates/vendors/claude/.claude/skills/initiative-management/SKILL.md.template +2 -2
- package/templates/vendors/claude/.claude/skills/multi-agent-coordination/SKILL.md.template +2 -2
- package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +4 -4
- package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +9 -1
- package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +9 -1
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveCliTemplatesDir
|
|
3
|
+
} from "./chunk-D3UOFRSB.js";
|
|
4
|
+
import {
|
|
5
|
+
ErrorCodes,
|
|
6
|
+
createError
|
|
7
|
+
} from "./chunk-RXRKBBSM.js";
|
|
8
|
+
|
|
9
|
+
// src/init-scaffolding.ts
|
|
10
|
+
import * as fs from "fs";
|
|
11
|
+
import * as path from "path";
|
|
12
|
+
|
|
13
|
+
// src/merge-block.ts
|
|
14
|
+
var MARKERS = {
|
|
15
|
+
START: "<!-- LUMENFLOW:START -->",
|
|
16
|
+
END: "<!-- LUMENFLOW:END -->"
|
|
17
|
+
};
|
|
18
|
+
function detectLineEnding(content) {
|
|
19
|
+
if (!content) {
|
|
20
|
+
return "\n";
|
|
21
|
+
}
|
|
22
|
+
const crlfCount = (content.match(/\r\n/g) || []).length;
|
|
23
|
+
const lfCount = (content.match(/(?<!\r)\n/g) || []).length;
|
|
24
|
+
if (crlfCount === 0 && lfCount === 0) {
|
|
25
|
+
return "\n";
|
|
26
|
+
}
|
|
27
|
+
return crlfCount >= lfCount ? "\r\n" : "\n";
|
|
28
|
+
}
|
|
29
|
+
function normalizeLineEndings(content, lineEnding) {
|
|
30
|
+
const normalized = content.replace(/\r\n/g, "\n");
|
|
31
|
+
if (lineEnding === "\r\n") {
|
|
32
|
+
return normalized.replace(/\n/g, "\r\n");
|
|
33
|
+
}
|
|
34
|
+
return normalized;
|
|
35
|
+
}
|
|
36
|
+
function extractMergeBlock(content) {
|
|
37
|
+
const startIndexes = [];
|
|
38
|
+
const endIndexes = [];
|
|
39
|
+
let pos = 0;
|
|
40
|
+
while ((pos = content.indexOf(MARKERS.START, pos)) !== -1) {
|
|
41
|
+
startIndexes.push(pos);
|
|
42
|
+
pos += MARKERS.START.length;
|
|
43
|
+
}
|
|
44
|
+
pos = 0;
|
|
45
|
+
while ((pos = content.indexOf(MARKERS.END, pos)) !== -1) {
|
|
46
|
+
endIndexes.push(pos);
|
|
47
|
+
pos += MARKERS.END.length;
|
|
48
|
+
}
|
|
49
|
+
if (startIndexes.length > 1) {
|
|
50
|
+
return { found: false, malformed: true, malformedReason: "multiple-start" };
|
|
51
|
+
}
|
|
52
|
+
if (endIndexes.length > 1) {
|
|
53
|
+
return { found: false, malformed: true, malformedReason: "multiple-end" };
|
|
54
|
+
}
|
|
55
|
+
const hasStart = startIndexes.length === 1;
|
|
56
|
+
const hasEnd = endIndexes.length === 1;
|
|
57
|
+
if (hasStart && !hasEnd) {
|
|
58
|
+
return { found: false, malformed: true, malformedReason: "missing-end" };
|
|
59
|
+
}
|
|
60
|
+
if (!hasStart && hasEnd) {
|
|
61
|
+
return { found: false, malformed: true, malformedReason: "missing-start" };
|
|
62
|
+
}
|
|
63
|
+
if (!hasStart && !hasEnd) {
|
|
64
|
+
return { found: false };
|
|
65
|
+
}
|
|
66
|
+
const startIndex = startIndexes[0];
|
|
67
|
+
const endMarkerIndex = endIndexes[0];
|
|
68
|
+
const endIndex = endMarkerIndex + MARKERS.END.length;
|
|
69
|
+
if (endMarkerIndex <= startIndex) {
|
|
70
|
+
return { found: false, malformed: true, malformedReason: "missing-end" };
|
|
71
|
+
}
|
|
72
|
+
const afterStart = startIndex + MARKERS.START.length;
|
|
73
|
+
const beforeEnd = endMarkerIndex;
|
|
74
|
+
let blockContent = content.slice(afterStart, beforeEnd);
|
|
75
|
+
blockContent = trimNewlines(blockContent);
|
|
76
|
+
return {
|
|
77
|
+
found: true,
|
|
78
|
+
content: blockContent,
|
|
79
|
+
startIndex,
|
|
80
|
+
endIndex
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function insertMergeBlock(originalContent, blockContent) {
|
|
84
|
+
const lineEnding = detectLineEnding(originalContent);
|
|
85
|
+
const normalizedBlock = normalizeLineEndings(blockContent, lineEnding);
|
|
86
|
+
let content = originalContent;
|
|
87
|
+
if (!content.endsWith(lineEnding)) {
|
|
88
|
+
content += lineEnding;
|
|
89
|
+
}
|
|
90
|
+
if (!content.endsWith(lineEnding + lineEnding) && content.trim().length > 0) {
|
|
91
|
+
content += lineEnding;
|
|
92
|
+
}
|
|
93
|
+
const block = [MARKERS.START, normalizedBlock, MARKERS.END, ""].join(lineEnding);
|
|
94
|
+
return content + block;
|
|
95
|
+
}
|
|
96
|
+
function updateMergeBlock(originalContent, newBlockContent) {
|
|
97
|
+
const lineEnding = detectLineEnding(originalContent);
|
|
98
|
+
const extraction = extractMergeBlock(originalContent);
|
|
99
|
+
if (extraction.malformed) {
|
|
100
|
+
const warning = `LumenFlow markers are malformed (${extraction.malformedReason}). Appending fresh block.`;
|
|
101
|
+
const result2 = insertMergeBlock(originalContent, newBlockContent);
|
|
102
|
+
return {
|
|
103
|
+
content: result2,
|
|
104
|
+
updated: true,
|
|
105
|
+
wasInserted: true,
|
|
106
|
+
warning
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (!extraction.found) {
|
|
110
|
+
return {
|
|
111
|
+
content: insertMergeBlock(originalContent, newBlockContent),
|
|
112
|
+
updated: true,
|
|
113
|
+
wasInserted: true
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const normalizedNew = normalizeLineEndings(newBlockContent, lineEnding).trim();
|
|
117
|
+
const normalizedExisting = (extraction.content || "").trim();
|
|
118
|
+
if (normalizedNew === normalizedExisting) {
|
|
119
|
+
return {
|
|
120
|
+
content: originalContent,
|
|
121
|
+
updated: false,
|
|
122
|
+
unchanged: true
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const startIdx = extraction.startIndex ?? 0;
|
|
126
|
+
const endIdx = extraction.endIndex ?? originalContent.length;
|
|
127
|
+
const before = originalContent.slice(0, startIdx);
|
|
128
|
+
const after = originalContent.slice(endIdx);
|
|
129
|
+
const newBlock = [
|
|
130
|
+
MARKERS.START,
|
|
131
|
+
normalizeLineEndings(newBlockContent, lineEnding),
|
|
132
|
+
MARKERS.END
|
|
133
|
+
].join(lineEnding);
|
|
134
|
+
let result = before;
|
|
135
|
+
if (!result.endsWith(lineEnding) && result.length > 0) {
|
|
136
|
+
result += lineEnding;
|
|
137
|
+
}
|
|
138
|
+
result += newBlock;
|
|
139
|
+
if (after.trim().length > 0) {
|
|
140
|
+
if (!result.endsWith(lineEnding)) {
|
|
141
|
+
result += lineEnding;
|
|
142
|
+
}
|
|
143
|
+
result += after;
|
|
144
|
+
} else if (after.includes(lineEnding)) {
|
|
145
|
+
if (!result.endsWith(lineEnding)) {
|
|
146
|
+
result += lineEnding;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
content: result,
|
|
151
|
+
updated: true
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function trimNewlines(str) {
|
|
155
|
+
let start = 0;
|
|
156
|
+
let end = str.length;
|
|
157
|
+
while (start < end && (str[start] === "\r" || str[start] === "\n")) {
|
|
158
|
+
start++;
|
|
159
|
+
}
|
|
160
|
+
while (end > start && (str[end - 1] === "\r" || str[end - 1] === "\n")) {
|
|
161
|
+
end--;
|
|
162
|
+
}
|
|
163
|
+
return str.slice(start, end);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/init-scaffolding.ts
|
|
167
|
+
function processTemplate(content, tokens) {
|
|
168
|
+
let output = content;
|
|
169
|
+
for (const [key, value] of Object.entries(tokens)) {
|
|
170
|
+
output = output.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
|
|
171
|
+
}
|
|
172
|
+
return output;
|
|
173
|
+
}
|
|
174
|
+
function getRelativePath(targetDir, filePath) {
|
|
175
|
+
return path.relative(targetDir, filePath).split(path.sep).join("/");
|
|
176
|
+
}
|
|
177
|
+
function getTemplatesDir() {
|
|
178
|
+
return resolveCliTemplatesDir();
|
|
179
|
+
}
|
|
180
|
+
function loadTemplate(templatePath) {
|
|
181
|
+
const templatesDir = getTemplatesDir();
|
|
182
|
+
const fullPath = path.join(templatesDir, templatePath);
|
|
183
|
+
if (!fs.existsSync(fullPath)) {
|
|
184
|
+
throw createError(ErrorCodes.FILE_NOT_FOUND, `Template not found: ${templatePath}`);
|
|
185
|
+
}
|
|
186
|
+
return fs.readFileSync(fullPath, "utf-8");
|
|
187
|
+
}
|
|
188
|
+
function resolveBooleanToFileMode(mode) {
|
|
189
|
+
if (typeof mode === "boolean") {
|
|
190
|
+
return mode ? "force" : "skip";
|
|
191
|
+
}
|
|
192
|
+
return mode;
|
|
193
|
+
}
|
|
194
|
+
function handleMergeMode(filePath, content, result, relativePath) {
|
|
195
|
+
const existingContent = fs.readFileSync(filePath, "utf-8");
|
|
196
|
+
const mergeResult = updateMergeBlock(existingContent, content);
|
|
197
|
+
if (mergeResult.unchanged) {
|
|
198
|
+
result.skipped.push(relativePath);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (mergeResult.warning) {
|
|
202
|
+
result.warnings?.push(`${relativePath}: ${mergeResult.warning}`);
|
|
203
|
+
}
|
|
204
|
+
fs.writeFileSync(filePath, mergeResult.content);
|
|
205
|
+
result.merged?.push(relativePath);
|
|
206
|
+
}
|
|
207
|
+
function writeNewFile(filePath, content, result, relativePath) {
|
|
208
|
+
const parentDir = path.dirname(filePath);
|
|
209
|
+
if (!fs.existsSync(parentDir)) {
|
|
210
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
211
|
+
}
|
|
212
|
+
fs.writeFileSync(filePath, content);
|
|
213
|
+
result.created.push(relativePath);
|
|
214
|
+
}
|
|
215
|
+
async function createDirectory(dirPath, result, targetDir) {
|
|
216
|
+
if (!fs.existsSync(dirPath)) {
|
|
217
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
218
|
+
result.created.push(getRelativePath(targetDir, dirPath));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function createFile(filePath, content, mode, result, targetDir) {
|
|
222
|
+
const relativePath = getRelativePath(targetDir, filePath);
|
|
223
|
+
const resolvedMode = resolveBooleanToFileMode(mode);
|
|
224
|
+
result.merged = result.merged ?? [];
|
|
225
|
+
result.warnings = result.warnings ?? [];
|
|
226
|
+
result.overwritten = result.overwritten ?? [];
|
|
227
|
+
const fileExists = fs.existsSync(filePath);
|
|
228
|
+
if (fileExists && resolvedMode === "skip") {
|
|
229
|
+
result.skipped.push(relativePath);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (fileExists && resolvedMode === "merge") {
|
|
233
|
+
handleMergeMode(filePath, content, result, relativePath);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (fileExists && resolvedMode === "force") {
|
|
237
|
+
result.overwritten.push(relativePath);
|
|
238
|
+
}
|
|
239
|
+
writeNewFile(filePath, content, result, relativePath);
|
|
240
|
+
}
|
|
241
|
+
async function createExecutableScript(filePath, content, mode, result, targetDir) {
|
|
242
|
+
const relativePath = getRelativePath(targetDir, filePath);
|
|
243
|
+
const resolvedMode = resolveBooleanToFileMode(mode);
|
|
244
|
+
result.merged = result.merged ?? [];
|
|
245
|
+
result.warnings = result.warnings ?? [];
|
|
246
|
+
result.overwritten = result.overwritten ?? [];
|
|
247
|
+
const fileExists = fs.existsSync(filePath);
|
|
248
|
+
if (fileExists && resolvedMode === "skip") {
|
|
249
|
+
result.skipped.push(relativePath);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (fileExists && (resolvedMode === "force" || resolvedMode === "merge")) {
|
|
253
|
+
result.overwritten.push(relativePath);
|
|
254
|
+
}
|
|
255
|
+
const parentDir = path.dirname(filePath);
|
|
256
|
+
if (!fs.existsSync(parentDir)) {
|
|
257
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
258
|
+
}
|
|
259
|
+
fs.writeFileSync(filePath, content, { mode: 493 });
|
|
260
|
+
result.created.push(relativePath);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export {
|
|
264
|
+
processTemplate,
|
|
265
|
+
loadTemplate,
|
|
266
|
+
createDirectory,
|
|
267
|
+
createFile,
|
|
268
|
+
createExecutableScript
|
|
269
|
+
};
|