cortex-editor 0.2.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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/browser/index.js +16919 -0
  4. package/dist/chunk-MTPBP2I7.js +357 -0
  5. package/dist/cli/chunk-DDAWRJKB.js +8 -0
  6. package/dist/cli/demo-AVO56BY4.js +425 -0
  7. package/dist/cli/index.js +82 -0
  8. package/dist/cli/init-4THVM67R.js +904 -0
  9. package/dist/cli/mcp-4662LVDL.js +774 -0
  10. package/dist/edit-pipeline-CSKRjRlj.d.cts +1530 -0
  11. package/dist/edit-pipeline-CSKRjRlj.d.ts +1530 -0
  12. package/dist/index.cjs +6144 -0
  13. package/dist/index.d.cts +185 -0
  14. package/dist/index.d.ts +185 -0
  15. package/dist/index.js +5678 -0
  16. package/dist/next/next-source-loader.cjs +1421 -0
  17. package/dist/next/next-source-loader.d.cts +1 -0
  18. package/dist/next/next-source-loader.d.ts +1 -0
  19. package/dist/next/next.cjs +83 -0
  20. package/dist/next/next.d.cts +31 -0
  21. package/dist/next/next.d.ts +31 -0
  22. package/dist/next/next.js +47 -0
  23. package/dist/tailwind-v4-parser-K4ORCER6.js +14 -0
  24. package/dist/text-components-W2PN72Z5.js +38 -0
  25. package/dist/vite/tailwind-v4-parser-GFFOYWKN.js +355 -0
  26. package/dist/vite/text-components-W2PN72Z5.js +38 -0
  27. package/dist/vite/vite.cjs +8726 -0
  28. package/dist/vite/vite.d.cts +267 -0
  29. package/dist/vite/vite.d.ts +267 -0
  30. package/dist/vite/vite.js +8261 -0
  31. package/dist/webpack/source-loader.cjs +1421 -0
  32. package/dist/webpack/source-loader.d.cts +25 -0
  33. package/dist/webpack/source-loader.d.ts +25 -0
  34. package/dist/webpack/tailwind-v4-parser-GFFOYWKN.js +355 -0
  35. package/dist/webpack/text-components-W2PN72Z5.js +38 -0
  36. package/dist/webpack/webpack.cjs +7250 -0
  37. package/dist/webpack/webpack.d.cts +103 -0
  38. package/dist/webpack/webpack.d.ts +103 -0
  39. package/dist/webpack/webpack.js +6794 -0
  40. package/package.json +146 -0
