@bonginkan/maria 4.3.27 → 4.3.28
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/README.md +4 -4
- package/dist/READY.manifest.json +1 -1
- package/dist/bin/maria.cjs +326 -43
- package/dist/bin/maria.cjs.map +1 -1
- package/dist/cli.cjs +326 -43
- package/dist/cli.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/server/express-server.cjs +1 -1
- package/dist/server/express-server.js +1 -1
- package/dist/server-express.cjs +1 -1
- package/dist/server-express.cjs.map +1 -1
- package/package.json +2 -2
- package/src/slash-commands/READY.manifest.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -1704,7 +1704,7 @@ var init_AuthenticationManager = __esm({
|
|
|
1704
1704
|
const response = await fetch(`${this.apiBase}/api/user/profile`, {
|
|
1705
1705
|
headers: {
|
|
1706
1706
|
"Authorization": `Bearer ${tokens2.accessToken}`,
|
|
1707
|
-
"User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.
|
|
1707
|
+
"User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.28"}`
|
|
1708
1708
|
}
|
|
1709
1709
|
});
|
|
1710
1710
|
if (response.status === 401) {
|
|
@@ -2407,7 +2407,7 @@ async function callApi(path60, init3 = {}) {
|
|
|
2407
2407
|
"Authorization": `Bearer ${token}`,
|
|
2408
2408
|
"X-Device-Id": getDeviceId(),
|
|
2409
2409
|
"X-Session-Id": getSessionId() || "",
|
|
2410
|
-
"User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.
|
|
2410
|
+
"User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.28"}`,
|
|
2411
2411
|
"Content-Type": init3.headers?.["Content-Type"] || "application/json"
|
|
2412
2412
|
});
|
|
2413
2413
|
const doFetch = async (token) => {
|
|
@@ -16121,8 +16121,8 @@ var require_package = __commonJS({
|
|
|
16121
16121
|
"package.json"(exports, module) {
|
|
16122
16122
|
module.exports = {
|
|
16123
16123
|
name: "@bonginkan/maria",
|
|
16124
|
-
version: "4.3.
|
|
16125
|
-
description: "\u{1F680} MARIA v4.3.
|
|
16124
|
+
version: "4.3.28",
|
|
16125
|
+
description: "\u{1F680} MARIA v4.3.28 - Enterprise AI Development Platform with identity system and character voice implementation. Features 74 production-ready commands with comprehensive fallback implementation, local LLM support, and zero external dependencies. Includes natural language coding, AI safety evaluation, intelligent evolution system, episodic memory with PII masking, and real-time monitoring dashboard. Built with TypeScript AST-powered code generation, OAuth2.0 + PKCE authentication, quantum-resistant cryptography, and enterprise-grade performance.",
|
|
16126
16126
|
keywords: [
|
|
16127
16127
|
"ai",
|
|
16128
16128
|
"cli",
|
|
@@ -19285,7 +19285,7 @@ async function applyPlans(plans, opts) {
|
|
|
19285
19285
|
try {
|
|
19286
19286
|
for (const plan of plans) {
|
|
19287
19287
|
if (opts.signal?.aborted) throw abortErr();
|
|
19288
|
-
const target = path10__namespace.default.join(opts.root, plan.path);
|
|
19288
|
+
const target = plan.absPath ? plan.absPath : path10__namespace.default.join(opts.root, plan.path);
|
|
19289
19289
|
const dir = path10__namespace.default.dirname(target);
|
|
19290
19290
|
await fs19.promises.mkdir(dir, { recursive: true });
|
|
19291
19291
|
const exists2 = await fileExists(target);
|
|
@@ -25753,7 +25753,7 @@ var init_about_command = __esm({
|
|
|
25753
25753
|
async execute(args2, context2) {
|
|
25754
25754
|
const output3 = [];
|
|
25755
25755
|
output3.push("");
|
|
25756
|
-
output3.push(chalk40__default.default.cyan.bold("\u{1F916} About MARIA v4.3.
|
|
25756
|
+
output3.push(chalk40__default.default.cyan.bold("\u{1F916} About MARIA v4.3.28"));
|
|
25757
25757
|
output3.push(chalk40__default.default.gray("\u2550".repeat(40)));
|
|
25758
25758
|
output3.push("");
|
|
25759
25759
|
output3.push(chalk40__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
|
|
@@ -38018,6 +38018,10 @@ async function normalizePlans(plans, opts) {
|
|
|
38018
38018
|
const profile = await scanRepo(opts.root);
|
|
38019
38019
|
const out = [];
|
|
38020
38020
|
for (const fp of plans) {
|
|
38021
|
+
if (fp.noNormalize) {
|
|
38022
|
+
out.push(fp);
|
|
38023
|
+
continue;
|
|
38024
|
+
}
|
|
38021
38025
|
const n = normalizePlanItem(fp, profile);
|
|
38022
38026
|
if (!n.kind) n.kind = guessKindByPath(n.path);
|
|
38023
38027
|
out.push(n);
|
|
@@ -38062,7 +38066,7 @@ async function validatePlan(plans, opts) {
|
|
|
38062
38066
|
skipped.push(fp.path);
|
|
38063
38067
|
continue;
|
|
38064
38068
|
}
|
|
38065
|
-
const full = path10__namespace.default.join(opts.root, rel);
|
|
38069
|
+
const full = fp.absPath ? fp.absPath : path10__namespace.default.join(opts.root, rel);
|
|
38066
38070
|
if (!full.startsWith(path10__namespace.default.resolve(opts.root))) {
|
|
38067
38071
|
warnings.push(`Outside root denied: ${fp.path}`);
|
|
38068
38072
|
skipped.push(fp.path);
|
|
@@ -38193,10 +38197,10 @@ function formatPlan(summary, opts) {
|
|
|
38193
38197
|
budget.diffLines = Math.min(budget.diffLines, 20);
|
|
38194
38198
|
lines.push("", `Diff preview (truncated to ${budget.diffLines} lines per file):`);
|
|
38195
38199
|
for (const f3 of summary.files) {
|
|
38196
|
-
if (f3.action
|
|
38197
|
-
const before = readCurrentFileSafe(opts.root, f3.path);
|
|
38200
|
+
if (f3.action !== "modify") continue;
|
|
38201
|
+
const before = readCurrentFileSafe(opts.root, f3.path, f3.absPath);
|
|
38198
38202
|
const after = f3.preview || "";
|
|
38199
|
-
const diff = buildUnifiedDiff(f3.path, before, after, budget);
|
|
38203
|
+
const diff = buildUnifiedDiff(f3.path, before, after, budget, f3.absPath);
|
|
38200
38204
|
lines.push(diff, "");
|
|
38201
38205
|
}
|
|
38202
38206
|
}
|
|
@@ -38233,9 +38237,10 @@ function formatPlanAsDiff(files, opts) {
|
|
|
38233
38237
|
let shownFiles = 0;
|
|
38234
38238
|
for (const f3 of files) {
|
|
38235
38239
|
if (budget.globalMaxFiles !== void 0 && shownFiles >= budget.globalMaxFiles) break;
|
|
38236
|
-
|
|
38240
|
+
if (f3.action !== "modify") continue;
|
|
38241
|
+
const before = readCurrentFileSafe(opts.root, f3.path, f3.absPath);
|
|
38237
38242
|
const after = f3.preview || "";
|
|
38238
|
-
const diff = buildUnifiedDiff(f3.path, before, after, budget);
|
|
38243
|
+
const diff = buildUnifiedDiff(f3.path, before, after, budget, f3.absPath);
|
|
38239
38244
|
const diffBytes = Buffer.byteLength(diff, "utf8");
|
|
38240
38245
|
if (budget.globalMaxBytes !== void 0 && bytesUsed + diffBytes > budget.globalMaxBytes && shownFiles > 0) {
|
|
38241
38246
|
lines.push(`
|
|
@@ -38252,11 +38257,11 @@ function formatPlanAsDiff(files, opts) {
|
|
|
38252
38257
|
}
|
|
38253
38258
|
return lines.join("\n");
|
|
38254
38259
|
}
|
|
38255
|
-
function readCurrentFileSafe(root, rel) {
|
|
38256
|
-
if (!root) return "";
|
|
38260
|
+
function readCurrentFileSafe(root, rel, abs) {
|
|
38261
|
+
if (!root && !abs) return "";
|
|
38257
38262
|
try {
|
|
38258
38263
|
const fs49 = __require("fs");
|
|
38259
|
-
const p = __require("path").join(root, rel);
|
|
38264
|
+
const p = abs ? abs : __require("path").join(root, rel);
|
|
38260
38265
|
return fs49.existsSync(p) ? fs49.readFileSync(p, "utf8") : "";
|
|
38261
38266
|
} catch {
|
|
38262
38267
|
return "";
|
|
@@ -38273,7 +38278,7 @@ function normalizeDiffBudget(b) {
|
|
|
38273
38278
|
globalMaxFiles: Number.isFinite(b?.globalMaxFiles) ? b.globalMaxFiles : envGlobalFiles
|
|
38274
38279
|
};
|
|
38275
38280
|
}
|
|
38276
|
-
function buildUnifiedDiff(relPath, before, after, b) {
|
|
38281
|
+
function buildUnifiedDiff(relPath, before, after, b, abs) {
|
|
38277
38282
|
const beforeLines = before.split(/\r?\n/);
|
|
38278
38283
|
const afterLines = after.split(/\r?\n/);
|
|
38279
38284
|
let i2 = 0;
|
|
@@ -38282,14 +38287,15 @@ function buildUnifiedDiff(relPath, before, after, b) {
|
|
|
38282
38287
|
while (j < beforeLines.length - i2 && j < afterLines.length - i2 && beforeLines[beforeLines.length - 1 - j] === afterLines[afterLines.length - 1 - j]) j++;
|
|
38283
38288
|
const oldMid = beforeLines.slice(i2, beforeLines.length - j);
|
|
38284
38289
|
const newMid = afterLines.slice(i2, afterLines.length - j);
|
|
38285
|
-
const
|
|
38290
|
+
const headerPath = abs ? abs : relPath;
|
|
38291
|
+
const header = [`--- ${headerPath}`, `+++ ${headerPath}`];
|
|
38286
38292
|
const body = [];
|
|
38287
38293
|
const ctxPrefix = Math.max(0, i2 - 3);
|
|
38288
38294
|
Math.min(beforeLines.length, beforeLines.length - j + 3);
|
|
38289
38295
|
const preCtx = beforeLines.slice(ctxPrefix, i2).map((l) => ` ${l}`);
|
|
38290
38296
|
const postCtx = beforeLines.slice(beforeLines.length - j, Math.min(beforeLines.length - j + 3, beforeLines.length)).map((l) => ` ${l}`);
|
|
38291
|
-
const del = oldMid.map((l) => `-${l}`);
|
|
38292
|
-
const add = newMid.map((l) => `+${l}`);
|
|
38297
|
+
const del = oldMid.map((l) => colorRed(`-${l}`));
|
|
38298
|
+
const add = newMid.map((l) => colorGreen(`+${l}`));
|
|
38293
38299
|
body.push(...preCtx);
|
|
38294
38300
|
body.push(...del);
|
|
38295
38301
|
body.push(...add);
|
|
@@ -38306,6 +38312,22 @@ function buildUnifiedDiff(relPath, before, after, b) {
|
|
|
38306
38312
|
}
|
|
38307
38313
|
return out;
|
|
38308
38314
|
}
|
|
38315
|
+
function colorGreen(s2) {
|
|
38316
|
+
try {
|
|
38317
|
+
const chalk43 = __require("chalk");
|
|
38318
|
+
return chalk43.green(s2);
|
|
38319
|
+
} catch {
|
|
38320
|
+
return s2;
|
|
38321
|
+
}
|
|
38322
|
+
}
|
|
38323
|
+
function colorRed(s2) {
|
|
38324
|
+
try {
|
|
38325
|
+
const chalk43 = __require("chalk");
|
|
38326
|
+
return chalk43.red(s2);
|
|
38327
|
+
} catch {
|
|
38328
|
+
return s2;
|
|
38329
|
+
}
|
|
38330
|
+
}
|
|
38309
38331
|
function languageLabel(lang, filePath) {
|
|
38310
38332
|
if (lang) {
|
|
38311
38333
|
const l = lang.toLowerCase();
|
|
@@ -38932,6 +38954,20 @@ var init_policy = __esm({
|
|
|
38932
38954
|
}
|
|
38933
38955
|
});
|
|
38934
38956
|
|
|
38957
|
+
// src/utils/esm-compat.ts
|
|
38958
|
+
var esm_compat_exports = {};
|
|
38959
|
+
__export(esm_compat_exports, {
|
|
38960
|
+
loadGlobby: () => loadGlobby
|
|
38961
|
+
});
|
|
38962
|
+
async function loadGlobby() {
|
|
38963
|
+
const mod = await import('globby');
|
|
38964
|
+
return mod?.globby ?? mod?.default ?? mod;
|
|
38965
|
+
}
|
|
38966
|
+
var init_esm_compat = __esm({
|
|
38967
|
+
"src/utils/esm-compat.ts"() {
|
|
38968
|
+
}
|
|
38969
|
+
});
|
|
38970
|
+
|
|
38935
38971
|
// src/services/code-orchestrator/Orchestrator.ts
|
|
38936
38972
|
var Orchestrator_exports = {};
|
|
38937
38973
|
__export(Orchestrator_exports, {
|
|
@@ -38966,6 +39002,20 @@ async function orchestrate(request, opts) {
|
|
|
38966
39002
|
const initial = [];
|
|
38967
39003
|
const fallbackNotices = [];
|
|
38968
39004
|
const withNotices = (base) => fallbackNotices.length > 0 ? [...fallbackNotices, ...base] : base;
|
|
39005
|
+
const explicitFilesRaw = parseExplicitFilenames(request);
|
|
39006
|
+
const explicitFiles = explicitFilesRaw.length > 0 ? await resolveExplicitPaths(opts.root, explicitFilesRaw, request) : [];
|
|
39007
|
+
const explicitAbsMap = /* @__PURE__ */ Object.create(null);
|
|
39008
|
+
if (explicitFiles.length > 0) {
|
|
39009
|
+
const pathMod = await import('path');
|
|
39010
|
+
for (const rel of explicitFiles) {
|
|
39011
|
+
explicitAbsMap[rel] = pathMod.join(opts.root, rel);
|
|
39012
|
+
}
|
|
39013
|
+
}
|
|
39014
|
+
const isEditIntent = detectEditIntent(request, {
|
|
39015
|
+
hasAttachments: !!(opts.attachedFiles && opts.attachedFiles.length > 0),
|
|
39016
|
+
explicitFilesCount: explicitFiles.length
|
|
39017
|
+
});
|
|
39018
|
+
const editContext = isEditIntent && explicitFiles.length > 0 ? await buildEditContext(opts.root, explicitFiles, 200, 512 * 1024) : "";
|
|
38969
39019
|
if (opts.attachedFiles && opts.attachedFiles.length > 0) {
|
|
38970
39020
|
const mapRes = await mapAttachmentsToTargets(opts.attachedFiles, {
|
|
38971
39021
|
root: opts.root,
|
|
@@ -38985,7 +39035,6 @@ async function orchestrate(request, opts) {
|
|
|
38985
39035
|
}
|
|
38986
39036
|
}
|
|
38987
39037
|
const onlyAttached = !!opts.flags.onlyAttached;
|
|
38988
|
-
const explicitFiles = parseExplicitFilenames(request);
|
|
38989
39038
|
if (!onlyAttached) {
|
|
38990
39039
|
let codeOutput = "";
|
|
38991
39040
|
if (process.env.MARIA_E2E_FAKE_CODE === "1") {
|
|
@@ -39005,9 +39054,17 @@ async function orchestrate(request, opts) {
|
|
|
39005
39054
|
"[BEGIN file: path]\n<content>\n[END]",
|
|
39006
39055
|
"Do not include any prose before/after; no menus/questions/suggestions; start immediately with ``` or [BEGIN file: ...]."
|
|
39007
39056
|
].join("\n");
|
|
39057
|
+
const requestPreamble = isEditIntent ? [
|
|
39058
|
+
"// EDIT MODE: modify existing files, preserve unrelated content.",
|
|
39059
|
+
"// Follow existing structure and only touch requested files.",
|
|
39060
|
+
editContext ? "// Current file snapshots provided below." : ""
|
|
39061
|
+
].filter(Boolean).join("\n") : "";
|
|
39008
39062
|
const enriched = `${FILE_FORMAT_INSTRUCTIONS}
|
|
39009
39063
|
|
|
39010
|
-
${
|
|
39064
|
+
${requestPreamble}
|
|
39065
|
+
${request}
|
|
39066
|
+
|
|
39067
|
+
${editContext}`;
|
|
39011
39068
|
const response = await executeCode(enriched);
|
|
39012
39069
|
const raw = (response.output || response?.data?.content || "").trim();
|
|
39013
39070
|
if (!raw) {
|
|
@@ -39052,24 +39109,27 @@ ${request}`;
|
|
|
39052
39109
|
const htmlIdx = blocks.findIndex((b) => /html/i.test(b.language));
|
|
39053
39110
|
const htmlFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".html"));
|
|
39054
39111
|
if (htmlIdx >= 0 && htmlFile) {
|
|
39055
|
-
initial.push({ path: htmlFile, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
|
|
39112
|
+
initial.push({ path: htmlFile, absPath: explicitAbsMap[htmlFile], noNormalize: true, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
|
|
39056
39113
|
mapped.add(htmlFile);
|
|
39057
39114
|
}
|
|
39058
39115
|
const jsIdx = blocks.findIndex((b) => /(ts|tsx|jsx|javascript|js)/i.test(b.language));
|
|
39059
39116
|
const jsFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".js"));
|
|
39060
39117
|
if (jsIdx >= 0 && jsFile && !mapped.has(jsFile)) {
|
|
39061
|
-
initial.push({ path: jsFile, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
|
|
39118
|
+
initial.push({ path: jsFile, absPath: explicitAbsMap[jsFile], noNormalize: true, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
|
|
39062
39119
|
mapped.add(jsFile);
|
|
39063
39120
|
}
|
|
39064
39121
|
const cssIdx = blocks.findIndex((b) => /css/i.test(b.language));
|
|
39065
39122
|
const cssFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".css"));
|
|
39066
39123
|
if (cssIdx >= 0 && cssFile && !mapped.has(cssFile)) {
|
|
39067
|
-
initial.push({ path: cssFile, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
|
|
39124
|
+
initial.push({ path: cssFile, absPath: explicitAbsMap[cssFile], noNormalize: true, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
|
|
39068
39125
|
mapped.add(cssFile);
|
|
39069
39126
|
}
|
|
39070
39127
|
for (const f3 of explicitFiles) {
|
|
39071
39128
|
if (mapped.has(f3)) continue;
|
|
39072
|
-
|
|
39129
|
+
const plan = scaffoldForFilename(f3, explicitFiles);
|
|
39130
|
+
plan.absPath = explicitAbsMap[f3];
|
|
39131
|
+
plan.noNormalize = true;
|
|
39132
|
+
initial.push(plan);
|
|
39073
39133
|
}
|
|
39074
39134
|
} else {
|
|
39075
39135
|
for (let i2 = 0; i2 < blocks.length; i2++) {
|
|
@@ -39087,12 +39147,26 @@ ${request}`;
|
|
|
39087
39147
|
}
|
|
39088
39148
|
}
|
|
39089
39149
|
}
|
|
39150
|
+
if (!isEditIntent) {
|
|
39151
|
+
const proposedTop = deriveProjectFolderName(request);
|
|
39152
|
+
const { folderName, detectedTop } = await ensureTopFolder(opts.root, proposedTop, initial);
|
|
39153
|
+
if (folderName) {
|
|
39154
|
+
for (const p of initial) {
|
|
39155
|
+
if (!startsWithTopFolder(p.path, detectedTop || folderName)) {
|
|
39156
|
+
p.path = prefixWithTopFolder(p.path, folderName);
|
|
39157
|
+
}
|
|
39158
|
+
}
|
|
39159
|
+
}
|
|
39160
|
+
}
|
|
39090
39161
|
if (explicitFiles.length > 0 && initial.filter((f3) => !!f3.preview).length === 0) {
|
|
39091
39162
|
for (const f3 of explicitFiles) {
|
|
39092
39163
|
initial.push(scaffoldForFilename(f3, explicitFiles));
|
|
39093
39164
|
}
|
|
39094
39165
|
}
|
|
39095
|
-
const normalized = await normalizePlans(
|
|
39166
|
+
const normalized = await normalizePlans(
|
|
39167
|
+
initial.map((p) => p.noNormalize ? p : p),
|
|
39168
|
+
{ root: opts.root }
|
|
39169
|
+
);
|
|
39096
39170
|
try {
|
|
39097
39171
|
const [{ access: access18 }, path60] = await Promise.all([
|
|
39098
39172
|
import('fs/promises'),
|
|
@@ -39100,8 +39174,12 @@ ${request}`;
|
|
|
39100
39174
|
]);
|
|
39101
39175
|
for (const p of normalized) {
|
|
39102
39176
|
try {
|
|
39103
|
-
|
|
39177
|
+
const absCandidate = p.absPath ? p.absPath : path60.join(opts.root, p.path);
|
|
39178
|
+
await access18(absCandidate);
|
|
39104
39179
|
p.action = "modify";
|
|
39180
|
+
if (isEditIntent) {
|
|
39181
|
+
p.overwritePolicy = "allow";
|
|
39182
|
+
}
|
|
39105
39183
|
} catch {
|
|
39106
39184
|
p.action = "create";
|
|
39107
39185
|
}
|
|
@@ -39109,10 +39187,12 @@ ${request}`;
|
|
|
39109
39187
|
} catch {
|
|
39110
39188
|
}
|
|
39111
39189
|
const validated = await validatePlan(normalized, { root: opts.root, profile, flags: { maxFiles: opts.flags.maxFiles, yes: opts.flags.yes, interactive: !!opts.flags.interactive, ...opts.flags } });
|
|
39112
|
-
const
|
|
39113
|
-
const
|
|
39114
|
-
|
|
39115
|
-
);
|
|
39190
|
+
const hasAnyModify = validated.files.some((f3) => f3.action === "modify") || isEditIntent;
|
|
39191
|
+
const outputMode = !opts.flags.hideCode && hasAnyModify ? "diff" : resolveOutputMode(opts.flags.output, validated.files.length, !!opts.flags.hideCode);
|
|
39192
|
+
const skippedSetForLookup = new Set(validated.skipped || []);
|
|
39193
|
+
const skippedPlans = normalized.filter((f3) => skippedSetForLookup.has(f3.path));
|
|
39194
|
+
const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
|
|
39195
|
+
const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
|
|
39116
39196
|
const summary = summarizePlan(displayFiles);
|
|
39117
39197
|
const lines = [
|
|
39118
39198
|
formatPlan(summary, {
|
|
@@ -39150,6 +39230,7 @@ ${request}`;
|
|
|
39150
39230
|
if (softIssues.hasTrailingWhitespace) lines.push(warnLine("Proposed changes contain trailing whitespace"));
|
|
39151
39231
|
if (softIssues.hasConflictMarkers) lines.push(warnLine("Proposed changes contain conflict markers"));
|
|
39152
39232
|
}
|
|
39233
|
+
const preApplyOutput = withNotices(lines);
|
|
39153
39234
|
let appliedCount = 0;
|
|
39154
39235
|
let durationMs = 0;
|
|
39155
39236
|
let rolledBack = false;
|
|
@@ -39161,7 +39242,7 @@ ${request}`;
|
|
|
39161
39242
|
return { plan: normalized, validated, summaryLines: withNotices([errorLine("working tree not clean (commit or stash first). Re-run after cleaning your git status.")]) };
|
|
39162
39243
|
}
|
|
39163
39244
|
}
|
|
39164
|
-
const allowOverwrite = opts.flags.overwriteAllowed === true || !!opts.flags.yes;
|
|
39245
|
+
const allowOverwrite = opts.flags.overwriteAllowed === true || !!opts.flags.yes || isEditIntent;
|
|
39165
39246
|
const applyRes = await applyPlans(approved, { root: opts.root, overwriteAllowed: allowOverwrite, rollback: opts.flags.rollback !== false, signal: opts.abortSignal, onProgress: (w, t2) => {
|
|
39166
39247
|
}, eol: profile.eol });
|
|
39167
39248
|
appliedCount = applyRes.appliedCount;
|
|
@@ -39191,7 +39272,7 @@ ${request}`;
|
|
|
39191
39272
|
const savedList = [].concat(applyRes.created, applyRes.modified);
|
|
39192
39273
|
const savedAbs = savedList.map((rel) => path10__namespace.default.resolve(opts.root, rel));
|
|
39193
39274
|
const footer = savedAbs.length > 0 ? ["Saved files (full paths):", ...savedAbs.map((p) => `- ${p}`)] : [];
|
|
39194
|
-
return { plan: normalized, validated, applied: { count: appliedCount, durationMs, rolledBack }, summaryLines:
|
|
39275
|
+
return { plan: normalized, validated, applied: { count: appliedCount, durationMs, rolledBack }, summaryLines: [...preApplyOutput, "", msg, ...footer] };
|
|
39195
39276
|
} catch (e2) {
|
|
39196
39277
|
if (e2?.name === "AbortError") {
|
|
39197
39278
|
await journalResume(opts.root, request, validated.files);
|
|
@@ -39412,6 +39493,218 @@ function parseExplicitFilenames(request) {
|
|
|
39412
39493
|
}
|
|
39413
39494
|
return out;
|
|
39414
39495
|
}
|
|
39496
|
+
function detectEditIntent(request, ctx2) {
|
|
39497
|
+
const r2 = request.toLowerCase();
|
|
39498
|
+
const editKeywords = ["modify", "edit", "update", "fix", "refactor", "change", "patch", "\u5DEE\u5206", "\u4FEE\u6B63", "\u5909\u66F4", "\u65E2\u5B58", "\u8FFD\u8A18"];
|
|
39499
|
+
const mentionsEdit = editKeywords.some((k) => r2.includes(k));
|
|
39500
|
+
return ctx2.hasAttachments || ctx2.explicitFilesCount > 0 || mentionsEdit;
|
|
39501
|
+
}
|
|
39502
|
+
function sanitizeFolderName(name2) {
|
|
39503
|
+
const base = name2.toLowerCase().replace(/[`~!@#$%^&*()+=\[\]{}|;:'",<>/?\\]/g, " ").replace(/\s+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
39504
|
+
return base || "project";
|
|
39505
|
+
}
|
|
39506
|
+
function deriveProjectFolderName(request) {
|
|
39507
|
+
const words = request.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2).slice(0, 4).join("-");
|
|
39508
|
+
return sanitizeFolderName(words || "project");
|
|
39509
|
+
}
|
|
39510
|
+
function startsWithTopFolder(p, folder) {
|
|
39511
|
+
if (!folder) return false;
|
|
39512
|
+
const seg = p.replace(/^\/+/, "").split("/")[0];
|
|
39513
|
+
return seg.toLowerCase() === folder.toLowerCase();
|
|
39514
|
+
}
|
|
39515
|
+
function prefixWithTopFolder(p, folder) {
|
|
39516
|
+
const rel = p.replace(/^\/+/, "");
|
|
39517
|
+
return `${folder}/${rel}`;
|
|
39518
|
+
}
|
|
39519
|
+
async function ensureTopFolder(root, proposed, plans) {
|
|
39520
|
+
const tops = /* @__PURE__ */ new Set();
|
|
39521
|
+
for (const p of plans) {
|
|
39522
|
+
const seg = p.path.replace(/^\/+/, "").split("/")[0] || "";
|
|
39523
|
+
if (seg) tops.add(seg);
|
|
39524
|
+
}
|
|
39525
|
+
if (tops.size === 1) {
|
|
39526
|
+
const only = Array.from(tops)[0];
|
|
39527
|
+
const unique2 = await ensureUniqueFolder(root, only);
|
|
39528
|
+
return { folderName: unique2, detectedTop: only };
|
|
39529
|
+
}
|
|
39530
|
+
const unique = await ensureUniqueFolder(root, proposed);
|
|
39531
|
+
return { folderName: unique };
|
|
39532
|
+
}
|
|
39533
|
+
async function ensureUniqueFolder(root, base) {
|
|
39534
|
+
const fs49 = await import('fs/promises');
|
|
39535
|
+
const pathMod = await import('path');
|
|
39536
|
+
let name2 = sanitizeFolderName(base);
|
|
39537
|
+
let suffix = 0;
|
|
39538
|
+
for (; suffix < Number.MAX_SAFE_INTEGER; ) {
|
|
39539
|
+
const candidate = suffix === 0 ? name2 : `${name2}-${String(suffix).padStart(2, "0")}`;
|
|
39540
|
+
try {
|
|
39541
|
+
await fs49.access(pathMod.join(root, candidate));
|
|
39542
|
+
suffix += 1;
|
|
39543
|
+
} catch {
|
|
39544
|
+
return candidate;
|
|
39545
|
+
}
|
|
39546
|
+
}
|
|
39547
|
+
throw new Error("ensureUniqueFolder: exhausted attempts to find a unique folder name");
|
|
39548
|
+
}
|
|
39549
|
+
async function buildEditContext(root, files, maxLines, maxBytes) {
|
|
39550
|
+
try {
|
|
39551
|
+
const fs49 = await import('fs/promises');
|
|
39552
|
+
const pathMod = await import('path');
|
|
39553
|
+
const sections = [];
|
|
39554
|
+
for (const rel of files) {
|
|
39555
|
+
const full = pathMod.join(root, rel);
|
|
39556
|
+
try {
|
|
39557
|
+
const buf = await fs49.readFile(full);
|
|
39558
|
+
const clipped = buf.length > maxBytes ? buf.subarray(0, maxBytes) : buf;
|
|
39559
|
+
const text = clipped.toString("utf8").replace(/\r\n/g, "\n");
|
|
39560
|
+
const lines = text.split("\n").slice(0, maxLines).join("\n");
|
|
39561
|
+
sections.push(`[BEGIN file: ${rel}]
|
|
39562
|
+
${lines}
|
|
39563
|
+
[END]`);
|
|
39564
|
+
} catch {
|
|
39565
|
+
}
|
|
39566
|
+
}
|
|
39567
|
+
if (sections.length === 0) return "";
|
|
39568
|
+
return ["// Current repository files (read-only context):", ...sections].join("\n");
|
|
39569
|
+
} catch {
|
|
39570
|
+
return "";
|
|
39571
|
+
}
|
|
39572
|
+
}
|
|
39573
|
+
async function resolveExplicitPaths(root, files, hintText) {
|
|
39574
|
+
const fs49 = await import('fs/promises');
|
|
39575
|
+
const pathMod = await import('path');
|
|
39576
|
+
const { loadGlobby: loadGlobby2 } = await Promise.resolve().then(() => (init_esm_compat(), esm_compat_exports));
|
|
39577
|
+
const globby = await loadGlobby2();
|
|
39578
|
+
const ignore = [
|
|
39579
|
+
"**/node_modules/**",
|
|
39580
|
+
"**/.git/**",
|
|
39581
|
+
"**/dist/**",
|
|
39582
|
+
"**/build/**",
|
|
39583
|
+
"**/.maria/**",
|
|
39584
|
+
"**/.next/**",
|
|
39585
|
+
"**/coverage/**"
|
|
39586
|
+
];
|
|
39587
|
+
const hintTokens = Array.from(new Set(hintText.toLowerCase().replace(/[^a-z0-9_/.-]+/g, " ").split(/\s+/).filter(Boolean)));
|
|
39588
|
+
async function findBest(rel) {
|
|
39589
|
+
const normalized = rel.replace(/^\/+/, "").replace(/\\/g, "/");
|
|
39590
|
+
const fullExact = pathMod.join(root, normalized);
|
|
39591
|
+
try {
|
|
39592
|
+
await fs49.access(fullExact);
|
|
39593
|
+
return normalized;
|
|
39594
|
+
} catch {
|
|
39595
|
+
}
|
|
39596
|
+
const lowerRel = normalized.toLowerCase();
|
|
39597
|
+
const ext2 = (pathMod.extname(normalized) || "").toLowerCase();
|
|
39598
|
+
const base = pathMod.basename(normalized);
|
|
39599
|
+
const nameNoExt = base.replace(/\.[^.]+$/, "").toLowerCase();
|
|
39600
|
+
const parentPath = pathMod.dirname(normalized);
|
|
39601
|
+
const parent = parentPath.split("/").pop() || "";
|
|
39602
|
+
const dirParts = parentPath === "." ? [] : parentPath.split("/").filter(Boolean).map((s2) => s2.toLowerCase());
|
|
39603
|
+
const patterns = [];
|
|
39604
|
+
patterns.push(`**/${normalized}`);
|
|
39605
|
+
if (parent && parent !== "." && parent !== "/") patterns.push(`**/${parent}/${base}`);
|
|
39606
|
+
if (base) patterns.push(`**/${base}`);
|
|
39607
|
+
patterns.push(`**/*${base}`);
|
|
39608
|
+
if (!ext2) {
|
|
39609
|
+
patterns.push(`**/${nameNoExt}.*`);
|
|
39610
|
+
}
|
|
39611
|
+
const uniqPatterns = Array.from(new Set(patterns));
|
|
39612
|
+
const candidatesSet = /* @__PURE__ */ new Set();
|
|
39613
|
+
for (const pat of uniqPatterns) {
|
|
39614
|
+
const found = await globby(pat, { cwd: root, absolute: false, gitignore: true, ignore });
|
|
39615
|
+
for (const f3 of found) {
|
|
39616
|
+
candidatesSet.add(f3.replace(/\\/g, "/"));
|
|
39617
|
+
}
|
|
39618
|
+
if (candidatesSet.size > 200) break;
|
|
39619
|
+
}
|
|
39620
|
+
let candidates = Array.from(candidatesSet);
|
|
39621
|
+
if (dirParts.length > 0) {
|
|
39622
|
+
const filtered = candidates.filter((relp) => {
|
|
39623
|
+
const segs = relp.toLowerCase().split("/");
|
|
39624
|
+
let pos = -1;
|
|
39625
|
+
for (const part of dirParts) {
|
|
39626
|
+
const next = segs.indexOf(part, pos + 1);
|
|
39627
|
+
if (next === -1) return false;
|
|
39628
|
+
pos = next;
|
|
39629
|
+
}
|
|
39630
|
+
return true;
|
|
39631
|
+
});
|
|
39632
|
+
if (filtered.length > 0) candidates = filtered;
|
|
39633
|
+
}
|
|
39634
|
+
if (candidates.length === 0) {
|
|
39635
|
+
const prefixes = ["", "src/", "app/", "pages/"];
|
|
39636
|
+
for (const pre of prefixes) {
|
|
39637
|
+
const cand = pathMod.join(root, pre + normalized);
|
|
39638
|
+
try {
|
|
39639
|
+
await fs49.access(cand);
|
|
39640
|
+
return (pre + normalized).replace(/^\/+/, "");
|
|
39641
|
+
} catch {
|
|
39642
|
+
}
|
|
39643
|
+
}
|
|
39644
|
+
if (dirParts.length > 0) {
|
|
39645
|
+
if (/^(src|app|pages)\//i.test(normalized)) return normalized;
|
|
39646
|
+
const pref = await pickExistingFolderPrefix(root, parentPath);
|
|
39647
|
+
const combined = (pref + normalized).replace(/^\/+/, "").replace(/^(src\/)src\//i, "$1");
|
|
39648
|
+
return combined;
|
|
39649
|
+
}
|
|
39650
|
+
return normalized.replace(/^(src\/)src\//i, "$1");
|
|
39651
|
+
}
|
|
39652
|
+
function score(relPath) {
|
|
39653
|
+
const lower2 = relPath.toLowerCase();
|
|
39654
|
+
let s2 = 0;
|
|
39655
|
+
if (lower2.endsWith(lowerRel)) s2 += 80;
|
|
39656
|
+
if (lower2.split("/").pop() === base.toLowerCase()) s2 += 40;
|
|
39657
|
+
if (ext2 && lower2.endsWith(ext2)) s2 += 10;
|
|
39658
|
+
if (lower2.startsWith("src/")) s2 += 18;
|
|
39659
|
+
if (parent && lower2.includes(`/${parent.toLowerCase()}/`)) s2 += 15;
|
|
39660
|
+
if (parentPath && lower2.endsWith(`/${parentPath.toLowerCase()}/${base.toLowerCase()}`)) s2 += 40;
|
|
39661
|
+
if (dirParts.length > 0) {
|
|
39662
|
+
for (const part of dirParts) {
|
|
39663
|
+
if (lower2.includes(`/${part}/`)) s2 += 20;
|
|
39664
|
+
else s2 -= 120;
|
|
39665
|
+
}
|
|
39666
|
+
}
|
|
39667
|
+
for (const t2 of hintTokens) {
|
|
39668
|
+
if (t2.length >= 3 && lower2.includes(`/${t2}/`)) {
|
|
39669
|
+
s2 += 2;
|
|
39670
|
+
}
|
|
39671
|
+
}
|
|
39672
|
+
s2 -= Math.min(10, Math.floor(relPath.length / 80));
|
|
39673
|
+
return s2;
|
|
39674
|
+
}
|
|
39675
|
+
let best = candidates[0];
|
|
39676
|
+
let bestScore = score(best);
|
|
39677
|
+
for (let i2 = 1; i2 < candidates.length; i2++) {
|
|
39678
|
+
const c = candidates[i2];
|
|
39679
|
+
const sc = score(c);
|
|
39680
|
+
if (sc > bestScore) {
|
|
39681
|
+
best = c;
|
|
39682
|
+
bestScore = sc;
|
|
39683
|
+
}
|
|
39684
|
+
}
|
|
39685
|
+
return best.replace(/^\/+/, "");
|
|
39686
|
+
}
|
|
39687
|
+
const out = [];
|
|
39688
|
+
for (const f3 of files) {
|
|
39689
|
+
out.push(await findBest(f3));
|
|
39690
|
+
}
|
|
39691
|
+
return out;
|
|
39692
|
+
}
|
|
39693
|
+
async function pickExistingFolderPrefix(root, parentPath) {
|
|
39694
|
+
const fs49 = await import('fs/promises');
|
|
39695
|
+
const pathMod = await import('path');
|
|
39696
|
+
const parts = parentPath.replace(/^\/+/, "").split("/").filter(Boolean);
|
|
39697
|
+
const prefixes = ["src", "app", "pages", ""];
|
|
39698
|
+
for (const pre of prefixes) {
|
|
39699
|
+
const test = pre ? pathMod.join(root, pre, ...parts) : pathMod.join(root, ...parts);
|
|
39700
|
+
try {
|
|
39701
|
+
await fs49.access(test);
|
|
39702
|
+
return pre ? `${pre}/` : "";
|
|
39703
|
+
} catch {
|
|
39704
|
+
}
|
|
39705
|
+
}
|
|
39706
|
+
return "src/";
|
|
39707
|
+
}
|
|
39415
39708
|
function scaffoldForFilename(filename, all) {
|
|
39416
39709
|
const lower2 = filename.toLowerCase();
|
|
39417
39710
|
if (lower2.endsWith(".html")) {
|
|
@@ -40625,16 +40918,6 @@ var init_loader = __esm({
|
|
|
40625
40918
|
}
|
|
40626
40919
|
});
|
|
40627
40920
|
|
|
40628
|
-
// src/utils/esm-compat.ts
|
|
40629
|
-
async function loadGlobby() {
|
|
40630
|
-
const mod = await import('globby');
|
|
40631
|
-
return mod?.globby ?? mod?.default ?? mod;
|
|
40632
|
-
}
|
|
40633
|
-
var init_esm_compat = __esm({
|
|
40634
|
-
"src/utils/esm-compat.ts"() {
|
|
40635
|
-
}
|
|
40636
|
-
});
|
|
40637
|
-
|
|
40638
40921
|
// src/services/init/scanner.ts
|
|
40639
40922
|
var scanner_exports = {};
|
|
40640
40923
|
__export(scanner_exports, {
|