usemint-cli 0.2.0-beta.1 → 0.2.0-beta.2
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 +66 -54
- package/dist/cli/index.js +562 -118
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -44,7 +44,7 @@ function getConfigPath() {
|
|
|
44
44
|
function getGatewayUrl() {
|
|
45
45
|
return conf.get("apiBaseUrl") ?? "https://api.usemint.dev";
|
|
46
46
|
}
|
|
47
|
-
var configSchema, conf,
|
|
47
|
+
var configSchema, conf, config2;
|
|
48
48
|
var init_config = __esm({
|
|
49
49
|
"src/utils/config.ts"() {
|
|
50
50
|
"use strict";
|
|
@@ -97,7 +97,7 @@ var init_config = __esm({
|
|
|
97
97
|
apiBaseUrl: { type: "string", default: "https://api.usemint.dev" }
|
|
98
98
|
}
|
|
99
99
|
});
|
|
100
|
-
|
|
100
|
+
config2 = {
|
|
101
101
|
get,
|
|
102
102
|
set,
|
|
103
103
|
setAll,
|
|
@@ -547,7 +547,7 @@ var init_anthropic = __esm({
|
|
|
547
547
|
client = null;
|
|
548
548
|
getClient() {
|
|
549
549
|
if (this.client) return this.client;
|
|
550
|
-
const apiKey =
|
|
550
|
+
const apiKey = config2.get("providers")?.anthropic;
|
|
551
551
|
if (!apiKey) {
|
|
552
552
|
throw new Error("Anthropic API key not configured. Run: axon config:set providers.anthropic <key>");
|
|
553
553
|
}
|
|
@@ -709,7 +709,7 @@ var init_deepseek = __esm({
|
|
|
709
709
|
client = null;
|
|
710
710
|
getClient() {
|
|
711
711
|
if (this.client) return this.client;
|
|
712
|
-
const apiKey =
|
|
712
|
+
const apiKey = config2.get("providers")?.deepseek;
|
|
713
713
|
if (!apiKey) {
|
|
714
714
|
throw new Error("DeepSeek API key not configured. Run: axon config:set providers.deepseek <key>");
|
|
715
715
|
}
|
|
@@ -981,7 +981,7 @@ var init_openai_compatible = __esm({
|
|
|
981
981
|
getClient() {
|
|
982
982
|
if (this.client) return this.client;
|
|
983
983
|
const [section, key] = this.cfg.apiKeyConfigPath.split(".");
|
|
984
|
-
const sectionData =
|
|
984
|
+
const sectionData = config2.get(section);
|
|
985
985
|
const apiKey = sectionData?.[key];
|
|
986
986
|
if (!apiKey) {
|
|
987
987
|
throw new Error(
|
|
@@ -1209,7 +1209,7 @@ var init_gemini = __esm({
|
|
|
1209
1209
|
sdk = null;
|
|
1210
1210
|
getSDK() {
|
|
1211
1211
|
if (this.sdk) return this.sdk;
|
|
1212
|
-
const sectionData =
|
|
1212
|
+
const sectionData = config2.get("providers");
|
|
1213
1213
|
const apiKey = sectionData?.["gemini"];
|
|
1214
1214
|
if (!apiKey) throw new Error("Gemini API key not configured. Run: axon config:set providers.gemini <key>");
|
|
1215
1215
|
this.sdk = new GoogleGenerativeAI(apiKey);
|
|
@@ -1307,12 +1307,12 @@ var init_gemini = __esm({
|
|
|
1307
1307
|
|
|
1308
1308
|
// src/providers/gateway.ts
|
|
1309
1309
|
function getGatewayUrl2() {
|
|
1310
|
-
return process.env.MINT_GATEWAY_URL ??
|
|
1310
|
+
return process.env.MINT_GATEWAY_URL ?? config2.getGatewayUrl();
|
|
1311
1311
|
}
|
|
1312
1312
|
function getToken() {
|
|
1313
|
-
const gatewayToken =
|
|
1313
|
+
const gatewayToken = config2.get("gatewayToken");
|
|
1314
1314
|
if (gatewayToken) return gatewayToken;
|
|
1315
|
-
const userToken =
|
|
1315
|
+
const userToken = config2.get("apiKey");
|
|
1316
1316
|
if (userToken) return userToken;
|
|
1317
1317
|
const envToken = process.env.MINT_GATEWAY_TOKEN ?? process.env.MINT_API_TOKEN ?? "";
|
|
1318
1318
|
if (envToken) return envToken;
|
|
@@ -1639,7 +1639,7 @@ function getProvider(modelId) {
|
|
|
1639
1639
|
}
|
|
1640
1640
|
function hasProviderKey(providerId) {
|
|
1641
1641
|
try {
|
|
1642
|
-
const providerKeys =
|
|
1642
|
+
const providerKeys = config2.get("providers");
|
|
1643
1643
|
return !!providerKeys?.[providerId];
|
|
1644
1644
|
} catch {
|
|
1645
1645
|
return false;
|
|
@@ -4334,10 +4334,10 @@ var init_SlashAutocomplete = __esm({
|
|
|
4334
4334
|
SLASH_COMMANDS = [
|
|
4335
4335
|
{ name: "help", description: "show commands + keyboard shortcuts" },
|
|
4336
4336
|
{ name: "clear", description: "clear chat history" },
|
|
4337
|
-
{ name: "model", description: "show
|
|
4338
|
-
{ name: "
|
|
4339
|
-
{ name: "
|
|
4340
|
-
{ name: "usage", description: "session stats +
|
|
4337
|
+
{ name: "model", description: "show current model" },
|
|
4338
|
+
{ name: "auto", description: "toggle auto mode (skip approvals)" },
|
|
4339
|
+
{ name: "yolo", description: "toggle yolo mode (full autonomy)" },
|
|
4340
|
+
{ name: "usage", description: "session stats + savings" }
|
|
4341
4341
|
];
|
|
4342
4342
|
}
|
|
4343
4343
|
});
|
|
@@ -7663,13 +7663,13 @@ async function executeTool2(toolName, input, toolCallId, options) {
|
|
|
7663
7663
|
async function generateDiffPreview(toolName, input, cwd) {
|
|
7664
7664
|
const { createTwoFilesPatch: createTwoFilesPatch2 } = await import("diff");
|
|
7665
7665
|
const { readFile: readFile10 } = await import("fs/promises");
|
|
7666
|
-
const { join:
|
|
7666
|
+
const { join: join21 } = await import("path");
|
|
7667
7667
|
if (toolName === "write_file") {
|
|
7668
7668
|
const path = String(input.path ?? "");
|
|
7669
7669
|
const newContent = String(input.content ?? "");
|
|
7670
7670
|
let oldContent = "";
|
|
7671
7671
|
try {
|
|
7672
|
-
oldContent = await readFile10(
|
|
7672
|
+
oldContent = await readFile10(join21(cwd, path), "utf-8");
|
|
7673
7673
|
} catch {
|
|
7674
7674
|
}
|
|
7675
7675
|
return createTwoFilesPatch2(path, path, oldContent, newContent, "old", "new");
|
|
@@ -7679,7 +7679,7 @@ async function generateDiffPreview(toolName, input, cwd) {
|
|
|
7679
7679
|
const oldStr = String(input.old_text ?? "");
|
|
7680
7680
|
const newStr = String(input.new_text ?? "");
|
|
7681
7681
|
try {
|
|
7682
|
-
const current = await readFile10(
|
|
7682
|
+
const current = await readFile10(join21(cwd, path), "utf-8");
|
|
7683
7683
|
const firstMatch = current.indexOf(oldStr);
|
|
7684
7684
|
const secondMatch = firstMatch === -1 ? -1 : current.indexOf(oldStr, firstMatch + oldStr.length);
|
|
7685
7685
|
if (firstMatch !== -1 && secondMatch === -1) {
|
|
@@ -7692,7 +7692,7 @@ async function generateDiffPreview(toolName, input, cwd) {
|
|
|
7692
7692
|
}
|
|
7693
7693
|
if (toolName === "search_replace") {
|
|
7694
7694
|
const path = String(input.path ?? "");
|
|
7695
|
-
const current = await readFile10(
|
|
7695
|
+
const current = await readFile10(join21(cwd, path), "utf-8");
|
|
7696
7696
|
const { buildSearchReplacePlan: buildSearchReplacePlan2, buildSearchReplacePreview: buildSearchReplacePreview2 } = await Promise.resolve().then(() => (init_search_replace(), search_replace_exports));
|
|
7697
7697
|
const plan = buildSearchReplacePlan2(current, {
|
|
7698
7698
|
path,
|
|
@@ -10994,39 +10994,210 @@ var init_pipeline = __esm({
|
|
|
10994
10994
|
});
|
|
10995
10995
|
|
|
10996
10996
|
// src/orchestrator/prompts.ts
|
|
10997
|
-
var ORCHESTRATOR_PROMPT;
|
|
10997
|
+
var ORCHESTRATOR_PROMPT, MEMORY_INSTRUCTION;
|
|
10998
10998
|
var init_prompts = __esm({
|
|
10999
10999
|
"src/orchestrator/prompts.ts"() {
|
|
11000
11000
|
"use strict";
|
|
11001
|
-
ORCHESTRATOR_PROMPT = `You are Mint CLI,
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
-
|
|
11007
|
-
-
|
|
11008
|
-
-
|
|
11009
|
-
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11001
|
+
ORCHESTRATOR_PROMPT = `You are Mint CLI, an AI coding assistant running in a terminal. You help developers fix bugs, add features, refactor code, and answer questions about codebases.
|
|
11002
|
+
|
|
11003
|
+
# Tools
|
|
11004
|
+
|
|
11005
|
+
## Search & Read (free, no LLM cost)
|
|
11006
|
+
- **search_files**: Find relevant files by keywords. Use this first to locate files related to the task.
|
|
11007
|
+
- **read_file**: Read a file's contents. Large files are truncated at 200 lines \u2014 use grep_file for specifics. You MUST read a file before editing it.
|
|
11008
|
+
- **grep_file**: Search inside a file for specific text. Returns matching lines with line numbers and 2 lines of context. Use this for large files or to find exact text before edit_file.
|
|
11009
|
+
- **list_files**: List directory contents. Ignores node_modules and hidden files.
|
|
11010
|
+
|
|
11011
|
+
## Edit & Write (requires user approval)
|
|
11012
|
+
- **edit_file**: Replace exact text in a file. The old_text must match EXACTLY including whitespace and indentation. If it fails, use grep_file to get the precise text, then retry. Prefer this over write_file for existing files.
|
|
11013
|
+
- **write_file**: Create a new file or overwrite entirely. Use for new files only \u2014 prefer edit_file for changes to existing files.
|
|
11014
|
+
- **write_code**: Dispatch a coding task to a fast coding model. Provide a precise task description + relevant file contents. Returns generated code. Use for complex multi-file changes or large code generation. YOU do the planning \u2014 write_code does the typing.
|
|
11015
|
+
|
|
11016
|
+
## Verify & Execute (free, no LLM cost)
|
|
11017
|
+
- **run_command**: Execute a shell command with 30s timeout. Use for build, lint, curl, etc. NEVER run destructive commands (rm -rf, sudo, chmod 777, kill, shutdown).
|
|
11018
|
+
- **run_tests**: Detect and run the project's test suite. Checks package.json for test script.
|
|
11019
|
+
- **git_diff**: Show all uncommitted changes (status + staged + unstaged diffs).
|
|
11020
|
+
- **git_commit**: Stage all changes and commit with a message.
|
|
11021
|
+
- **undo**: Revert the last edit to a specific file. Only the most recent change per file can be undone.
|
|
11022
|
+
|
|
11023
|
+
# How to work
|
|
11024
|
+
|
|
11025
|
+
## Questions vs changes
|
|
11026
|
+
- If the user asks a QUESTION (can you see, what does, how does, show me, explain, suggest, review) \u2014 read the relevant files and ANSWER. Do NOT edit anything.
|
|
11027
|
+
- Only edit files when the user explicitly asks for a change (fix, add, change, update, create, remove, rename, build).
|
|
11028
|
+
|
|
11029
|
+
## Before editing
|
|
11030
|
+
- Always read before writing. Never assume file contents.
|
|
11031
|
+
- For large files (truncated at 200 lines): use grep_file to find the exact line, then edit_file with the exact text from grep_file output.
|
|
11032
|
+
- For edit_file: copy the EXACT text from the file as shown by read_file or grep_file. Whitespace and indentation matter. If it fails, the text didn't match \u2014 use grep_file to get the real content.
|
|
11033
|
+
|
|
11034
|
+
## Making changes
|
|
11035
|
+
- Keep changes minimal and focused on the task. A bug fix doesn't need surrounding code cleaned up. A simple feature doesn't need extra configurability.
|
|
11036
|
+
- Don't add features, refactor code, or make "improvements" beyond what was asked.
|
|
11037
|
+
- Don't add error handling, fallbacks, or validation for scenarios that can't happen. Only validate at system boundaries (user input, external APIs).
|
|
11038
|
+
- Don't add comments, docstrings, or type annotations to code you didn't change.
|
|
11039
|
+
- Don't create helpers or abstractions for one-time operations. Three similar lines is better than a premature abstraction.
|
|
11040
|
+
- Match existing code patterns \u2014 read 2-3 nearby files first to understand naming, imports, error handling, and style.
|
|
11041
|
+
|
|
11042
|
+
## For complex changes
|
|
11043
|
+
- Use write_code for multi-file features or large code generation. Pass only the relevant files (max 4-8).
|
|
11044
|
+
- write_code dispatches to a fast coding model \u2014 YOU do the planning and thinking, write_code does the typing.
|
|
11045
|
+
|
|
11046
|
+
## Verification after changes
|
|
11047
|
+
After making changes, verify your work:
|
|
11048
|
+
1. Run the build if the project has one. A broken build means the work isn't done \u2014 fix it.
|
|
11049
|
+
2. Run tests if available. Failing tests mean the work isn't done \u2014 fix them.
|
|
11050
|
+
3. If the change is an API endpoint: use run_command to curl it and verify the response.
|
|
11051
|
+
4. If the change is frontend: check that the modified HTML/CSS is valid and references exist.
|
|
11052
|
+
Don't just read the code and say "looks correct" \u2014 actually run it and check.
|
|
11053
|
+
|
|
11054
|
+
## When things fail
|
|
11055
|
+
- If an approach fails, diagnose why before switching tactics \u2014 read the error, check your assumptions, try a focused fix.
|
|
11056
|
+
- Don't retry the identical action blindly, but don't abandon a viable approach after a single failure either.
|
|
11057
|
+
- If edit_file can't match the text, use grep_file to find the exact content, then retry with the precise text.
|
|
11058
|
+
- If the build fails after your change, read the error, fix it, and re-run. Repeat until it passes.
|
|
11019
11059
|
|
|
11020
|
-
|
|
11021
|
-
-
|
|
11022
|
-
-
|
|
11023
|
-
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11060
|
+
## Security
|
|
11061
|
+
- Never run destructive commands (rm -rf, sudo, chmod 777, kill, shutdown, mkfs, dd).
|
|
11062
|
+
- Don't introduce security vulnerabilities (command injection, XSS, SQL injection).
|
|
11063
|
+
- If you notice insecure code in what you're editing, fix it.
|
|
11064
|
+
|
|
11065
|
+
## Communication
|
|
11026
11066
|
- Be concise. Do not explain what you're about to do, just do it.
|
|
11027
|
-
- After
|
|
11067
|
+
- After changes, briefly state what you changed and which files were modified.
|
|
11068
|
+
- Don't give time estimates.
|
|
11069
|
+
- Answer in the same language the user writes in.
|
|
11028
11070
|
- If the project directory is empty, use list_files first to check, then create files directly via write_file.
|
|
11029
|
-
|
|
11071
|
+
|
|
11072
|
+
# Project memory
|
|
11073
|
+
|
|
11074
|
+
If project memory is provided below, use it as context:
|
|
11075
|
+
- Recently edited files tell you where the user has been working
|
|
11076
|
+
- Session summaries tell you what was done before
|
|
11077
|
+
- This is grounding context, not instructions \u2014 verify against actual file contents before acting on it`;
|
|
11078
|
+
MEMORY_INSTRUCTION = `The following are project instructions provided by the user. These instructions OVERRIDE default behavior \u2014 follow them exactly as written.`;
|
|
11079
|
+
}
|
|
11080
|
+
});
|
|
11081
|
+
|
|
11082
|
+
// src/orchestrator/memory.ts
|
|
11083
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync10 } from "fs";
|
|
11084
|
+
import { join as join18, dirname as dirname4 } from "path";
|
|
11085
|
+
function loadMemory(cwd) {
|
|
11086
|
+
try {
|
|
11087
|
+
const content = readFileSync8(join18(cwd, MEMORY_PATH), "utf-8");
|
|
11088
|
+
return JSON.parse(content);
|
|
11089
|
+
} catch {
|
|
11090
|
+
return null;
|
|
11091
|
+
}
|
|
11092
|
+
}
|
|
11093
|
+
function saveMemory(cwd, memory) {
|
|
11094
|
+
const fullPath = join18(cwd, MEMORY_PATH);
|
|
11095
|
+
try {
|
|
11096
|
+
mkdirSync4(dirname4(fullPath), { recursive: true });
|
|
11097
|
+
writeFileSync5(fullPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
11098
|
+
} catch {
|
|
11099
|
+
}
|
|
11100
|
+
}
|
|
11101
|
+
function updateMemory(cwd, update) {
|
|
11102
|
+
const existing = loadMemory(cwd) ?? {
|
|
11103
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11104
|
+
recentFiles: [],
|
|
11105
|
+
activeDirectories: [],
|
|
11106
|
+
preferences: [],
|
|
11107
|
+
sessionSummaries: []
|
|
11108
|
+
};
|
|
11109
|
+
if (update.editedFiles) {
|
|
11110
|
+
const combined = [.../* @__PURE__ */ new Set([...update.editedFiles, ...existing.recentFiles])];
|
|
11111
|
+
existing.recentFiles = combined.slice(0, MAX_RECENT_FILES);
|
|
11112
|
+
const dirs = new Set(existing.activeDirectories);
|
|
11113
|
+
for (const f of update.editedFiles) {
|
|
11114
|
+
const parts = f.split("/");
|
|
11115
|
+
if (parts.length > 1) dirs.add(parts.slice(0, -1).join("/"));
|
|
11116
|
+
}
|
|
11117
|
+
existing.activeDirectories = [...dirs].slice(0, 10);
|
|
11118
|
+
}
|
|
11119
|
+
if (update.sessionSummary) {
|
|
11120
|
+
existing.sessionSummaries = [
|
|
11121
|
+
update.sessionSummary,
|
|
11122
|
+
...existing.sessionSummaries
|
|
11123
|
+
].slice(0, MAX_SUMMARIES);
|
|
11124
|
+
}
|
|
11125
|
+
if (update.projectDescription) existing.projectDescription = update.projectDescription;
|
|
11126
|
+
if (update.language) existing.language = update.language;
|
|
11127
|
+
existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11128
|
+
saveMemory(cwd, existing);
|
|
11129
|
+
}
|
|
11130
|
+
function formatMemoryForPrompt(memory) {
|
|
11131
|
+
const parts = [];
|
|
11132
|
+
if (memory.projectDescription) {
|
|
11133
|
+
parts.push(`Project: ${memory.projectDescription}`);
|
|
11134
|
+
}
|
|
11135
|
+
if (memory.language) {
|
|
11136
|
+
parts.push(`Language: ${memory.language}`);
|
|
11137
|
+
}
|
|
11138
|
+
if (memory.recentFiles.length > 0) {
|
|
11139
|
+
parts.push(`Recently edited files: ${memory.recentFiles.slice(0, 10).join(", ")}`);
|
|
11140
|
+
}
|
|
11141
|
+
if (memory.activeDirectories.length > 0) {
|
|
11142
|
+
parts.push(`Active directories: ${memory.activeDirectories.join(", ")}`);
|
|
11143
|
+
}
|
|
11144
|
+
if (memory.sessionSummaries.length > 0) {
|
|
11145
|
+
parts.push(`Recent session: ${memory.sessionSummaries[0]}`);
|
|
11146
|
+
}
|
|
11147
|
+
return parts.length > 0 ? `
|
|
11148
|
+
<project_memory>
|
|
11149
|
+
${parts.join("\n")}
|
|
11150
|
+
</project_memory>` : "";
|
|
11151
|
+
}
|
|
11152
|
+
function loadProjectInstructions(cwd) {
|
|
11153
|
+
const candidates = [
|
|
11154
|
+
"MINT.md",
|
|
11155
|
+
".mint/MINT.md",
|
|
11156
|
+
"CLAUDE.md",
|
|
11157
|
+
".claude/CLAUDE.md"
|
|
11158
|
+
];
|
|
11159
|
+
const parts = [];
|
|
11160
|
+
for (const candidate of candidates) {
|
|
11161
|
+
const fullPath = join18(cwd, candidate);
|
|
11162
|
+
if (existsSync10(fullPath)) {
|
|
11163
|
+
try {
|
|
11164
|
+
const content = readFileSync8(fullPath, "utf-8").trim();
|
|
11165
|
+
if (content.length > 0 && content.length < 4e4) {
|
|
11166
|
+
parts.push(`# ${candidate}
|
|
11167
|
+
${content}`);
|
|
11168
|
+
}
|
|
11169
|
+
} catch {
|
|
11170
|
+
}
|
|
11171
|
+
}
|
|
11172
|
+
}
|
|
11173
|
+
const rulesDir = join18(cwd, ".mint", "rules");
|
|
11174
|
+
if (existsSync10(rulesDir)) {
|
|
11175
|
+
try {
|
|
11176
|
+
const { readdirSync: readdirSync4 } = __require("fs");
|
|
11177
|
+
const files = readdirSync4(rulesDir);
|
|
11178
|
+
for (const file of files) {
|
|
11179
|
+
if (!file.endsWith(".md")) continue;
|
|
11180
|
+
try {
|
|
11181
|
+
const content = readFileSync8(join18(rulesDir, file), "utf-8").trim();
|
|
11182
|
+
if (content.length > 0 && content.length < 1e4) {
|
|
11183
|
+
parts.push(`# .mint/rules/${file}
|
|
11184
|
+
${content}`);
|
|
11185
|
+
}
|
|
11186
|
+
} catch {
|
|
11187
|
+
}
|
|
11188
|
+
}
|
|
11189
|
+
} catch {
|
|
11190
|
+
}
|
|
11191
|
+
}
|
|
11192
|
+
return parts.length > 0 ? parts.join("\n\n") : null;
|
|
11193
|
+
}
|
|
11194
|
+
var MEMORY_PATH, MAX_RECENT_FILES, MAX_SUMMARIES;
|
|
11195
|
+
var init_memory = __esm({
|
|
11196
|
+
"src/orchestrator/memory.ts"() {
|
|
11197
|
+
"use strict";
|
|
11198
|
+
MEMORY_PATH = ".mint/memory.json";
|
|
11199
|
+
MAX_RECENT_FILES = 20;
|
|
11200
|
+
MAX_SUMMARIES = 10;
|
|
11030
11201
|
}
|
|
11031
11202
|
});
|
|
11032
11203
|
|
|
@@ -11109,15 +11280,24 @@ Include 3 context lines around each change. One diff block per file.`;
|
|
|
11109
11280
|
});
|
|
11110
11281
|
|
|
11111
11282
|
// src/orchestrator/tools.ts
|
|
11112
|
-
import { readFileSync as
|
|
11283
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, readdirSync as readdirSync3, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
|
|
11113
11284
|
import { execSync } from "child_process";
|
|
11114
|
-
import { join as
|
|
11285
|
+
import { join as join19, dirname as dirname5 } from "path";
|
|
11115
11286
|
function getWriteCodeCost() {
|
|
11116
11287
|
return sessionWriteCodeCost;
|
|
11117
11288
|
}
|
|
11118
11289
|
function resetWriteCodeCost() {
|
|
11119
11290
|
sessionWriteCodeCost = 0;
|
|
11120
11291
|
}
|
|
11292
|
+
function isToolSafe(toolName, input) {
|
|
11293
|
+
if (SAFE_TOOLS.has(toolName)) return true;
|
|
11294
|
+
if (toolName === "run_command") {
|
|
11295
|
+
const cmd = String(input.command ?? "").trim().toLowerCase();
|
|
11296
|
+
const readOnlyPrefixes = ["git status", "git log", "git diff", "ls", "cat ", "head ", "tail ", "npm run build", "npm test", "npx tsc", "curl ", "echo ", "pwd", "which ", "node -e", "wc "];
|
|
11297
|
+
return readOnlyPrefixes.some((prefix) => cmd.startsWith(prefix));
|
|
11298
|
+
}
|
|
11299
|
+
return false;
|
|
11300
|
+
}
|
|
11121
11301
|
async function executeOrchestratorTool(toolName, input, ctx) {
|
|
11122
11302
|
switch (toolName) {
|
|
11123
11303
|
case "search_files":
|
|
@@ -11147,6 +11327,14 @@ async function executeOrchestratorTool(toolName, input, ctx) {
|
|
|
11147
11327
|
return toolWriteFile(String(input.path ?? ""), String(input.content ?? ""), ctx);
|
|
11148
11328
|
case "run_command":
|
|
11149
11329
|
return toolRunCommand(String(input.command ?? ""), ctx);
|
|
11330
|
+
case "git_diff":
|
|
11331
|
+
return toolGitDiff(ctx);
|
|
11332
|
+
case "git_commit":
|
|
11333
|
+
return toolGitCommit(String(input.message ?? ""), ctx);
|
|
11334
|
+
case "run_tests":
|
|
11335
|
+
return toolRunTests(ctx);
|
|
11336
|
+
case "undo":
|
|
11337
|
+
return toolUndo(String(input.path ?? ""), ctx);
|
|
11150
11338
|
default:
|
|
11151
11339
|
return `Unknown tool: ${toolName}`;
|
|
11152
11340
|
}
|
|
@@ -11172,10 +11360,10 @@ async function toolSearchFiles(query, ctx) {
|
|
|
11172
11360
|
}
|
|
11173
11361
|
function toolReadFile(filePath, ctx) {
|
|
11174
11362
|
ctx.onLog?.(`reading ${filePath}`);
|
|
11175
|
-
const fullPath =
|
|
11363
|
+
const fullPath = join19(ctx.cwd, filePath);
|
|
11176
11364
|
if (!fullPath.startsWith(ctx.cwd)) return "Error: path outside project directory";
|
|
11177
11365
|
try {
|
|
11178
|
-
const content =
|
|
11366
|
+
const content = readFileSync9(fullPath, "utf-8");
|
|
11179
11367
|
if (content.length > 32e3) {
|
|
11180
11368
|
const lines = content.split("\n");
|
|
11181
11369
|
const preview = lines.slice(0, 200).map((l, i) => `${i + 1}: ${l}`).join("\n");
|
|
@@ -11190,10 +11378,10 @@ function toolReadFile(filePath, ctx) {
|
|
|
11190
11378
|
}
|
|
11191
11379
|
function toolGrepFile(filePath, pattern, ctx) {
|
|
11192
11380
|
ctx.onLog?.(`grep ${filePath}: ${pattern}`);
|
|
11193
|
-
const fullPath =
|
|
11381
|
+
const fullPath = join19(ctx.cwd, filePath);
|
|
11194
11382
|
if (!fullPath.startsWith(ctx.cwd)) return "Error: path outside project directory";
|
|
11195
11383
|
try {
|
|
11196
|
-
const content =
|
|
11384
|
+
const content = readFileSync9(fullPath, "utf-8");
|
|
11197
11385
|
const lines = content.split("\n");
|
|
11198
11386
|
const matches = [];
|
|
11199
11387
|
const patternLower = pattern.toLowerCase();
|
|
@@ -11215,7 +11403,7 @@ function toolGrepFile(filePath, pattern, ctx) {
|
|
|
11215
11403
|
}
|
|
11216
11404
|
function toolListFiles(dirPath, ctx) {
|
|
11217
11405
|
ctx.onLog?.(`listing ${dirPath}`);
|
|
11218
|
-
const fullPath =
|
|
11406
|
+
const fullPath = join19(ctx.cwd, dirPath);
|
|
11219
11407
|
if (!fullPath.startsWith(ctx.cwd) && fullPath !== ctx.cwd) return "Error: path outside project directory";
|
|
11220
11408
|
try {
|
|
11221
11409
|
const entries = readdirSync3(fullPath, { withFileTypes: true });
|
|
@@ -11233,7 +11421,7 @@ async function toolWriteCode(task, files, ctx) {
|
|
|
11233
11421
|
resolvedFiles[path] = content;
|
|
11234
11422
|
} else {
|
|
11235
11423
|
try {
|
|
11236
|
-
resolvedFiles[path] =
|
|
11424
|
+
resolvedFiles[path] = readFileSync9(join19(ctx.cwd, path), "utf-8");
|
|
11237
11425
|
} catch {
|
|
11238
11426
|
resolvedFiles[path] = "(file does not exist \u2014 create it)";
|
|
11239
11427
|
}
|
|
@@ -11257,17 +11445,18 @@ async function toolEditFile(filePath, oldText, newText, ctx) {
|
|
|
11257
11445
|
const approved = await ctx.onApprovalNeeded(preview);
|
|
11258
11446
|
if (!approved) return "User rejected this edit.";
|
|
11259
11447
|
}
|
|
11260
|
-
const fullPath =
|
|
11448
|
+
const fullPath = join19(ctx.cwd, filePath);
|
|
11261
11449
|
if (!fullPath.startsWith(ctx.cwd)) return "Error: path outside project directory";
|
|
11262
11450
|
try {
|
|
11263
|
-
const content =
|
|
11451
|
+
const content = readFileSync9(fullPath, "utf-8");
|
|
11264
11452
|
if (content.includes(oldText)) {
|
|
11265
11453
|
const count = content.split(oldText).length - 1;
|
|
11266
11454
|
if (count > 1) {
|
|
11267
11455
|
return `Error: old_text matches ${count} locations in ${filePath}. Make it more specific by including more surrounding context.`;
|
|
11268
11456
|
}
|
|
11457
|
+
undoBackups.set(filePath, content);
|
|
11269
11458
|
const updated = content.replace(oldText, newText);
|
|
11270
|
-
|
|
11459
|
+
writeFileSync6(fullPath, updated, "utf-8");
|
|
11271
11460
|
return `Edited ${filePath}: replaced ${oldText.length} chars with ${newText.length} chars.`;
|
|
11272
11461
|
}
|
|
11273
11462
|
const normalize = (s) => s.replace(/\s+/g, " ").trim();
|
|
@@ -11281,7 +11470,7 @@ async function toolEditFile(filePath, oldText, newText, ctx) {
|
|
|
11281
11470
|
newText
|
|
11282
11471
|
));
|
|
11283
11472
|
if (updated !== content) {
|
|
11284
|
-
|
|
11473
|
+
writeFileSync6(fullPath, updated, "utf-8");
|
|
11285
11474
|
return `Edited ${filePath} (fuzzy match on line ${i + 1}): replaced text.`;
|
|
11286
11475
|
}
|
|
11287
11476
|
}
|
|
@@ -11289,7 +11478,7 @@ async function toolEditFile(filePath, oldText, newText, ctx) {
|
|
|
11289
11478
|
const window = lines.slice(i, i + windowSize).join("\n");
|
|
11290
11479
|
if (normalize(window).includes(normalizedOld)) {
|
|
11291
11480
|
const replacement = lines.slice(0, i).join("\n") + "\n" + newText + "\n" + lines.slice(i + windowSize).join("\n");
|
|
11292
|
-
|
|
11481
|
+
writeFileSync6(fullPath, replacement, "utf-8");
|
|
11293
11482
|
return `Edited ${filePath} (fuzzy match lines ${i + 1}-${i + windowSize}): replaced text.`;
|
|
11294
11483
|
}
|
|
11295
11484
|
}
|
|
@@ -11303,6 +11492,75 @@ Tip: use read_file to see the exact content, then copy-paste the exact text you
|
|
|
11303
11492
|
return `Error editing ${filePath}: ${err instanceof Error ? err.message : String(err)}`;
|
|
11304
11493
|
}
|
|
11305
11494
|
}
|
|
11495
|
+
function toolGitDiff(ctx) {
|
|
11496
|
+
ctx.onLog?.("git diff");
|
|
11497
|
+
try {
|
|
11498
|
+
const diff = execSync("git diff", { cwd: ctx.cwd, encoding: "utf-8", timeout: 1e4 });
|
|
11499
|
+
const staged = execSync("git diff --cached", { cwd: ctx.cwd, encoding: "utf-8", timeout: 1e4 });
|
|
11500
|
+
const status = execSync("git status --short", { cwd: ctx.cwd, encoding: "utf-8", timeout: 1e4 });
|
|
11501
|
+
const parts = [
|
|
11502
|
+
status.trim() ? `Status:
|
|
11503
|
+
${status.trim()}` : "No changes.",
|
|
11504
|
+
diff.trim() ? `
|
|
11505
|
+
Unstaged changes:
|
|
11506
|
+
${diff.trim().slice(0, MAX_OUTPUT4)}` : "",
|
|
11507
|
+
staged.trim() ? `
|
|
11508
|
+
Staged changes:
|
|
11509
|
+
${staged.trim().slice(0, MAX_OUTPUT4)}` : ""
|
|
11510
|
+
].filter(Boolean);
|
|
11511
|
+
return parts.join("\n") || "Working tree clean.";
|
|
11512
|
+
} catch (err) {
|
|
11513
|
+
return `Git error: ${err instanceof Error ? err.message : String(err)}`;
|
|
11514
|
+
}
|
|
11515
|
+
}
|
|
11516
|
+
function toolGitCommit(message, ctx) {
|
|
11517
|
+
ctx.onLog?.(`git commit: ${message.slice(0, 40)}`);
|
|
11518
|
+
try {
|
|
11519
|
+
execSync("git add -A", { cwd: ctx.cwd, timeout: 1e4 });
|
|
11520
|
+
const result = execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, {
|
|
11521
|
+
cwd: ctx.cwd,
|
|
11522
|
+
encoding: "utf-8",
|
|
11523
|
+
timeout: 1e4
|
|
11524
|
+
});
|
|
11525
|
+
return result.trim() || "Committed.";
|
|
11526
|
+
} catch (err) {
|
|
11527
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11528
|
+
if (msg.includes("nothing to commit")) return "Nothing to commit \u2014 working tree clean.";
|
|
11529
|
+
return `Git commit error: ${msg}`;
|
|
11530
|
+
}
|
|
11531
|
+
}
|
|
11532
|
+
function toolRunTests(ctx) {
|
|
11533
|
+
ctx.onLog?.("running tests");
|
|
11534
|
+
try {
|
|
11535
|
+
const pkgPath = join19(ctx.cwd, "package.json");
|
|
11536
|
+
if (existsSync11(pkgPath)) {
|
|
11537
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
11538
|
+
const testScript = pkg.scripts?.test;
|
|
11539
|
+
if (testScript && testScript !== 'echo "Error: no test specified" && exit 1') {
|
|
11540
|
+
const output = execSync("npm test", { cwd: ctx.cwd, encoding: "utf-8", timeout: 6e4, maxBuffer: 1024 * 1024 });
|
|
11541
|
+
return output.length > MAX_OUTPUT4 ? output.slice(0, MAX_OUTPUT4) + "\n... (truncated)" : output;
|
|
11542
|
+
}
|
|
11543
|
+
}
|
|
11544
|
+
return "No test script found in package.json.";
|
|
11545
|
+
} catch (err) {
|
|
11546
|
+
const execErr = err;
|
|
11547
|
+
const out = [execErr.stdout, execErr.stderr].filter(Boolean).join("\n");
|
|
11548
|
+
return out.length > MAX_OUTPUT4 ? out.slice(0, MAX_OUTPUT4) + "\n... (truncated)" : out || "Tests failed.";
|
|
11549
|
+
}
|
|
11550
|
+
}
|
|
11551
|
+
function toolUndo(filePath, ctx) {
|
|
11552
|
+
ctx.onLog?.(`undo ${filePath}`);
|
|
11553
|
+
const backup = undoBackups.get(filePath);
|
|
11554
|
+
if (!backup) return `No undo history for ${filePath}. Only the most recent edit can be undone.`;
|
|
11555
|
+
const fullPath = join19(ctx.cwd, filePath);
|
|
11556
|
+
try {
|
|
11557
|
+
writeFileSync6(fullPath, backup, "utf-8");
|
|
11558
|
+
undoBackups.delete(filePath);
|
|
11559
|
+
return `Reverted ${filePath} to previous state.`;
|
|
11560
|
+
} catch (err) {
|
|
11561
|
+
return `Undo error: ${err instanceof Error ? err.message : String(err)}`;
|
|
11562
|
+
}
|
|
11563
|
+
}
|
|
11306
11564
|
function escapeRegex(s) {
|
|
11307
11565
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11308
11566
|
}
|
|
@@ -11314,11 +11572,15 @@ async function toolWriteFile(filePath, content, ctx) {
|
|
|
11314
11572
|
const approved = await ctx.onApprovalNeeded(preview);
|
|
11315
11573
|
if (!approved) return "User rejected this file creation.";
|
|
11316
11574
|
}
|
|
11317
|
-
const fullPath =
|
|
11575
|
+
const fullPath = join19(ctx.cwd, filePath);
|
|
11318
11576
|
if (!fullPath.startsWith(ctx.cwd)) return "Error: path outside project directory";
|
|
11319
11577
|
try {
|
|
11320
|
-
|
|
11321
|
-
|
|
11578
|
+
mkdirSync5(dirname5(fullPath), { recursive: true });
|
|
11579
|
+
try {
|
|
11580
|
+
undoBackups.set(filePath, readFileSync9(fullPath, "utf-8"));
|
|
11581
|
+
} catch {
|
|
11582
|
+
}
|
|
11583
|
+
writeFileSync6(fullPath, content, "utf-8");
|
|
11322
11584
|
return `Created ${filePath} (${content.length} chars).`;
|
|
11323
11585
|
} catch (err) {
|
|
11324
11586
|
return `Error writing ${filePath}: ${err instanceof Error ? err.message : String(err)}`;
|
|
@@ -11369,7 +11631,7 @@ function toolRunCommand(command, ctx) {
|
|
|
11369
11631
|
return out.length > MAX_OUTPUT4 ? out.slice(0, MAX_OUTPUT4) + "\n... (truncated)" : out || "Command failed";
|
|
11370
11632
|
}
|
|
11371
11633
|
}
|
|
11372
|
-
var sessionWriteCodeCost, ORCHESTRATOR_TOOL_DEFINITIONS, DANGEROUS_COMMANDS, MAX_OUTPUT4;
|
|
11634
|
+
var sessionWriteCodeCost, undoBackups, SAFE_TOOLS, ORCHESTRATOR_TOOL_DEFINITIONS, DANGEROUS_COMMANDS, MAX_OUTPUT4;
|
|
11373
11635
|
var init_tools3 = __esm({
|
|
11374
11636
|
"src/orchestrator/tools.ts"() {
|
|
11375
11637
|
"use strict";
|
|
@@ -11378,6 +11640,16 @@ var init_tools3 = __esm({
|
|
|
11378
11640
|
init_diff_apply();
|
|
11379
11641
|
init_write_code();
|
|
11380
11642
|
sessionWriteCodeCost = 0;
|
|
11643
|
+
undoBackups = /* @__PURE__ */ new Map();
|
|
11644
|
+
SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
11645
|
+
"search_files",
|
|
11646
|
+
"read_file",
|
|
11647
|
+
"grep_file",
|
|
11648
|
+
"list_files",
|
|
11649
|
+
"git_diff",
|
|
11650
|
+
"run_tests",
|
|
11651
|
+
"write_code"
|
|
11652
|
+
]);
|
|
11381
11653
|
ORCHESTRATOR_TOOL_DEFINITIONS = [
|
|
11382
11654
|
{
|
|
11383
11655
|
name: "search_files",
|
|
@@ -11482,6 +11754,46 @@ var init_tools3 = __esm({
|
|
|
11482
11754
|
},
|
|
11483
11755
|
required: ["command"]
|
|
11484
11756
|
}
|
|
11757
|
+
},
|
|
11758
|
+
{
|
|
11759
|
+
name: "git_diff",
|
|
11760
|
+
description: "Show what changed since the last commit. Returns unified diff of all modified files.",
|
|
11761
|
+
input_schema: {
|
|
11762
|
+
type: "object",
|
|
11763
|
+
properties: {},
|
|
11764
|
+
required: []
|
|
11765
|
+
}
|
|
11766
|
+
},
|
|
11767
|
+
{
|
|
11768
|
+
name: "git_commit",
|
|
11769
|
+
description: "Stage all changes and commit with a message.",
|
|
11770
|
+
input_schema: {
|
|
11771
|
+
type: "object",
|
|
11772
|
+
properties: {
|
|
11773
|
+
message: { type: "string", description: "Commit message" }
|
|
11774
|
+
},
|
|
11775
|
+
required: ["message"]
|
|
11776
|
+
}
|
|
11777
|
+
},
|
|
11778
|
+
{
|
|
11779
|
+
name: "run_tests",
|
|
11780
|
+
description: "Detect and run the project test suite. Tries npm test, then looks for common test runners.",
|
|
11781
|
+
input_schema: {
|
|
11782
|
+
type: "object",
|
|
11783
|
+
properties: {},
|
|
11784
|
+
required: []
|
|
11785
|
+
}
|
|
11786
|
+
},
|
|
11787
|
+
{
|
|
11788
|
+
name: "undo",
|
|
11789
|
+
description: "Revert the last file change made by edit_file or write_file. Restores the file to its previous state.",
|
|
11790
|
+
input_schema: {
|
|
11791
|
+
type: "object",
|
|
11792
|
+
properties: {
|
|
11793
|
+
path: { type: "string", description: "File path to revert" }
|
|
11794
|
+
},
|
|
11795
|
+
required: ["path"]
|
|
11796
|
+
}
|
|
11485
11797
|
}
|
|
11486
11798
|
];
|
|
11487
11799
|
DANGEROUS_COMMANDS = /\b(rm\s+-rf|sudo|chmod\s+777|mkfs|dd\s+if|shutdown|reboot|kill\s+-9|pkill)\b/;
|
|
@@ -11497,6 +11809,15 @@ __export(loop_exports, {
|
|
|
11497
11809
|
async function runOrchestrator(task, cwd, callbacks, signal, previousMessages) {
|
|
11498
11810
|
const startTime = Date.now();
|
|
11499
11811
|
resetWriteCodeCost();
|
|
11812
|
+
const memory = loadMemory(cwd);
|
|
11813
|
+
const memoryBlock = memory ? formatMemoryForPrompt(memory) : "";
|
|
11814
|
+
const projectInstructions = loadProjectInstructions(cwd);
|
|
11815
|
+
const instructionsBlock = projectInstructions ? `
|
|
11816
|
+
|
|
11817
|
+
${MEMORY_INSTRUCTION}
|
|
11818
|
+
|
|
11819
|
+
${projectInstructions}` : "";
|
|
11820
|
+
const systemPrompt = ORCHESTRATOR_PROMPT + memoryBlock + instructionsBlock;
|
|
11500
11821
|
const messages = [
|
|
11501
11822
|
...previousMessages ?? [],
|
|
11502
11823
|
{ role: "user", content: task }
|
|
@@ -11513,13 +11834,14 @@ async function runOrchestrator(task, cwd, callbacks, signal, previousMessages) {
|
|
|
11513
11834
|
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
11514
11835
|
if (signal?.aborted) break;
|
|
11515
11836
|
iterations = i + 1;
|
|
11837
|
+
compactMessagesIfNeeded(messages);
|
|
11516
11838
|
let responseText = "";
|
|
11517
11839
|
const toolCalls = [];
|
|
11518
11840
|
try {
|
|
11519
11841
|
for await (const chunk of streamAgent({
|
|
11520
11842
|
model: ORCHESTRATOR_MODEL,
|
|
11521
11843
|
messages,
|
|
11522
|
-
systemPrompt
|
|
11844
|
+
systemPrompt,
|
|
11523
11845
|
tools: ORCHESTRATOR_TOOL_DEFINITIONS,
|
|
11524
11846
|
maxTokens: 4096,
|
|
11525
11847
|
signal,
|
|
@@ -11562,8 +11884,24 @@ ${errMsg2}`;
|
|
|
11562
11884
|
}))
|
|
11563
11885
|
});
|
|
11564
11886
|
const toolResults = [];
|
|
11565
|
-
|
|
11566
|
-
|
|
11887
|
+
const writeTools = /* @__PURE__ */ new Set(["edit_file", "write_file", "git_commit", "apply_diff"]);
|
|
11888
|
+
const parallelCalls = toolCalls.filter((tc) => !writeTools.has(tc.name));
|
|
11889
|
+
const sequentialCalls = toolCalls.filter((tc) => writeTools.has(tc.name));
|
|
11890
|
+
if (parallelCalls.length > 0) {
|
|
11891
|
+
const results = await Promise.all(
|
|
11892
|
+
parallelCalls.map(async (tc) => {
|
|
11893
|
+
callbacks?.onToolCall?.(tc.name, tc.input);
|
|
11894
|
+
const result = await executeOrchestratorTool(tc.name, tc.input, toolCtx);
|
|
11895
|
+
callbacks?.onToolResult?.(tc.name, result.slice(0, 200));
|
|
11896
|
+
return { toolCallId: tc.id, content: result };
|
|
11897
|
+
})
|
|
11898
|
+
);
|
|
11899
|
+
toolResults.push(...results);
|
|
11900
|
+
}
|
|
11901
|
+
for (const tc of sequentialCalls) {
|
|
11902
|
+
callbacks?.onToolCall?.(tc.name, tc.input);
|
|
11903
|
+
if (!isToolSafe(tc.name, tc.input) && callbacks?.onApprovalNeeded) {
|
|
11904
|
+
}
|
|
11567
11905
|
const result = await executeOrchestratorTool(tc.name, tc.input, toolCtx);
|
|
11568
11906
|
callbacks?.onToolResult?.(tc.name, result.slice(0, 200));
|
|
11569
11907
|
toolResults.push({ toolCallId: tc.id, content: result });
|
|
@@ -11574,6 +11912,23 @@ ${errMsg2}`;
|
|
|
11574
11912
|
toolResults
|
|
11575
11913
|
});
|
|
11576
11914
|
}
|
|
11915
|
+
const editedFiles = [];
|
|
11916
|
+
for (const msg of messages) {
|
|
11917
|
+
const tc = msg.toolCalls;
|
|
11918
|
+
if (tc) {
|
|
11919
|
+
for (const call of tc) {
|
|
11920
|
+
if ((call.name === "edit_file" || call.name === "write_file") && call.input.path) {
|
|
11921
|
+
editedFiles.push(String(call.input.path));
|
|
11922
|
+
}
|
|
11923
|
+
}
|
|
11924
|
+
}
|
|
11925
|
+
}
|
|
11926
|
+
if (editedFiles.length > 0 || fullOutput) {
|
|
11927
|
+
updateMemory(cwd, {
|
|
11928
|
+
editedFiles: [...new Set(editedFiles)],
|
|
11929
|
+
sessionSummary: fullOutput.slice(0, 200)
|
|
11930
|
+
});
|
|
11931
|
+
}
|
|
11577
11932
|
const modelInfo = MODELS[ORCHESTRATOR_MODEL];
|
|
11578
11933
|
const orchestratorCost = modelInfo ? orchestratorInputTokens / 1e6 * modelInfo.inputPrice + orchestratorOutputTokens / 1e6 * modelInfo.outputPrice : 0;
|
|
11579
11934
|
const writeCodeCost = getWriteCodeCost();
|
|
@@ -11588,6 +11943,52 @@ ${errMsg2}`;
|
|
|
11588
11943
|
messages
|
|
11589
11944
|
};
|
|
11590
11945
|
}
|
|
11946
|
+
function compactMessagesIfNeeded(messages) {
|
|
11947
|
+
const totalChars = messages.reduce((sum, m) => {
|
|
11948
|
+
const content = typeof m.content === "string" ? m.content : "";
|
|
11949
|
+
const toolContent = m.toolResults ? JSON.stringify(m.toolResults) : "";
|
|
11950
|
+
return sum + content.length + toolContent.length;
|
|
11951
|
+
}, 0);
|
|
11952
|
+
if (totalChars < MAX_CONTEXT_CHARS) return;
|
|
11953
|
+
if (messages.length <= 8) return;
|
|
11954
|
+
const first = messages[0];
|
|
11955
|
+
const recent = messages.slice(-6);
|
|
11956
|
+
const middle = messages.slice(1, -6);
|
|
11957
|
+
const filesEdited = /* @__PURE__ */ new Set();
|
|
11958
|
+
const filesRead = /* @__PURE__ */ new Set();
|
|
11959
|
+
const userRequests = [];
|
|
11960
|
+
const actionsCompleted = [];
|
|
11961
|
+
for (const msg of middle) {
|
|
11962
|
+
if (msg.role === "user" && msg.content) {
|
|
11963
|
+
userRequests.push(msg.content.slice(0, 150));
|
|
11964
|
+
}
|
|
11965
|
+
if (msg.role === "assistant" && msg.content) {
|
|
11966
|
+
const text = msg.content.trim();
|
|
11967
|
+
if (text) actionsCompleted.push(text.slice(0, 200));
|
|
11968
|
+
}
|
|
11969
|
+
const tc = msg.toolCalls;
|
|
11970
|
+
if (tc) {
|
|
11971
|
+
for (const call of tc) {
|
|
11972
|
+
const path = String(call.input?.path ?? "");
|
|
11973
|
+
if (call.name === "edit_file" || call.name === "write_file") filesEdited.add(path);
|
|
11974
|
+
if (call.name === "read_file" || call.name === "grep_file") filesRead.add(path);
|
|
11975
|
+
}
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
const summaryParts = [
|
|
11979
|
+
"[Conversation compacted to save context]",
|
|
11980
|
+
userRequests.length > 0 ? `User requests: ${userRequests.join(" \u2192 ")}` : "",
|
|
11981
|
+
filesRead.size > 0 ? `Files examined: ${[...filesRead].join(", ")}` : "",
|
|
11982
|
+
filesEdited.size > 0 ? `Files modified: ${[...filesEdited].join(", ")}` : "",
|
|
11983
|
+
actionsCompleted.length > 0 ? `Actions: ${actionsCompleted.join(" | ")}` : ""
|
|
11984
|
+
].filter(Boolean);
|
|
11985
|
+
const summary = {
|
|
11986
|
+
role: "assistant",
|
|
11987
|
+
content: summaryParts.join("\n")
|
|
11988
|
+
};
|
|
11989
|
+
messages.length = 0;
|
|
11990
|
+
messages.push(first, summary, ...recent);
|
|
11991
|
+
}
|
|
11591
11992
|
function formatError(err) {
|
|
11592
11993
|
const raw = err instanceof Error ? err.message : typeof err === "object" && err !== null ? JSON.stringify(err) : String(err);
|
|
11593
11994
|
if (raw.includes("401") || raw.includes("Unauthorized")) return "Gateway auth failed. Run `mint login` or check your API keys.";
|
|
@@ -11599,16 +12000,19 @@ function formatError(err) {
|
|
|
11599
12000
|
if (raw.includes("No provider")) return "No API key configured. Run `mint config:set providers.deepseek <key>` or `mint login`.";
|
|
11600
12001
|
return raw.length > 200 ? raw.slice(0, 200) + "..." : raw;
|
|
11601
12002
|
}
|
|
11602
|
-
var ORCHESTRATOR_MODEL, MAX_ITERATIONS;
|
|
12003
|
+
var ORCHESTRATOR_MODEL, MAX_ITERATIONS, MAX_CONTEXT_CHARS;
|
|
11603
12004
|
var init_loop2 = __esm({
|
|
11604
12005
|
"src/orchestrator/loop.ts"() {
|
|
11605
12006
|
"use strict";
|
|
11606
12007
|
init_providers();
|
|
11607
12008
|
init_prompts();
|
|
12009
|
+
init_memory();
|
|
12010
|
+
init_prompts();
|
|
11608
12011
|
init_tools3();
|
|
11609
12012
|
init_types();
|
|
11610
12013
|
ORCHESTRATOR_MODEL = "grok-4.1-fast";
|
|
11611
12014
|
MAX_ITERATIONS = 20;
|
|
12015
|
+
MAX_CONTEXT_CHARS = 1e5;
|
|
11612
12016
|
}
|
|
11613
12017
|
});
|
|
11614
12018
|
|
|
@@ -11694,11 +12098,12 @@ function estimateInputAreaHeight(input, isBusy, isRouting, contextChips, termina
|
|
|
11694
12098
|
}
|
|
11695
12099
|
return lines;
|
|
11696
12100
|
}
|
|
11697
|
-
function App({ initialPrompt, modelPreference, agentMode, useOrchestrator = true }) {
|
|
12101
|
+
function App({ initialPrompt, modelPreference, agentMode: initialAgentMode, useOrchestrator = true }) {
|
|
11698
12102
|
const { exit } = useApp();
|
|
11699
12103
|
const [messages, setMessages] = useState5([]);
|
|
11700
12104
|
const [input, setInput] = useState5("");
|
|
11701
12105
|
const [isBusy, setIsBusy] = useState5(false);
|
|
12106
|
+
const [agentMode, setAgentMode] = useState5(initialAgentMode);
|
|
11702
12107
|
const [isRouting, setIsRouting] = useState5(false);
|
|
11703
12108
|
const [currentModel, setCurrentModel] = useState5(null);
|
|
11704
12109
|
const [sessionTokens, setSessionTokens] = useState5(0);
|
|
@@ -11833,8 +12238,8 @@ function App({ initialPrompt, modelPreference, agentMode, useOrchestrator = true
|
|
|
11833
12238
|
" /help \u2014 this help",
|
|
11834
12239
|
" /clear \u2014 clear chat",
|
|
11835
12240
|
" /model \u2014 current model",
|
|
11836
|
-
" /
|
|
11837
|
-
" /
|
|
12241
|
+
" /auto \u2014 toggle auto mode (skip approvals)",
|
|
12242
|
+
" /yolo \u2014 toggle yolo mode (full autonomy)",
|
|
11838
12243
|
" /usage \u2014 session stats",
|
|
11839
12244
|
"",
|
|
11840
12245
|
"Keyboard:",
|
|
@@ -11860,6 +12265,28 @@ function App({ initialPrompt, modelPreference, agentMode, useOrchestrator = true
|
|
|
11860
12265
|
resetPhases();
|
|
11861
12266
|
return;
|
|
11862
12267
|
}
|
|
12268
|
+
if (trimmed === "/auto") {
|
|
12269
|
+
const newMode = agentMode === "auto" ? void 0 : "auto";
|
|
12270
|
+
setAgentMode(newMode);
|
|
12271
|
+
setMessages((prev) => [...prev, {
|
|
12272
|
+
id: nextId(),
|
|
12273
|
+
role: "assistant",
|
|
12274
|
+
content: newMode === "auto" ? "Auto mode ON \u2014 changes apply without asking." : "Auto mode OFF \u2014 you'll be asked before changes."
|
|
12275
|
+
}]);
|
|
12276
|
+
setInput("");
|
|
12277
|
+
return;
|
|
12278
|
+
}
|
|
12279
|
+
if (trimmed === "/yolo") {
|
|
12280
|
+
const newMode = agentMode === "yolo" ? void 0 : "yolo";
|
|
12281
|
+
setAgentMode(newMode);
|
|
12282
|
+
setMessages((prev) => [...prev, {
|
|
12283
|
+
id: nextId(),
|
|
12284
|
+
role: "assistant",
|
|
12285
|
+
content: newMode === "yolo" ? "YOLO mode ON \u2014 full autonomy, no approvals." : "YOLO mode OFF \u2014 back to normal approvals."
|
|
12286
|
+
}]);
|
|
12287
|
+
setInput("");
|
|
12288
|
+
return;
|
|
12289
|
+
}
|
|
11863
12290
|
if (trimmed === "/model") {
|
|
11864
12291
|
setScrollOffset(0);
|
|
11865
12292
|
setMessages((prev) => [
|
|
@@ -11931,27 +12358,33 @@ function App({ initialPrompt, modelPreference, agentMode, useOrchestrator = true
|
|
|
11931
12358
|
try {
|
|
11932
12359
|
const { runOrchestrator: runOrchestrator2 } = await Promise.resolve().then(() => (init_loop2(), loop_exports));
|
|
11933
12360
|
let responseText = "";
|
|
11934
|
-
|
|
12361
|
+
const steps = [];
|
|
11935
12362
|
const result = await runOrchestrator2(trimmed, process.cwd(), {
|
|
11936
12363
|
onLog: () => {
|
|
11937
12364
|
},
|
|
11938
12365
|
onText: (text) => {
|
|
11939
12366
|
responseText += text;
|
|
11940
|
-
|
|
11941
|
-
streamRef.current = responseText;
|
|
11942
|
-
setStreamingContent(
|
|
12367
|
+
const stepsBlock2 = steps.length > 0 ? steps.map((s) => ` \x1B[32m\u2713\x1B[0m ${s}`).join("\n") + "\n\n" : "";
|
|
12368
|
+
streamRef.current = stepsBlock2 + responseText;
|
|
12369
|
+
setStreamingContent(streamRef.current);
|
|
11943
12370
|
},
|
|
11944
12371
|
onToolCall: (name, input2) => {
|
|
11945
|
-
const preview = name === "write_code" ?
|
|
11946
|
-
|
|
11947
|
-
|
|
12372
|
+
const preview = name === "write_code" ? "writing code..." : name === "read_file" ? `reading ${String(input2.path ?? "")}` : name === "grep_file" ? `searching in ${String(input2.path ?? "")}` : name === "search_files" ? `searching "${String(input2.query ?? "").slice(0, 40)}"` : name === "edit_file" ? `editing ${String(input2.path ?? "")}` : name === "write_file" ? `creating ${String(input2.path ?? "")}` : name === "run_command" ? `running ${String(input2.command ?? "").slice(0, 40)}` : name;
|
|
12373
|
+
const completedBlock = steps.map((s) => ` \x1B[32m\u2713\x1B[0m ${s}`).join("\n");
|
|
12374
|
+
const activeStep = ` \x1B[36m\u25CF\x1B[0m ${preview}`;
|
|
12375
|
+
streamRef.current = (completedBlock ? completedBlock + "\n" : "") + activeStep;
|
|
11948
12376
|
setStreamingContent(streamRef.current);
|
|
11949
12377
|
},
|
|
11950
|
-
|
|
12378
|
+
onToolResult: (name, result2) => {
|
|
12379
|
+
const label = name === "write_code" ? "code generated" : name === "search_files" ? "files found" : name === "read_file" ? "file read" : name === "grep_file" ? "pattern found" : name === "edit_file" ? result2.startsWith("Edited") ? result2.split(":")[0] : "edit failed" : name === "write_file" ? result2.startsWith("Created") ? result2.split("(")[0].trim() : "write failed" : name === "run_command" ? "command done" : name === "apply_diff" ? "diff applied" : name === "git_diff" ? "changes shown" : name === "git_commit" ? "committed" : name === "run_tests" ? result2.includes("passing") ? "tests passed" : "tests done" : name === "undo" ? "reverted" : name;
|
|
12380
|
+
steps.push(label);
|
|
12381
|
+
},
|
|
12382
|
+
onApprovalNeeded: agentMode === "auto" || agentMode === "yolo" ? void 0 : async (description) => {
|
|
11951
12383
|
return new Promise((resolve12) => {
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
12384
|
+
const stepsBlock2 = steps.map((s) => ` \x1B[32m\u2713\x1B[0m ${s}`).join("\n");
|
|
12385
|
+
responseText = (stepsBlock2 ? stepsBlock2 + "\n\n" : "") + `${description}
|
|
12386
|
+
|
|
12387
|
+
\x1B[36mApply this change? [Y/n]\x1B[0m`;
|
|
11955
12388
|
streamRef.current = responseText;
|
|
11956
12389
|
setStreamingContent(responseText);
|
|
11957
12390
|
setIsBusy(false);
|
|
@@ -11967,9 +12400,10 @@ ${description}
|
|
|
11967
12400
|
}
|
|
11968
12401
|
}, controller.signal, orchestratorMessagesRef.current);
|
|
11969
12402
|
orchestratorMessagesRef.current = result.messages;
|
|
12403
|
+
const stepsBlock = steps.length > 0 ? steps.map((s) => ` \x1B[32m\u2713\x1B[0m ${s}`).join("\n") + "\n\n" : "";
|
|
11970
12404
|
const costLine = `
|
|
11971
|
-
Cost: $${result.totalCost.toFixed(4)} \xB7 ${(result.duration / 1e3).toFixed(1)}s
|
|
11972
|
-
responseText
|
|
12405
|
+
Cost: $${result.totalCost.toFixed(4)} \xB7 ${(result.duration / 1e3).toFixed(1)}s`;
|
|
12406
|
+
responseText = stepsBlock + responseText + costLine;
|
|
11973
12407
|
setMessages(
|
|
11974
12408
|
(prev) => prev.map(
|
|
11975
12409
|
(m) => m.id === assistantMsgIdRef.current ? { ...m, content: responseText, isStreaming: false } : m
|
|
@@ -12303,10 +12737,10 @@ ${diffDisplay}
|
|
|
12303
12737
|
}
|
|
12304
12738
|
async function loadContextChips() {
|
|
12305
12739
|
try {
|
|
12306
|
-
const { readFileSync:
|
|
12307
|
-
const { join:
|
|
12308
|
-
const indexPath =
|
|
12309
|
-
const raw =
|
|
12740
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
12741
|
+
const { join: join21 } = await import("path");
|
|
12742
|
+
const indexPath = join21(process.cwd(), ".mint", "context.json");
|
|
12743
|
+
const raw = readFileSync11(indexPath, "utf-8");
|
|
12310
12744
|
const index = JSON.parse(raw);
|
|
12311
12745
|
const chips = [];
|
|
12312
12746
|
if (index.language) chips.push({ label: index.language, color: "green" });
|
|
@@ -12497,8 +12931,8 @@ var init_dashboard = __esm({
|
|
|
12497
12931
|
// src/cli/index.ts
|
|
12498
12932
|
import { Command } from "commander";
|
|
12499
12933
|
import chalk10 from "chalk";
|
|
12500
|
-
import { readFileSync as
|
|
12501
|
-
import { dirname as
|
|
12934
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6 } from "fs";
|
|
12935
|
+
import { dirname as dirname6, resolve as resolve11, sep as sep9 } from "path";
|
|
12502
12936
|
|
|
12503
12937
|
// src/cli/commands/auth.ts
|
|
12504
12938
|
init_config();
|
|
@@ -12544,7 +12978,7 @@ function promptHidden(question) {
|
|
|
12544
12978
|
});
|
|
12545
12979
|
}
|
|
12546
12980
|
async function signup() {
|
|
12547
|
-
if (
|
|
12981
|
+
if (config2.isAuthenticated()) {
|
|
12548
12982
|
console.log(chalk.yellow("Already logged in. Run `mint logout` first."));
|
|
12549
12983
|
return;
|
|
12550
12984
|
}
|
|
@@ -12560,7 +12994,7 @@ async function signup() {
|
|
|
12560
12994
|
console.log(chalk.red("\n Password must be at least 8 characters."));
|
|
12561
12995
|
return;
|
|
12562
12996
|
}
|
|
12563
|
-
const gatewayUrl =
|
|
12997
|
+
const gatewayUrl = config2.getGatewayUrl();
|
|
12564
12998
|
try {
|
|
12565
12999
|
const res = await fetch(`${gatewayUrl}/auth/signup`, {
|
|
12566
13000
|
method: "POST",
|
|
@@ -12573,7 +13007,7 @@ async function signup() {
|
|
|
12573
13007
|
Signup failed: ${data.error || res.statusText}`));
|
|
12574
13008
|
return;
|
|
12575
13009
|
}
|
|
12576
|
-
|
|
13010
|
+
config2.setAll({
|
|
12577
13011
|
apiKey: data.api_token,
|
|
12578
13012
|
userId: data.user.id,
|
|
12579
13013
|
email: data.user.email
|
|
@@ -12593,8 +13027,8 @@ ${chalk.dim("Token saved. You can now use mint commands.")}`,
|
|
|
12593
13027
|
}
|
|
12594
13028
|
}
|
|
12595
13029
|
async function login() {
|
|
12596
|
-
if (
|
|
12597
|
-
const email2 =
|
|
13030
|
+
if (config2.isAuthenticated()) {
|
|
13031
|
+
const email2 = config2.get("email");
|
|
12598
13032
|
console.log(chalk.yellow(`Already logged in as ${email2}`));
|
|
12599
13033
|
console.log(chalk.dim("Run `mint logout` to switch accounts"));
|
|
12600
13034
|
return;
|
|
@@ -12606,7 +13040,7 @@ async function login() {
|
|
|
12606
13040
|
console.log(chalk.red("\n Email and password are required."));
|
|
12607
13041
|
return;
|
|
12608
13042
|
}
|
|
12609
|
-
const gatewayUrl =
|
|
13043
|
+
const gatewayUrl = config2.getGatewayUrl();
|
|
12610
13044
|
try {
|
|
12611
13045
|
const res = await fetch(`${gatewayUrl}/auth/login`, {
|
|
12612
13046
|
method: "POST",
|
|
@@ -12633,7 +13067,7 @@ async function login() {
|
|
|
12633
13067
|
Failed to create API token: ${tokenData.error}`));
|
|
12634
13068
|
return;
|
|
12635
13069
|
}
|
|
12636
|
-
|
|
13070
|
+
config2.setAll({
|
|
12637
13071
|
apiKey: tokenData.token,
|
|
12638
13072
|
userId: data.user.id,
|
|
12639
13073
|
email: data.user.email
|
|
@@ -12646,22 +13080,22 @@ async function login() {
|
|
|
12646
13080
|
}
|
|
12647
13081
|
}
|
|
12648
13082
|
async function logout() {
|
|
12649
|
-
if (!
|
|
13083
|
+
if (!config2.isAuthenticated()) {
|
|
12650
13084
|
console.log(chalk.yellow("Not currently logged in"));
|
|
12651
13085
|
return;
|
|
12652
13086
|
}
|
|
12653
|
-
const email =
|
|
12654
|
-
|
|
13087
|
+
const email = config2.get("email");
|
|
13088
|
+
config2.clear();
|
|
12655
13089
|
console.log(chalk.green(`Logged out from ${email}`));
|
|
12656
13090
|
}
|
|
12657
13091
|
async function whoami() {
|
|
12658
|
-
if (!
|
|
13092
|
+
if (!config2.isAuthenticated()) {
|
|
12659
13093
|
console.log(chalk.yellow("Not logged in"));
|
|
12660
13094
|
console.log(chalk.dim("Run `mint login` or `mint signup` to authenticate"));
|
|
12661
13095
|
return;
|
|
12662
13096
|
}
|
|
12663
|
-
const email =
|
|
12664
|
-
const configPath =
|
|
13097
|
+
const email = config2.get("email");
|
|
13098
|
+
const configPath = config2.getConfigPath();
|
|
12665
13099
|
console.log(boxen(
|
|
12666
13100
|
`${chalk.bold("Current User")}
|
|
12667
13101
|
|
|
@@ -12677,8 +13111,8 @@ import chalk2 from "chalk";
|
|
|
12677
13111
|
import boxen2 from "boxen";
|
|
12678
13112
|
import Table from "cli-table3";
|
|
12679
13113
|
async function showConfig() {
|
|
12680
|
-
const currentConfig =
|
|
12681
|
-
const configPath =
|
|
13114
|
+
const currentConfig = config2.getConfig();
|
|
13115
|
+
const configPath = config2.getConfigPath();
|
|
12682
13116
|
console.log(boxen2(
|
|
12683
13117
|
chalk2.bold("Mint Configuration") + "\n\n" + chalk2.dim(`Path: ${configPath}`),
|
|
12684
13118
|
{ padding: 1, borderColor: "cyan", borderStyle: "round" }
|
|
@@ -12720,8 +13154,8 @@ async function showConfig() {
|
|
|
12720
13154
|
async function setConfig(key, value) {
|
|
12721
13155
|
if (key.startsWith("providers.")) {
|
|
12722
13156
|
const provider = key.split(".")[1];
|
|
12723
|
-
const currentProviders =
|
|
12724
|
-
|
|
13157
|
+
const currentProviders = config2.get("providers") || {};
|
|
13158
|
+
config2.set("providers", {
|
|
12725
13159
|
...currentProviders,
|
|
12726
13160
|
[provider]: value
|
|
12727
13161
|
});
|
|
@@ -12729,16 +13163,16 @@ async function setConfig(key, value) {
|
|
|
12729
13163
|
return;
|
|
12730
13164
|
}
|
|
12731
13165
|
if (value === "true" || value === "false") {
|
|
12732
|
-
|
|
13166
|
+
config2.set(key, value === "true");
|
|
12733
13167
|
console.log(chalk2.green(`\u2713 Set ${key} = ${value}`));
|
|
12734
13168
|
return;
|
|
12735
13169
|
}
|
|
12736
13170
|
if (!isNaN(Number(value))) {
|
|
12737
|
-
|
|
13171
|
+
config2.set(key, Number(value));
|
|
12738
13172
|
console.log(chalk2.green(`\u2713 Set ${key} = ${value}`));
|
|
12739
13173
|
return;
|
|
12740
13174
|
}
|
|
12741
|
-
|
|
13175
|
+
config2.set(key, value);
|
|
12742
13176
|
console.log(chalk2.green(`\u2713 Set ${key} = ${value}`));
|
|
12743
13177
|
}
|
|
12744
13178
|
|
|
@@ -13004,14 +13438,14 @@ import chalk4 from "chalk";
|
|
|
13004
13438
|
import boxen3 from "boxen";
|
|
13005
13439
|
import Table3 from "cli-table3";
|
|
13006
13440
|
async function showUsage(options) {
|
|
13007
|
-
if (!
|
|
13441
|
+
if (!config2.isAuthenticated()) {
|
|
13008
13442
|
console.log(chalk4.yellow("Not authenticated. Usage tracking requires login."));
|
|
13009
13443
|
console.log(chalk4.dim("Run `axon login` to authenticate"));
|
|
13010
13444
|
return;
|
|
13011
13445
|
}
|
|
13012
13446
|
const days = parseInt(options.days, 10) || 7;
|
|
13013
|
-
const apiBaseUrl =
|
|
13014
|
-
const apiKey =
|
|
13447
|
+
const apiBaseUrl = config2.get("apiBaseUrl") || "https://api.axon.dev";
|
|
13448
|
+
const apiKey = config2.get("apiKey");
|
|
13015
13449
|
console.log(chalk4.dim(`Fetching usage for last ${days} days...
|
|
13016
13450
|
`));
|
|
13017
13451
|
try {
|
|
@@ -13268,9 +13702,9 @@ program.command("init").description("Scan project and build search index").actio
|
|
|
13268
13702
|
const topLangs = [...languages.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([lang, count]) => `${lang} (${count})`).join(", ");
|
|
13269
13703
|
let depCount = 0;
|
|
13270
13704
|
try {
|
|
13271
|
-
const { readFileSync:
|
|
13272
|
-
const { join:
|
|
13273
|
-
const pkg = JSON.parse(
|
|
13705
|
+
const { readFileSync: readFileSync11 } = await import("fs");
|
|
13706
|
+
const { join: join21 } = await import("path");
|
|
13707
|
+
const pkg = JSON.parse(readFileSync11(join21(cwd, "package.json"), "utf-8"));
|
|
13274
13708
|
depCount = Object.keys(pkg.dependencies ?? {}).length + Object.keys(pkg.devDependencies ?? {}).length;
|
|
13275
13709
|
} catch {
|
|
13276
13710
|
}
|
|
@@ -13283,6 +13717,16 @@ program.command("init").description("Scan project and build search index").actio
|
|
|
13283
13717
|
console.log(chalk10.dim(`
|
|
13284
13718
|
Run ${chalk10.cyan("mint")} to start editing.
|
|
13285
13719
|
`));
|
|
13720
|
+
try {
|
|
13721
|
+
const gatewayUrl = config.get("apiBaseUrl") ?? "https://api.usemint.dev";
|
|
13722
|
+
fetch(`${gatewayUrl}/track`, {
|
|
13723
|
+
method: "POST",
|
|
13724
|
+
headers: { "Content-Type": "application/json" },
|
|
13725
|
+
body: JSON.stringify({ event: "init", files_indexed: index.totalFiles, language: index.language })
|
|
13726
|
+
}).catch(() => {
|
|
13727
|
+
});
|
|
13728
|
+
} catch {
|
|
13729
|
+
}
|
|
13286
13730
|
});
|
|
13287
13731
|
program.command("skills").description("List all skills in .mint/skills/").action(async () => {
|
|
13288
13732
|
const { loadSkills: loadSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
@@ -13491,13 +13935,13 @@ function applyDiffs(diffs, cwd) {
|
|
|
13491
13935
|
}
|
|
13492
13936
|
try {
|
|
13493
13937
|
if (diff.oldContent === "") {
|
|
13494
|
-
|
|
13938
|
+
mkdirSync6(dirname6(fullPath), { recursive: true });
|
|
13495
13939
|
const newContent = diff.hunks.flatMap((h) => h.lines.filter((l) => l.type !== "remove").map((l) => l.content)).join("\n");
|
|
13496
|
-
|
|
13940
|
+
writeFileSync7(fullPath, newContent + "\n", "utf-8");
|
|
13497
13941
|
console.log(chalk10.green(` + Created ${diff.filePath}`));
|
|
13498
13942
|
continue;
|
|
13499
13943
|
}
|
|
13500
|
-
const current =
|
|
13944
|
+
const current = readFileSync10(fullPath, "utf-8");
|
|
13501
13945
|
let updated = current;
|
|
13502
13946
|
for (const hunk of diff.hunks) {
|
|
13503
13947
|
const removeLines = hunk.lines.filter((l) => l.type === "remove").map((l) => l.content);
|
|
@@ -13527,7 +13971,7 @@ function applyDiffs(diffs, cwd) {
|
|
|
13527
13971
|
}
|
|
13528
13972
|
}
|
|
13529
13973
|
if (updated !== current) {
|
|
13530
|
-
|
|
13974
|
+
writeFileSync7(fullPath, updated, "utf-8");
|
|
13531
13975
|
console.log(chalk10.green(` ~ Modified ${diff.filePath}`));
|
|
13532
13976
|
} else {
|
|
13533
13977
|
console.log(chalk10.yellow(` ? Could not apply diff to ${diff.filePath} (text not found)`));
|