@@ -0,0 +1,904 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ version
4
+ } from "./chunk-DDAWRJKB.js";
5
+
6
+ // src/cli/init.ts
7
+ import { spawn } from "child_process";
8
+ import fs4 from "fs";
9
+ import path3 from "path";
10
+ import { stdin, stdout } from "process";
11
+ import { createInterface } from "readline/promises";
12
+ import {
13
+ Project,
14
+ SyntaxKind,
15
+ ts
16
+ } from "ts-morph";
17
+
18
+ // src/cli/detect.ts
19
+ import fs from "fs";
20
+ import path from "path";
21
+ var VITE_CONFIG_FILES = [
22
+ "vite.config.ts",
23
+ "vite.config.js",
24
+ "vite.config.mts",
25
+ "vite.config.mjs",
26
+ "vite.config.cts",
27
+ "vite.config.cjs"
28
+ ];
29
+ var NEXT_CONFIG_FILES = [
30
+ "next.config.ts",
31
+ "next.config.mts",
32
+ "next.config.mjs",
33
+ "next.config.js",
34
+ "next.config.cjs",
35
+ "next.config.cts"
36
+ ];
37
+ var WEBPACK_CONFIG_FILES = [
38
+ "webpack.config.ts",
39
+ "webpack.config.js",
40
+ "webpack.config.mts",
41
+ "webpack.config.mjs",
42
+ "webpack.config.cts",
43
+ "webpack.config.cjs"
44
+ ];
45
+ function installedDependencies(pkg) {
46
+ return {
47
+ ...pkg.dependencies,
48
+ ...pkg.devDependencies,
49
+ ...pkg.optionalDependencies
50
+ };
51
+ }
52
+ function hasDependency(pkg, name) {
53
+ return Boolean(installedDependencies(pkg)[name]);
54
+ }
55
+ function detectPackageManager(cwd, pkg = {}) {
56
+ if (fs.existsSync(path.join(cwd, "package-lock.json"))) return "npm";
57
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
58
+ if (fs.existsSync(path.join(cwd, "yarn.lock"))) return "yarn";
59
+ if (fs.existsSync(path.join(cwd, "bun.lockb")) || fs.existsSync(path.join(cwd, "bun.lock"))) {
60
+ return "bun";
61
+ }
62
+ if (pkg.packageManager?.startsWith("pnpm@")) return "pnpm";
63
+ if (pkg.packageManager?.startsWith("yarn@")) return "yarn";
64
+ if (pkg.packageManager?.startsWith("bun@")) return "bun";
65
+ if (pkg.packageManager?.startsWith("npm@")) return "npm";
66
+ return "npm";
67
+ }
68
+
69
+ // src/adapters/telemetry.ts
70
+ import fs3 from "fs";
71
+ import path2 from "path";
72
+
73
+ // src/adapters/atomic-write.ts
74
+ import { promises as fs2 } from "fs";
75
+ import { randomBytes } from "crypto";
76
+ import { dirname, basename, join } from "path";
77
+ var ExternalRevertError = class extends Error {
78
+ filePath;
79
+ constructor(filePath) {
80
+ super("Write was reverted by an external process (e.g. editor auto-save)");
81
+ this.name = "ExternalRevertError";
82
+ this.filePath = filePath;
83
+ }
84
+ };
85
+ async function atomicWrite(filePath, content) {
86
+ const tmpPath = tempSibling(filePath);
87
+ try {
88
+ await fs2.writeFile(tmpPath, content, "utf-8");
89
+ await fs2.rename(tmpPath, filePath);
90
+ } catch (err) {
91
+ try {
92
+ await fs2.unlink(tmpPath);
93
+ } catch {
94
+ }
95
+ throw err;
96
+ }
97
+ const afterFirst = await fs2.readFile(filePath, "utf-8");
98
+ if (afterFirst === content) return;
99
+ const retryTmp = tempSibling(filePath);
100
+ try {
101
+ await fs2.writeFile(retryTmp, content, "utf-8");
102
+ await fs2.rename(retryTmp, filePath);
103
+ } catch (err) {
104
+ try {
105
+ await fs2.unlink(retryTmp);
106
+ } catch {
107
+ }
108
+ throw err;
109
+ }
110
+ const afterRetry = await fs2.readFile(filePath, "utf-8");
111
+ if (afterRetry === content) return;
112
+ throw new ExternalRevertError(filePath);
113
+ }
114
+ function tempSibling(filePath) {
115
+ const nonce = randomBytes(6).toString("hex");
116
+ return join(dirname(filePath), `.${basename(filePath)}.cortex-${process.pid}-${nonce}.tmp`);
117
+ }
118
+
119
+ // src/adapters/telemetry.ts
120
+ var NOOP = {
121
+ async recordInit() {
122
+ },
123
+ async recordActivation() {
124
+ },
125
+ async recordFirstEdit() {
126
+ }
127
+ };
128
+ function createTelemetry(options) {
129
+ if (!options.enabled) return NOOP;
130
+ const {
131
+ endpoint,
132
+ cortexRoot,
133
+ version: version2,
134
+ now,
135
+ fetchImpl = fetch,
136
+ readFileSync: readFileSyncImpl = (p, enc) => fs3.readFileSync(p, enc),
137
+ writeFile: writeFileImpl = atomicWrite,
138
+ mkdirSync: mkdirSyncImpl = (d, opts) => {
139
+ fs3.mkdirSync(d, opts);
140
+ }
141
+ } = options;
142
+ const usagePath = path2.join(cortexRoot, ".cortex", "usage.json");
143
+ const cortexDir = path2.join(cortexRoot, ".cortex");
144
+ function today() {
145
+ return (now?.() ?? /* @__PURE__ */ new Date()).toISOString().slice(0, 10);
146
+ }
147
+ function readState() {
148
+ try {
149
+ const raw = readFileSyncImpl(usagePath, "utf-8");
150
+ return JSON.parse(raw);
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
155
+ async function persistState(state) {
156
+ try {
157
+ mkdirSyncImpl(cortexDir, { recursive: true, mode: 448 });
158
+ await writeFileImpl(usagePath, JSON.stringify(state, null, 2));
159
+ } catch {
160
+ }
161
+ }
162
+ function emit(event) {
163
+ if (endpoint) {
164
+ const payload = {
165
+ event,
166
+ ts: (now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
167
+ cortexVersion: version2
168
+ };
169
+ void fetchImpl(endpoint, {
170
+ method: "POST",
171
+ headers: { "content-type": "application/json" },
172
+ body: JSON.stringify(payload),
173
+ signal: AbortSignal.timeout(3e3)
174
+ }).catch(() => {
175
+ });
176
+ }
177
+ }
178
+ let tail = Promise.resolve();
179
+ function serialize(task) {
180
+ const run = tail.then(task, task);
181
+ tail = run.catch(() => {
182
+ });
183
+ return run;
184
+ }
185
+ return {
186
+ recordInit() {
187
+ return serialize(async () => {
188
+ emit("cortex_init");
189
+ const state = readState() ?? { version: 1 };
190
+ await persistState(state);
191
+ });
192
+ },
193
+ recordActivation() {
194
+ return serialize(async () => {
195
+ const todayStr = today();
196
+ const state = readState() ?? { version: 1 };
197
+ const isReturnSession = state.lastActivationDate !== void 0 && state.lastActivationDate !== todayStr;
198
+ emit("editor_activated");
199
+ if (isReturnSession) emit("return_session");
200
+ const updated = {
201
+ ...state,
202
+ firstActivationDate: state.firstActivationDate ?? todayStr,
203
+ lastActivationDate: todayStr
204
+ };
205
+ await persistState(updated);
206
+ });
207
+ },
208
+ recordFirstEdit() {
209
+ return serialize(async () => {
210
+ const state = readState() ?? { version: 1 };
211
+ if (state.firstEditRecorded) return;
212
+ emit("first_edit");
213
+ const updated = { ...state, firstEditRecorded: true };
214
+ await persistState(updated);
215
+ });
216
+ }
217
+ };
218
+ }
219
+
220
+ // src/adapters/telemetry-config.ts
221
+ function resolveTelemetryEnabled(options) {
222
+ const { env = process.env } = options;
223
+ return (env.CORTEX_TELEMETRY ?? "").trim().toLowerCase() === "true";
224
+ }
225
+ function resolveTelemetryEndpoint(options) {
226
+ const { env = process.env } = options;
227
+ const raw = env.CORTEX_TELEMETRY_ENDPOINT;
228
+ if (!raw) return void 0;
229
+ try {
230
+ const parsed = new URL(raw);
231
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
232
+ return void 0;
233
+ }
234
+ return raw;
235
+ } catch {
236
+ return void 0;
237
+ }
238
+ }
239
+
240
+ // src/cli/init.ts
241
+ var VITE_SETUP_PACKAGES = ["vite", "@vitejs/plugin-react"];
242
+ function resolveObjectLiteralExpression(sourceFile, expr, options = {}, seen = /* @__PURE__ */ new Set()) {
243
+ if (expr.getKind() === SyntaxKind.ObjectLiteralExpression) {
244
+ return expr.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
245
+ }
246
+ if (options.allowCallObjectArg && expr.getKind() === SyntaxKind.CallExpression) {
247
+ const callExpr = expr.asKindOrThrow(SyntaxKind.CallExpression);
248
+ const firstArg = callExpr.getArguments()[0];
249
+ if (firstArg && firstArg.getKind() !== SyntaxKind.SpreadElement) {
250
+ return resolveObjectLiteralExpression(sourceFile, firstArg, options, seen);
251
+ }
252
+ }
253
+ if (expr.getKind() === SyntaxKind.Identifier) {
254
+ const name = expr.getText();
255
+ if (seen.has(name)) return void 0;
256
+ seen.add(name);
257
+ const initializer = sourceFile.getVariableDeclaration(name)?.getInitializer();
258
+ if (initializer) return resolveObjectLiteralExpression(sourceFile, initializer, options, seen);
259
+ }
260
+ return void 0;
261
+ }
262
+ function isCommonJsExportTarget(node) {
263
+ return node.getText().trim() === "module.exports";
264
+ }
265
+ function isCommonJsExportAssignment(binaryExpression) {
266
+ if (!binaryExpression.isKind(SyntaxKind.BinaryExpression)) return false;
267
+ if (binaryExpression.getOperatorToken().getKind() !== SyntaxKind.EqualsToken) return false;
268
+ return isCommonJsExportTarget(binaryExpression.getLeft());
269
+ }
270
+ function findCommonJSExportExpression(sourceFile) {
271
+ const assignment = sourceFile.getDescendantsOfKind(SyntaxKind.BinaryExpression).find((expr) => isCommonJsExportAssignment(expr));
272
+ return assignment?.getRight();
273
+ }
274
+ function findConfigObject(sourceFile, moduleConfig) {
275
+ if (moduleConfig) {
276
+ const defaultExport = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment);
277
+ const expr2 = defaultExport?.getExpression();
278
+ return expr2 ? resolveObjectLiteralExpression(sourceFile, expr2, { allowCallObjectArg: true }) : void 0;
279
+ }
280
+ const expr = findCommonJSExportExpression(sourceFile);
281
+ return expr ? resolveObjectLiteralExpression(sourceFile, expr, { allowCallObjectArg: true }) : void 0;
282
+ }
283
+ function createConfigSourceFile(fileName, content) {
284
+ const project = new Project({
285
+ useInMemoryFileSystem: true,
286
+ compilerOptions: {
287
+ allowJs: true,
288
+ noResolve: true,
289
+ skipLibCheck: true
290
+ }
291
+ });
292
+ return project.createSourceFile(fileName, content);
293
+ }
294
+ function assertParseable(sourceFile, basename2) {
295
+ const compilerSourceFile = sourceFile.compilerNode;
296
+ const syntaxDiag = compilerSourceFile.parseDiagnostics ?? [];
297
+ if (syntaxDiag.length === 0) return;
298
+ const raw = syntaxDiag[0].messageText;
299
+ const text = typeof raw === "string" ? raw : ts.flattenDiagnosticMessageText(raw, "\n");
300
+ throw new Error(`${basename2}: failed to parse - ${text}`);
301
+ }
302
+ function hasNamedCallExpression(node, name) {
303
+ if (node.isKind(SyntaxKind.CallExpression) && node.getExpression().getText() === name) {
304
+ return true;
305
+ }
306
+ return node.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => call.getExpression().getText() === name);
307
+ }
308
+ function isRequireCall(expr, moduleSpecifier) {
309
+ if (!expr || expr.getKind() !== SyntaxKind.CallExpression) return false;
310
+ const call = expr.asKindOrThrow(SyntaxKind.CallExpression);
311
+ if (call.getExpression().getText() !== "require") return false;
312
+ const firstArg = call.getArguments()[0];
313
+ return firstArg?.getText().replace(/^['"]|['"]$/g, "") === moduleSpecifier;
314
+ }
315
+ function hasNamedImport(sourceFile, functionName, moduleSpecifier) {
316
+ return sourceFile.getImportDeclarations().some(
317
+ (declaration) => declaration.getModuleSpecifierValue() === moduleSpecifier && declaration.getNamedImports().some((namedImport) => namedImport.getName() === functionName)
318
+ );
319
+ }
320
+ function hasNamedRequire(sourceFile, functionName, moduleSpecifier) {
321
+ return sourceFile.getVariableDeclarations().some((declaration) => {
322
+ const nameNode = declaration.getNameNode();
323
+ if (nameNode.getKind() !== SyntaxKind.ObjectBindingPattern) return false;
324
+ const binding = nameNode.asKindOrThrow(SyntaxKind.ObjectBindingPattern);
325
+ const hasBinding = binding.getElements().some((element) => element.getName() === functionName);
326
+ return hasBinding && isRequireCall(declaration.getInitializer(), moduleSpecifier);
327
+ });
328
+ }
329
+ function getCommonJSHelperInsertIndex(sourceFile) {
330
+ const statements = sourceFile.getStatements();
331
+ let insertIndex = 0;
332
+ while (insertIndex < statements.length) {
333
+ const statement = statements[insertIndex];
334
+ if (statement.getKind() !== SyntaxKind.ExpressionStatement) break;
335
+ const expression = statement.asKindOrThrow(SyntaxKind.ExpressionStatement).getExpression();
336
+ if (expression.getKind() !== SyntaxKind.StringLiteral && expression.getKind() !== SyntaxKind.NoSubstitutionTemplateLiteral) {
337
+ break;
338
+ }
339
+ insertIndex++;
340
+ }
341
+ return insertIndex;
342
+ }
343
+ function ensureHelperBinding(sourceFile, functionName, moduleSpecifier, moduleConfig) {
344
+ if (hasNamedImport(sourceFile, functionName, moduleSpecifier) || hasNamedRequire(sourceFile, functionName, moduleSpecifier)) {
345
+ return;
346
+ }
347
+ if (moduleConfig) {
348
+ sourceFile.addImportDeclaration({
349
+ namedImports: [functionName],
350
+ moduleSpecifier
351
+ });
352
+ } else {
353
+ sourceFile.insertStatements(
354
+ getCommonJSHelperInsertIndex(sourceFile),
355
+ `const { ${functionName} } = require("${moduleSpecifier}")
356
+ `
357
+ );
358
+ }
359
+ }
360
+ function configExpressionUsesNamedCall(sourceFile, expression, name) {
361
+ if (hasNamedCallExpression(expression, name)) return true;
362
+ const identifier = expression.getText().trim();
363
+ if (!/^[A-Za-z_$][\w$]*$/.test(identifier)) return false;
364
+ const declaration = sourceFile.getVariableDeclaration(identifier);
365
+ const initializer = declaration?.getInitializer();
366
+ return Boolean(initializer && hasNamedCallExpression(initializer, name));
367
+ }
368
+ function objectPropertyValueUsesNamedCall(sourceFile, property, name) {
369
+ if (property.isKind(SyntaxKind.PropertyAssignment)) {
370
+ const initializer = property.getInitializer();
371
+ return Boolean(initializer && configExpressionUsesNamedCall(sourceFile, initializer, name));
372
+ }
373
+ return configExpressionUsesNamedCall(sourceFile, property, name);
374
+ }
375
+ function viteConfigUsesCortexEditor(content, basename2, moduleConfig) {
376
+ const sourceFile = createConfigSourceFile(basename2, content);
377
+ assertParseable(sourceFile, basename2);
378
+ const configObject = findConfigObject(sourceFile, moduleConfig);
379
+ const pluginsProperty = configObject?.getProperty("plugins");
380
+ return Boolean(
381
+ pluginsProperty && objectPropertyValueUsesNamedCall(sourceFile, pluginsProperty, "cortexEditor")
382
+ );
383
+ }
384
+ function nextConfigUsesWithCortex(content, basename2, moduleConfig) {
385
+ const sourceFile = createConfigSourceFile(basename2, content);
386
+ assertParseable(sourceFile, basename2);
387
+ if (moduleConfig) {
388
+ const defaultExport = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment);
389
+ return Boolean(
390
+ defaultExport && configExpressionUsesNamedCall(sourceFile, defaultExport.getExpression(), "withCortex")
391
+ );
392
+ }
393
+ return sourceFile.getDescendantsOfKind(SyntaxKind.BinaryExpression).some((binaryExpression) => isCommonJsExportAssignment(binaryExpression) && configExpressionUsesNamedCall(sourceFile, binaryExpression.getRight(), "withCortex"));
394
+ }
395
+ function webpackConfigUsesCortexWebpack(content, basename2, moduleConfig) {
396
+ const sourceFile = createConfigSourceFile(basename2, content);
397
+ assertParseable(sourceFile, basename2);
398
+ const configObject = findConfigObject(sourceFile, moduleConfig);
399
+ const pluginsProperty = configObject?.getProperty("plugins");
400
+ return Boolean(
401
+ pluginsProperty && objectPropertyValueUsesNamedCall(sourceFile, pluginsProperty, "cortexWebpack")
402
+ );
403
+ }
404
+ function findFirstExisting(cwd, names) {
405
+ return names.map((file) => path3.join(cwd, file)).find((file) => fs4.existsSync(file)) ?? null;
406
+ }
407
+ function isModuleConfig(filePath, content, pkgType) {
408
+ const ext = path3.extname(filePath);
409
+ if (ext === ".mjs" || ext === ".mts") return true;
410
+ if (ext === ".cjs" || ext === ".cts") return false;
411
+ const sourceFile = createConfigSourceFile(path3.basename(filePath), content);
412
+ if (findCommonJSExportExpression(sourceFile)) return false;
413
+ const exportAssignment = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment);
414
+ if (exportAssignment && !exportAssignment.compilerNode.isExportEquals) {
415
+ return true;
416
+ }
417
+ return pkgType === "module";
418
+ }
419
+ function viteConfigCanBeAutoConfigured(content, basename2, moduleConfig) {
420
+ const sourceFile = createConfigSourceFile(basename2, content);
421
+ assertParseable(sourceFile, basename2);
422
+ return Boolean(findConfigObject(sourceFile, moduleConfig));
423
+ }
424
+ function injectVitePlugin(content, basename2, moduleConfig) {
425
+ const sourceFile = createConfigSourceFile(basename2, content);
426
+ assertParseable(sourceFile, basename2);
427
+ const configObject = findConfigObject(sourceFile, moduleConfig);
428
+ if (!configObject) {
429
+ throw new Error(
430
+ `${basename2}: could not find config object - expected defineConfig({...}), export default {...}, or module.exports = {...}`
431
+ );
432
+ }
433
+ const pluginAdded = addPluginToConfigObject(configObject, "cortexEditor()", basename2);
434
+ if (!pluginAdded) return { content, injected: false };
435
+ ensureHelperBinding(sourceFile, "cortexEditor", "cortex-editor/vite", moduleConfig);
436
+ return { content: sourceFile.getFullText(), injected: true };
437
+ }
438
+ function isFunctionConfigExpression(sourceFile, expr) {
439
+ const kind = expr.getKind();
440
+ if (kind === SyntaxKind.ArrowFunction || kind === SyntaxKind.FunctionExpression) return true;
441
+ if (kind !== SyntaxKind.Identifier) return false;
442
+ const name = expr.getText();
443
+ const variable = sourceFile.getVariableDeclaration(name);
444
+ const initializer = variable?.getInitializer();
445
+ if (initializer) {
446
+ const initializerKind = initializer.getKind();
447
+ return initializerKind === SyntaxKind.ArrowFunction || initializerKind === SyntaxKind.FunctionExpression;
448
+ }
449
+ return Boolean(sourceFile.getFunction(name));
450
+ }
451
+ function wrapConfigExpression(sourceFile, expr, helperName) {
452
+ const exprText = expr.getText();
453
+ if (isFunctionConfigExpression(sourceFile, expr)) {
454
+ return `async (...args) => ${helperName}(await (${exprText})(...args))`;
455
+ }
456
+ return `${helperName}(${exprText})`;
457
+ }
458
+ function injectNextWrapper(content, basename2, moduleConfig) {
459
+ const sourceFile = createConfigSourceFile(basename2, content);
460
+ assertParseable(sourceFile, basename2);
461
+ if (moduleConfig) {
462
+ const defaultExport = sourceFile.getFirstDescendantByKind(SyntaxKind.ExportAssignment);
463
+ if (!defaultExport) return { content, injected: false };
464
+ const expr = defaultExport.getExpression();
465
+ expr.replaceWithText(wrapConfigExpression(sourceFile, expr, "withCortex"));
466
+ ensureHelperBinding(sourceFile, "withCortex", "cortex-editor/next", moduleConfig);
467
+ return { content: sourceFile.getFullText(), injected: true };
468
+ }
469
+ const assignment = sourceFile.getDescendantsOfKind(SyntaxKind.BinaryExpression).find((expr) => isCommonJsExportAssignment(expr));
470
+ if (!assignment) return { content, injected: false };
471
+ const right = assignment.getRight();
472
+ right.replaceWithText(wrapConfigExpression(sourceFile, right, "withCortex"));
473
+ ensureHelperBinding(sourceFile, "withCortex", "cortex-editor/next", moduleConfig);
474
+ return { content: sourceFile.getFullText(), injected: true };
475
+ }
476
+ function addPluginToConfigObject(configObject, pluginExpression, basename2) {
477
+ const pluginsProp = configObject.getProperty("plugins");
478
+ if (pluginsProp) {
479
+ const initializer = pluginsProp.getChildrenOfKind(SyntaxKind.ArrayLiteralExpression)[0];
480
+ if (initializer) {
481
+ initializer.insertElement(0, pluginExpression);
482
+ return true;
483
+ }
484
+ console.warn(` ${basename2}: plugins is not an array literal - add ${pluginExpression} manually`);
485
+ return false;
486
+ }
487
+ configObject.addPropertyAssignment({
488
+ name: "plugins",
489
+ initializer: `[${pluginExpression}]`
490
+ });
491
+ return true;
492
+ }
493
+ function injectWebpackPlugin(content, basename2, moduleConfig) {
494
+ const sourceFile = createConfigSourceFile(basename2, content);
495
+ assertParseable(sourceFile, basename2);
496
+ const configObject = findConfigObject(sourceFile, moduleConfig);
497
+ if (!configObject) {
498
+ const exportKind = moduleConfig ? "default export object" : "module.exports object";
499
+ throw new Error(`${basename2}: expected ${exportKind} to configure with cortexWebpack()`);
500
+ }
501
+ const pluginAdded = addPluginToConfigObject(configObject, "cortexWebpack()", basename2);
502
+ if (!pluginAdded) return { content, injected: false };
503
+ ensureHelperBinding(sourceFile, "cortexWebpack", "cortex-editor/webpack", moduleConfig);
504
+ return { content: sourceFile.getFullText(), injected: true };
505
+ }
506
+ var CORTEX_SLASH_COMMAND = `---
507
+ description: Activate or manage the Cortex visual editor for this project
508
+ argument-hint: [activate|status|apply|deactivate]
509
+ ---
510
+
511
+ # Cortex
512
+
513
+ Use the Cortex MCP tools for this project. Interpret \`$ARGUMENTS\` as an optional action:
514
+
515
+ - No arguments or \`activate\`: call \`cortex_status\`. If the dev server is not connected, tell the user to start the app's normal dev server and open the app in a browser. If connected, call \`cortex_activate\`.
516
+ - \`status\`: call \`cortex_status\` and summarize whether the dev server, browser, and editor are connected.
517
+ - \`deactivate\` or \`close\`: call \`cortex_deactivate\`.
518
+ - \`apply\`: call \`cortex_get_pending_edits\`. If there are staged edits, call \`cortex_apply_edits\` with their intent IDs. For any \`needs-source-edit\` result, inspect the intent/source context as needed, edit the source with normal file-editing tools, then call \`cortex_discard_edits\` for completed intent IDs. Report failed IDs clearly.
519
+
520
+ If the Cortex MCP server is unavailable, ask the user to restart Claude Code or run \`/mcp\` and approve the project-scoped \`cortex\` server.
521
+ `;
522
+ function createInstallRequest(packageManager, packages, cwd) {
523
+ if (packageManager === "pnpm") {
524
+ return {
525
+ packageManager,
526
+ command: "pnpm",
527
+ args: ["add", "-D", ...packages],
528
+ cwd,
529
+ packages
530
+ };
531
+ }
532
+ if (packageManager === "yarn") {
533
+ return {
534
+ packageManager,
535
+ command: "yarn",
536
+ args: ["add", "-D", ...packages],
537
+ cwd,
538
+ packages
539
+ };
540
+ }
541
+ if (packageManager === "bun") {
542
+ return {
543
+ packageManager,
544
+ command: "bun",
545
+ args: ["add", "-d", ...packages],
546
+ cwd,
547
+ packages
548
+ };
549
+ }
550
+ return {
551
+ packageManager,
552
+ command: "npm",
553
+ args: ["install", "-D", ...packages],
554
+ cwd,
555
+ packages
556
+ };
557
+ }
558
+ async function defaultInstallPackages(request) {
559
+ await new Promise((resolve, reject) => {
560
+ const child = spawn(request.command, request.args, {
561
+ cwd: request.cwd,
562
+ stdio: "inherit"
563
+ });
564
+ child.on("error", reject);
565
+ child.on("close", (code, signal) => {
566
+ if (code === 0) {
567
+ resolve();
568
+ } else if (signal) {
569
+ reject(new Error(`${request.command} ${request.args.join(" ")} exited with signal ${signal}`));
570
+ } else {
571
+ reject(
572
+ new Error(
573
+ `${request.command} ${request.args.join(" ")} exited with ${code ?? "unknown status"}`
574
+ )
575
+ );
576
+ }
577
+ });
578
+ });
579
+ }
580
+ async function defaultPromptInstall(request) {
581
+ if (!stdin.isTTY) return false;
582
+ const command = createInstallRequest(request.packageManager, request.packages, request.cwd);
583
+ const promptCwd = path3.resolve(request.cwd);
584
+ const cwdHint = promptCwd === path3.resolve(process.cwd()) ? "" : ` in ${promptCwd}`;
585
+ const rl = createInterface({ input: stdin, output: stdout });
586
+ try {
587
+ const answer = await rl.question(
588
+ `Cortex needs ${request.packages.join(" and ")} to configure source annotations. Run "${command.command} ${command.args.join(" ")}"${cwdHint} now? [Y/n] `
589
+ );
590
+ return answer.trim() === "" || /^y(es)?$/i.test(answer.trim());
591
+ } finally {
592
+ rl.close();
593
+ }
594
+ }
595
+ async function ensurePackages(cwd, pkg, packageManager, packages, reason, options) {
596
+ const missing = packages.filter((name) => !hasDependency(pkg, name));
597
+ if (missing.length === 0) return true;
598
+ const promptInstall = options.promptInstall ?? defaultPromptInstall;
599
+ const approved = await promptInstall({ cwd, packageManager, packages: missing, reason });
600
+ if (!approved) {
601
+ const installRequest2 = createInstallRequest(packageManager, missing, cwd);
602
+ console.warn(
603
+ ` Cortex setup incomplete: missing ${missing.join(" and ")} required to configure source annotations.`
604
+ );
605
+ console.warn(
606
+ ` Install missing packages with: ${installRequest2.command} ${installRequest2.args.join(" ")}`
607
+ );
608
+ console.warn(" Then re-run: npx cortex init");
609
+ return false;
610
+ }
611
+ const installPackages = options.installPackages ?? defaultInstallPackages;
612
+ const installRequest = createInstallRequest(packageManager, missing, cwd);
613
+ await installPackages(installRequest);
614
+ return true;
615
+ }
616
+ function writeViteConfig(cwd) {
617
+ const viteConfigPath = path3.join(cwd, "vite.config.ts");
618
+ const content = [
619
+ "import { defineConfig } from 'vite'",
620
+ "import react from '@vitejs/plugin-react'",
621
+ "import { cortexEditor } from 'cortex-editor/vite'",
622
+ "",
623
+ "export default defineConfig({",
624
+ " plugins: [cortexEditor(), react()],",
625
+ "})",
626
+ ""
627
+ ].join("\n");
628
+ fs4.writeFileSync(viteConfigPath, content);
629
+ console.log(" vite.config.ts: created with cortexEditor plugin");
630
+ return viteConfigPath;
631
+ }
632
+ function writeNextConfig(cwd) {
633
+ const nextConfigPath = path3.join(cwd, "next.config.mjs");
634
+ const content = [
635
+ "import { withCortex } from 'cortex-editor/next'",
636
+ "",
637
+ "export default withCortex({})",
638
+ ""
639
+ ].join("\n");
640
+ fs4.writeFileSync(nextConfigPath, content);
641
+ console.log(" next.config.mjs: created with withCortex()");
642
+ return nextConfigPath;
643
+ }
644
+ function selectBundler(cwd, pkg, paths) {
645
+ if (paths.nextConfigPath) return "next";
646
+ if (paths.viteConfigPath) return "vite";
647
+ if (paths.webpackConfigPath) return "webpack";
648
+ if (hasDependency(pkg, "next")) return "next";
649
+ if (hasDependency(pkg, "vite")) return "vite";
650
+ if (hasDependency(pkg, "webpack") || hasDependency(pkg, "react-scripts")) return "webpack";
651
+ void cwd;
652
+ return "none";
653
+ }
654
+ async function runInit(cwd = process.cwd(), options = {}) {
655
+ const pkgPath = path3.join(cwd, "package.json");
656
+ if (!fs4.existsSync(pkgPath)) {
657
+ throw new Error("No package.json found. Run this from your project root.");
658
+ }
659
+ let pkg;
660
+ try {
661
+ pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf8"));
662
+ } catch (err) {
663
+ throw new Error(
664
+ `package.json: failed to parse - ${err instanceof Error ? err.message : String(err)}`
665
+ );
666
+ }
667
+ const mcpPath = path3.join(cwd, ".mcp.json");
668
+ let mcpConfig = {};
669
+ let mcpWritten = false;
670
+ if (fs4.existsSync(mcpPath)) {
671
+ try {
672
+ mcpConfig = JSON.parse(fs4.readFileSync(mcpPath, "utf8"));
673
+ } catch (err) {
674
+ throw new Error(
675
+ `.mcp.json: failed to parse - ${err instanceof Error ? err.message : String(err)}
676
+ Fix the JSON syntax and re-run cortex init.`
677
+ );
678
+ }
679
+ if (typeof mcpConfig !== "object" || mcpConfig === null || Array.isArray(mcpConfig)) {
680
+ throw new Error(".mcp.json: root value must be a JSON object.");
681
+ }
682
+ }
683
+ const rawServers = mcpConfig.mcpServers;
684
+ if (rawServers !== void 0 && rawServers !== null && (typeof rawServers !== "object" || Array.isArray(rawServers))) {
685
+ throw new Error('.mcp.json: "mcpServers" must be an object.');
686
+ }
687
+ const servers = rawServers ?? {};
688
+ if (servers.cortex) {
689
+ console.log(" .mcp.json: cortex already configured");
690
+ } else {
691
+ servers.cortex = { command: "npx", args: ["cortex", "mcp"] };
692
+ mcpConfig.mcpServers = servers;
693
+ fs4.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2) + "\n");
694
+ console.log(" .mcp.json: added cortex MCP server");
695
+ mcpWritten = true;
696
+ }
697
+ const slashCommandPath = path3.join(cwd, ".claude", "commands", "cortex.md");
698
+ let slashCommandFound = false;
699
+ let slashCommandWritten = false;
700
+ if (fs4.existsSync(slashCommandPath)) {
701
+ slashCommandFound = true;
702
+ console.log(" .claude/commands/cortex.md: /cortex command already configured");
703
+ } else {
704
+ fs4.mkdirSync(path3.dirname(slashCommandPath), { recursive: true });
705
+ fs4.writeFileSync(slashCommandPath, CORTEX_SLASH_COMMAND);
706
+ slashCommandFound = true;
707
+ slashCommandWritten = true;
708
+ console.log(" .claude/commands/cortex.md: added /cortex slash command");
709
+ }
710
+ const viteConfigPath = findFirstExisting(cwd, VITE_CONFIG_FILES);
711
+ const nextConfigPath = findFirstExisting(cwd, NEXT_CONFIG_FILES);
712
+ const webpackConfigPath = findFirstExisting(cwd, WEBPACK_CONFIG_FILES);
713
+ const webpackConfigFound = Boolean(webpackConfigPath);
714
+ const detectedBundler = selectBundler(cwd, pkg, {
715
+ viteConfigPath,
716
+ nextConfigPath,
717
+ webpackConfigPath
718
+ });
719
+ const packageManager = detectPackageManager(cwd, pkg);
720
+ const depFound = hasDependency(pkg, "cortex-editor");
721
+ let vitePluginFound = null;
722
+ let vitePluginInjected = false;
723
+ let viteConfigCreated = false;
724
+ let nextConfigFound = null;
725
+ let nextConfigInjected = false;
726
+ let nextConfigCreated = false;
727
+ let webpackConfigInjected = false;
728
+ let adapterConfigured = false;
729
+ if (!depFound) {
730
+ const installRequest = createInstallRequest(packageManager, ["cortex-editor"], cwd);
731
+ console.warn(
732
+ " cortex-editor not in dependencies - add it before configuring source annotations."
733
+ );
734
+ console.warn(
735
+ ` Install cortex-editor with: ${installRequest.command} ${installRequest.args.join(" ")}`
736
+ );
737
+ } else if (detectedBundler === "next") {
738
+ if (viteConfigPath && nextConfigPath) {
739
+ console.warn(
740
+ ` ${path3.basename(viteConfigPath)} found alongside ${path3.basename(nextConfigPath)}; skipping Vite setup to avoid configuring auxiliary tooling`
741
+ );
742
+ }
743
+ if (!nextConfigPath) {
744
+ writeNextConfig(cwd);
745
+ nextConfigFound = true;
746
+ nextConfigInjected = true;
747
+ nextConfigCreated = true;
748
+ adapterConfigured = true;
749
+ } else {
750
+ nextConfigFound = true;
751
+ const basename2 = path3.basename(nextConfigPath);
752
+ const content = fs4.readFileSync(nextConfigPath, "utf8");
753
+ const moduleConfig = isModuleConfig(nextConfigPath, content, pkg.type);
754
+ if (nextConfigUsesWithCortex(content, basename2, moduleConfig)) {
755
+ console.log(` ${basename2}: withCortex config found`);
756
+ adapterConfigured = true;
757
+ } else {
758
+ const result = injectNextWrapper(content, basename2, moduleConfig);
759
+ if (result.injected) {
760
+ fs4.writeFileSync(nextConfigPath, result.content);
761
+ nextConfigInjected = true;
762
+ adapterConfigured = true;
763
+ console.log(` ${basename2}: withCortex config injected`);
764
+ } else {
765
+ console.warn(
766
+ ` ${basename2}: could not auto-configure Next.js - wrap your config with withCortex() from cortex-editor/next`
767
+ );
768
+ }
769
+ }
770
+ }
771
+ } else if (detectedBundler === "vite") {
772
+ if (webpackConfigPath && viteConfigPath) {
773
+ console.warn(
774
+ ` ${path3.basename(webpackConfigPath)} found alongside ${path3.basename(viteConfigPath)}; skipping Webpack setup because Vite is the selected app adapter`
775
+ );
776
+ }
777
+ if (!viteConfigPath) {
778
+ const installed = await ensurePackages(
779
+ cwd,
780
+ pkg,
781
+ packageManager,
782
+ VITE_SETUP_PACKAGES,
783
+ "missing-vite-config",
784
+ options
785
+ );
786
+ if (installed) {
787
+ writeViteConfig(cwd);
788
+ vitePluginFound = true;
789
+ vitePluginInjected = true;
790
+ viteConfigCreated = true;
791
+ adapterConfigured = true;
792
+ }
793
+ } else {
794
+ const vitePeerInstalled = await ensurePackages(
795
+ cwd,
796
+ pkg,
797
+ packageManager,
798
+ ["vite"],
799
+ "missing-vite-peer",
800
+ options
801
+ );
802
+ if (vitePeerInstalled) {
803
+ const basename2 = path3.basename(viteConfigPath);
804
+ const content = fs4.readFileSync(viteConfigPath, "utf8");
805
+ const moduleConfig = isModuleConfig(viteConfigPath, content, pkg.type);
806
+ if (viteConfigUsesCortexEditor(content, basename2, moduleConfig)) {
807
+ vitePluginFound = true;
808
+ adapterConfigured = true;
809
+ console.log(` ${basename2}: cortexEditor plugin found`);
810
+ } else if (!viteConfigCanBeAutoConfigured(content, basename2, moduleConfig)) {
811
+ vitePluginFound = false;
812
+ console.warn(
813
+ ` ${basename2}: Vite config cannot be auto-configured - use export default/module.exports syntax or add cortexEditor() manually.`
814
+ );
815
+ } else {
816
+ const result = injectVitePlugin(content, basename2, moduleConfig);
817
+ if (result.injected) {
818
+ fs4.writeFileSync(viteConfigPath, result.content);
819
+ vitePluginFound = true;
820
+ vitePluginInjected = true;
821
+ adapterConfigured = true;
822
+ console.log(` ${basename2}: cortexEditor plugin injected`);
823
+ } else {
824
+ vitePluginFound = false;
825
+ }
826
+ }
827
+ }
828
+ }
829
+ } else if (detectedBundler === "webpack") {
830
+ if (!webpackConfigPath) {
831
+ console.warn(
832
+ " Webpack detected but no webpack.config.* file was found - add cortexWebpack() manually or create a config file, then re-run cortex init."
833
+ );
834
+ } else {
835
+ const basename2 = path3.basename(webpackConfigPath);
836
+ const content = fs4.readFileSync(webpackConfigPath, "utf8");
837
+ const moduleConfig = isModuleConfig(webpackConfigPath, content, pkg.type);
838
+ if (webpackConfigUsesCortexWebpack(content, basename2, moduleConfig)) {
839
+ adapterConfigured = true;
840
+ console.log(` ${basename2}: cortexWebpack plugin found`);
841
+ } else {
842
+ const result = injectWebpackPlugin(content, basename2, moduleConfig);
843
+ if (result.injected) {
844
+ fs4.writeFileSync(webpackConfigPath, result.content);
845
+ webpackConfigInjected = true;
846
+ adapterConfigured = true;
847
+ console.log(` ${basename2}: cortexWebpack plugin injected`);
848
+ }
849
+ }
850
+ }
851
+ } else {
852
+ const installed = await ensurePackages(
853
+ cwd,
854
+ pkg,
855
+ packageManager,
856
+ VITE_SETUP_PACKAGES,
857
+ "missing-bundler",
858
+ options
859
+ );
860
+ if (installed) {
861
+ writeViteConfig(cwd);
862
+ vitePluginFound = true;
863
+ vitePluginInjected = true;
864
+ viteConfigCreated = true;
865
+ adapterConfigured = true;
866
+ }
867
+ }
868
+ const setupComplete = depFound && adapterConfigured;
869
+ if (setupComplete) {
870
+ console.log(" Setup complete. Restart your AI agent so it picks up .mcp.json.");
871
+ try {
872
+ const telemetry = createTelemetry({
873
+ enabled: resolveTelemetryEnabled({}),
874
+ endpoint: resolveTelemetryEndpoint({}),
875
+ cortexRoot: cwd,
876
+ version
877
+ });
878
+ await telemetry.recordInit();
879
+ } catch {
880
+ }
881
+ } else {
882
+ console.warn(" Cortex setup incomplete. Resolve the warnings above, then re-run cortex init.");
883
+ }
884
+ return {
885
+ mcpWritten,
886
+ slashCommandFound,
887
+ slashCommandWritten,
888
+ vitePluginFound,
889
+ vitePluginInjected,
890
+ viteConfigCreated,
891
+ nextConfigFound,
892
+ nextConfigInjected,
893
+ nextConfigCreated,
894
+ webpackConfigFound,
895
+ webpackConfigInjected,
896
+ depFound,
897
+ detectedBundler,
898
+ packageManager,
899
+ setupComplete
900
+ };
901
+ }
902
+ export {
903
+ runInit
904
+ };