@liumir/lmcode 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/{app-cmsAp4uI.mjs → app-E1W6D7x3.mjs} +251 -64
- package/dist/main.mjs +1 -1
- package/package.json +80 -80
package/README.md
CHANGED
|
@@ -75,6 +75,43 @@ cd ~/.lmcode && ./install.sh --upgrade
|
|
|
75
75
|
|
|
76
76
|
---
|
|
77
77
|
|
|
78
|
+
## 🚀 v0.7.0 更新日志
|
|
79
|
+
|
|
80
|
+
### ✨ 新功能
|
|
81
|
+
- **MultiEdit 批量编辑工具** — 一次调用对同一文件做多处 find/replace,**原子生效**(任一处失败则整批不写、文件不动)。把原来 N 次 Edit 往返压成 1 次,明显提速并降低 token 消耗
|
|
82
|
+
- **Glob 支持花括号展开** — `*.{ts,tsx}`、`{src,test}/**/*.ts` 等一次调用即匹配所有分支(支持多组与嵌套、转义按字面),不再需要拆成多次调用
|
|
83
|
+
|
|
84
|
+
### 🐞 修复 / 体验
|
|
85
|
+
- **Write 自动创建父目录** — 写入到不存在的目录时自动 `mkdir -p`,消除「写入失败 → mkdir → 重写整个文件」的二次往返(大文件可省去约一倍输出 token)
|
|
86
|
+
- **`lm -p` 参数顺序不再敏感** — `--prompt` 改为可选值并支持末尾位置参数,`lm -p --output-format stream-json "..."` 等任意顺序都能正确解析;裸文本 `lm "..."` 也可作为一次性提示
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 🚀 v0.6.0 更新日志
|
|
91
|
+
|
|
92
|
+
### 🐞 修复
|
|
93
|
+
- **135 个 Windows 测试失败全部修复** — 覆盖路径归一化、SQLite EBUSY 清理、Hook 子进程、yolo 权限迁移、配置格式等 10 类问题
|
|
94
|
+
- **Hook 子进程在 Windows 上弹出 git 窗口** — `spawn()` 添加 `windowsHide: true`,根治每次跑 hook 弹 conhost 窗口
|
|
95
|
+
- **brand rename 遗留的 "scream" 引用** — 218 处 scream → lmcode 品牌重命名全覆盖
|
|
96
|
+
|
|
97
|
+
### ⚡ 性能优化
|
|
98
|
+
- **linkedom(2MB)和 nunjucks(1.8MB)懒加载** — 不再静态打包,仅在首次使用时动态 import,大幅降低启动时间
|
|
99
|
+
- **系统提示词精简** — AGENTS.md 改为路径列表按需读取(原 32KB 固定注入),移除冗余通用指令
|
|
100
|
+
- **embedding 存储优化** — JSON 字符串改为二进制 Float32Array Buffer
|
|
101
|
+
- **FTS 空结果回退优化** — 先尝试前缀通配符再全表扫描
|
|
102
|
+
|
|
103
|
+
### 🧹 清理
|
|
104
|
+
- **安装脚本修复** — `scream` → `lm` 命令创建正确
|
|
105
|
+
- **死代码清理** — 移除 migration 残留代码
|
|
106
|
+
- **CI 基础设施** — 添加 `.nvmrc`,配置简单 git hooks
|
|
107
|
+
- **文档修复** — tsconfig、README 等同步更新
|
|
108
|
+
|
|
109
|
+
### 🏗️ 架构
|
|
110
|
+
- **多注入器合并** — 所有 `beforeStep` 注入器合并为单条 `<system-reminder>` 复合消息
|
|
111
|
+
- **bundle 分割** — 移除 `alwaysBundle` 配置,产物自然分割(主入口仅 ~0.54kB)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
78
115
|
## cc-connect 通过聊天远程控制 LMcode
|
|
79
116
|
|
|
80
117
|
- 支持微信、飞书、slack、钉钉、QQ、Telegram等,你可以在安装lmcode后一键安装cc-connect来控制你的 LMcode
|
|
@@ -67480,7 +67480,7 @@ function computeAnchor(text) {
|
|
|
67480
67480
|
}
|
|
67481
67481
|
//#endregion
|
|
67482
67482
|
//#region ../../packages/agent-core/src/tools/builtin/file/edit.md
|
|
67483
|
-
var edit_default = "Perform exact string replacements against the text view returned by Read.\r\n\r\n- When copying from Read output, omit the line-number prefix and tab; match only the file content.\r\n- By default, old_string must occur exactly once. If it matches multiple locations, add surrounding context or set replace_all when every occurrence should change.\r\n- Prefer Edit for targeted changes to existing files; use Write only for new files or complete overwrites.\r\n- To modify a file, always use Edit; do not run a Shell `sed` command for edits.\r\n- When making several independent changes, issue multiple Edit calls in parallel within a single response; edits to the same file are serialized automatically by a write lock.\r\n- When several parallel Edit calls target the same file, a write lock serializes them; they apply in the order the calls appear in your response. An edit fails with `old_string not found` if its old_string was taken from text an earlier edit already replaced — base every old_string on the latest Read view and order dependent edits accordingly.\r\n- For pure CRLF files, Read shows LF and Edit.old_string/new_string should use LF; Edit writes the file back with CRLF preserved.\r\n- For mixed line endings or lone carriage returns, Read displays carriage returns as \\r; include actual \\r escapes in old_string/new_string for those positions.\r\n- When Read returned an `Anchor:` value in its status block, pass it as `anchor` to verify the file has not changed since it was read. If the anchor does not match, re-read the file before editing.";
|
|
67483
|
+
var edit_default = "Perform exact string replacements against the text view returned by Read.\r\n\r\n- When copying from Read output, omit the line-number prefix and tab; match only the file content.\r\n- By default, old_string must occur exactly once. If it matches multiple locations, add surrounding context or set replace_all when every occurrence should change.\r\n- Prefer Edit for targeted changes to existing files; use Write only for new files or complete overwrites.\r\n- When making several changes to the SAME file, prefer a single `MultiEdit` call over multiple `Edit` calls — it applies all the edits atomically in one round-trip.\r\n- To modify a file, always use Edit; do not run a Shell `sed` command for edits.\r\n- When making several independent changes, issue multiple Edit calls in parallel within a single response; edits to the same file are serialized automatically by a write lock.\r\n- When several parallel Edit calls target the same file, a write lock serializes them; they apply in the order the calls appear in your response. An edit fails with `old_string not found` if its old_string was taken from text an earlier edit already replaced — base every old_string on the latest Read view and order dependent edits accordingly.\r\n- For pure CRLF files, Read shows LF and Edit.old_string/new_string should use LF; Edit writes the file back with CRLF preserved.\r\n- For mixed line endings or lone carriage returns, Read displays carriage returns as \\r; include actual \\r escapes in old_string/new_string for those positions.\r\n- When Read returned an `Anchor:` value in its status block, pass it as `anchor` to verify the file has not changed since it was read. If the anchor does not match, re-read the file before editing.";
|
|
67484
67484
|
//#endregion
|
|
67485
67485
|
//#region ../../packages/agent-core/src/tools/builtin/file/edit.ts
|
|
67486
67486
|
const EditInputSchema = z.object({
|
|
@@ -67490,7 +67490,7 @@ const EditInputSchema = z.object({
|
|
|
67490
67490
|
replace_all: z.boolean().optional().describe("Set true only when every occurrence of old_string should be replaced."),
|
|
67491
67491
|
anchor: z.string().optional().describe("Content anchor from the most recent Read of this file. When provided, Edit verifies the file content has not changed before applying the replacement.")
|
|
67492
67492
|
});
|
|
67493
|
-
function replaceOnceLiteral(content, oldString, newString) {
|
|
67493
|
+
function replaceOnceLiteral$1(content, oldString, newString) {
|
|
67494
67494
|
const index = content.indexOf(oldString);
|
|
67495
67495
|
if (index === -1) return content;
|
|
67496
67496
|
return content.slice(0, index) + newString + content.slice(index + oldString.length);
|
|
@@ -67564,7 +67564,7 @@ var EditTool = class {
|
|
|
67564
67564
|
isError: true,
|
|
67565
67565
|
output: `old_string is not unique in ${args.path} (found ${String(count)} occurrences). To replace every occurrence, set replace_all=true. To replace only one occurrence, include more surrounding context in old_string.`
|
|
67566
67566
|
};
|
|
67567
|
-
const newContent = replaceOnceLiteral(content, args.old_string, args.new_string);
|
|
67567
|
+
const newContent = replaceOnceLiteral$1(content, args.old_string, args.new_string);
|
|
67568
67568
|
await this.jian.writeText(safePath, materializeModelText(newContent, modelView.lineEndingStyle));
|
|
67569
67569
|
return { output: `Replaced 1 occurrence in ${args.path}` };
|
|
67570
67570
|
}
|
|
@@ -67661,7 +67661,7 @@ async function listDirectory(jian, workDir = jian.getcwd()) {
|
|
|
67661
67661
|
}
|
|
67662
67662
|
//#endregion
|
|
67663
67663
|
//#region ../../packages/agent-core/src/tools/builtin/file/glob.md
|
|
67664
|
-
var glob_default = "Find files (and optionally directories) by glob pattern, sorted by modification time (most recent first).\r\n\r\nGood patterns:\r\n- `*.ts` — files in the current directory matching an extension\r\n- `src/**/*.ts` — recursive with a subdirectory anchor and extension\r\n- `test_*.py` — files whose name starts with a literal prefix\r\n\r\nRejected patterns (no literal anchor — nothing bounds the result set):\r\n- `**`, `**/*`, `*/*` — pure wildcards. Add an extension or subdirectory to give the walk a concrete target.\r\n- Anything that starts with `**/` (e.g. `**/*.md`, `**/main/*.py`). The leading `**/` has no literal anchor in front of it. Anchor it with a top-level subdirectory like `src/**/*.md
|
|
67664
|
+
var glob_default = "Find files (and optionally directories) by glob pattern, sorted by modification time (most recent first).\r\n\r\nGood patterns:\r\n- `*.ts` — files in the current directory matching an extension\r\n- `src/**/*.ts` — recursive with a subdirectory anchor and extension\r\n- `test_*.py` — files whose name starts with a literal prefix\r\n- `*.{ts,tsx}` — brace expansion is supported and matches every alternative in one call (also `{src,test}/**/*.ts`)\r\n\r\nRejected patterns (no literal anchor — nothing bounds the result set):\r\n- `**`, `**/*`, `*/*` — pure wildcards. Add an extension or subdirectory to give the walk a concrete target.\r\n- Anything that starts with `**/` (e.g. `**/*.md`, `**/main/*.py`). The leading `**/` has no literal anchor in front of it. Anchor it with a top-level subdirectory like `src/**/*.md`. (Each brace alternative must also satisfy this — `{**/*.ts,src/*.ts}` is rejected.)\r\n\r\nLarge-directory warning — avoid recursing into dependency/build output even with an anchor:\r\n- `node_modules/**/*.js`, `.venv/**/*.py`, `__pycache__/**`, `target/**` all match technically but\r\n typically produce thousands of results that truncate at the match cap and waste the caller context.\r\n Prefer specific subpaths like `node_modules/react/src/**/*.js`.";
|
|
67665
67665
|
//#endregion
|
|
67666
67666
|
//#region ../../packages/agent-core/src/tools/builtin/file/glob.ts
|
|
67667
67667
|
const GlobInputSchema = z.object({
|
|
@@ -67727,35 +67727,34 @@ var GlobTool = class {
|
|
|
67727
67727
|
};
|
|
67728
67728
|
}
|
|
67729
67729
|
async execution(args, searchRoots) {
|
|
67730
|
-
|
|
67731
|
-
|
|
67732
|
-
|
|
67733
|
-
tree
|
|
67734
|
-
|
|
67735
|
-
|
|
67730
|
+
const patterns = expandBraces(args.pattern).slice(0, 100);
|
|
67731
|
+
for (const pattern of patterns) {
|
|
67732
|
+
if (startsWithDoubleStarPrefix(pattern)) {
|
|
67733
|
+
let tree;
|
|
67734
|
+
try {
|
|
67735
|
+
tree = await listDirectory(this.jian, this.workspace.workspaceDir);
|
|
67736
|
+
} catch {
|
|
67737
|
+
tree = "(listing unavailable)";
|
|
67738
|
+
}
|
|
67739
|
+
return {
|
|
67740
|
+
isError: true,
|
|
67741
|
+
output: `Pattern "${pattern}" starts with '**' which is not allowed — the leading '**/' has no literal anchor in front of it and would enumerate every file under the search root, typically exhausting the caller's context on large trees. Use more specific patterns instead, such as "src/**/*.py" or "test/**/*.py".\n\nTop of ${this.workspace.workspaceDir}:\n${tree}`
|
|
67742
|
+
};
|
|
67736
67743
|
}
|
|
67737
|
-
|
|
67738
|
-
|
|
67739
|
-
|
|
67740
|
-
|
|
67741
|
-
|
|
67742
|
-
|
|
67743
|
-
|
|
67744
|
-
|
|
67745
|
-
|
|
67746
|
-
|
|
67747
|
-
|
|
67748
|
-
|
|
67744
|
+
if (isPureWildcard(pattern)) {
|
|
67745
|
+
const rootList = [this.workspace.workspaceDir, ...this.workspace.additionalDirs].map((d) => ` - ${d}`).join("\n");
|
|
67746
|
+
let tree;
|
|
67747
|
+
try {
|
|
67748
|
+
tree = await listDirectory(this.jian, this.workspace.workspaceDir);
|
|
67749
|
+
} catch {
|
|
67750
|
+
tree = "(listing unavailable)";
|
|
67751
|
+
}
|
|
67752
|
+
return {
|
|
67753
|
+
isError: true,
|
|
67754
|
+
output: `Pattern "${pattern}" is a pure wildcard (only \`*\`, \`?\`, \`**\`, \`/\`) and would enumerate every file under the search root — with no literal anchor to bound the result set, this typically exhausts your context on large trees. Add an extension ("${pattern === "**" || pattern === "**/*" ? "**/*.ts" : "**/*.md"}") or a subdirectory ("src/**/*.ts") to constrain the walk.\n\nAllowed roots for explicit path searches:\n${rootList}\n\nTop of ${this.workspace.workspaceDir}:\n${tree}`
|
|
67755
|
+
};
|
|
67749
67756
|
}
|
|
67750
|
-
return {
|
|
67751
|
-
isError: true,
|
|
67752
|
-
output: `Pattern "${args.pattern}" is a pure wildcard (only \`*\`, \`?\`, \`**\`, \`/\`) and would enumerate every file under the search root — with no literal anchor to bound the result set, this typically exhausts your context on large trees. Add an extension ("${args.pattern === "**" || args.pattern === "**/*" ? "**/*.ts" : "**/*.md"}") or a subdirectory ("src/**/*.ts") to constrain the walk.\n\nAllowed roots for explicit path searches:\n${rootList}\n\nTop of ${this.workspace.workspaceDir}:\n${tree}`
|
|
67753
|
-
};
|
|
67754
67757
|
}
|
|
67755
|
-
if (containsBraceExpansion(args.pattern)) return {
|
|
67756
|
-
isError: true,
|
|
67757
|
-
output: `Pattern "${args.pattern}" uses brace expansion (\`{a,b,...}\`), which is not supported by this Glob tool. Split it into separate calls, one pattern per alternative. For example, instead of "*.{ts,tsx}" issue two calls: "*.ts" and "*.tsx".`
|
|
67758
|
-
};
|
|
67759
67758
|
const includeDirs = args.include_dirs ?? true;
|
|
67760
67759
|
for (const root of searchRoots) try {
|
|
67761
67760
|
const iter = this.jian.iterdir(root);
|
|
@@ -67780,7 +67779,7 @@ var GlobTool = class {
|
|
|
67780
67779
|
const YIELD_SAFETY_CAP = MAX_MATCHES * 2;
|
|
67781
67780
|
let yielded = 0;
|
|
67782
67781
|
let truncated = false;
|
|
67783
|
-
outer: for (const root of searchRoots) for await (const filePath of this.jian.glob(root,
|
|
67782
|
+
outer: for (const root of searchRoots) for (const pattern of patterns) for await (const filePath of this.jian.glob(root, pattern)) {
|
|
67784
67783
|
yielded++;
|
|
67785
67784
|
if (yielded >= YIELD_SAFETY_CAP) {
|
|
67786
67785
|
truncated = true;
|
|
@@ -67872,29 +67871,74 @@ function isPureWildcard(pattern) {
|
|
|
67872
67871
|
}
|
|
67873
67872
|
return true;
|
|
67874
67873
|
}
|
|
67875
|
-
/**
|
|
67876
|
-
|
|
67877
|
-
|
|
67878
|
-
|
|
67874
|
+
/**
|
|
67875
|
+
* Expand shell-style `{a,b,c}` brace alternatives into concrete patterns,
|
|
67876
|
+
* so `*.{ts,tsx}` becomes `['*.ts', '*.tsx']` and one call can match every
|
|
67877
|
+
* alternative. Handles multiple and nested groups (the cartesian product);
|
|
67878
|
+
* backslash-escaped braces and commas are treated as literals. A group with
|
|
67879
|
+
* no top-level comma (e.g. `{x}`) and an unbalanced brace are both left
|
|
67880
|
+
* untouched. Returns `[pattern]` when there is nothing to expand. Results are
|
|
67881
|
+
* de-duplicated while preserving first-seen order.
|
|
67882
|
+
*/
|
|
67883
|
+
function expandBraces(pattern) {
|
|
67884
|
+
const group = findFirstBraceGroup(pattern);
|
|
67885
|
+
if (group === void 0) return [pattern];
|
|
67886
|
+
const prefix = pattern.slice(0, group.start);
|
|
67887
|
+
const suffix = pattern.slice(group.end + 1);
|
|
67888
|
+
const out = [];
|
|
67889
|
+
const seen = /* @__PURE__ */ new Set();
|
|
67890
|
+
for (const alt of group.alternatives) for (const expanded of expandBraces(prefix + alt + suffix)) if (!seen.has(expanded)) {
|
|
67891
|
+
seen.add(expanded);
|
|
67892
|
+
out.push(expanded);
|
|
67893
|
+
}
|
|
67894
|
+
return out;
|
|
67895
|
+
}
|
|
67896
|
+
/**
|
|
67897
|
+
* Locate the first balanced `{...}` group that contains a top-level comma.
|
|
67898
|
+
* Returns its bounds and the comma-separated alternatives, or `undefined`
|
|
67899
|
+
* when there is no expandable group (no brace, unbalanced, or comma-free).
|
|
67900
|
+
*/
|
|
67901
|
+
function findFirstBraceGroup(pattern) {
|
|
67879
67902
|
for (let i = 0; i < pattern.length; i++) {
|
|
67880
67903
|
const ch = pattern[i];
|
|
67881
|
-
if (ch === "\\"
|
|
67904
|
+
if (ch === "\\") {
|
|
67882
67905
|
i++;
|
|
67883
67906
|
continue;
|
|
67884
67907
|
}
|
|
67885
|
-
if (ch
|
|
67886
|
-
|
|
67887
|
-
|
|
67888
|
-
|
|
67908
|
+
if (ch !== "{") continue;
|
|
67909
|
+
let depth = 1;
|
|
67910
|
+
const commaPositions = [];
|
|
67911
|
+
let j = i + 1;
|
|
67912
|
+
for (; j < pattern.length; j++) {
|
|
67913
|
+
const c = pattern[j];
|
|
67914
|
+
if (c === "\\") {
|
|
67915
|
+
j++;
|
|
67916
|
+
continue;
|
|
67917
|
+
}
|
|
67918
|
+
if (c === "{") depth++;
|
|
67919
|
+
else if (c === "}") {
|
|
67920
|
+
depth--;
|
|
67921
|
+
if (depth === 0) break;
|
|
67922
|
+
} else if (c === "," && depth === 1) commaPositions.push(j);
|
|
67889
67923
|
}
|
|
67890
|
-
if (
|
|
67891
|
-
|
|
67892
|
-
|
|
67924
|
+
if (depth !== 0) return void 0;
|
|
67925
|
+
if (commaPositions.length === 0) {
|
|
67926
|
+
i = j;
|
|
67893
67927
|
continue;
|
|
67894
67928
|
}
|
|
67895
|
-
|
|
67929
|
+
const alternatives = [];
|
|
67930
|
+
let prev = i + 1;
|
|
67931
|
+
for (const pos of commaPositions) {
|
|
67932
|
+
alternatives.push(pattern.slice(prev, pos));
|
|
67933
|
+
prev = pos + 1;
|
|
67934
|
+
}
|
|
67935
|
+
alternatives.push(pattern.slice(prev, j));
|
|
67936
|
+
return {
|
|
67937
|
+
start: i,
|
|
67938
|
+
end: j,
|
|
67939
|
+
alternatives
|
|
67940
|
+
};
|
|
67896
67941
|
}
|
|
67897
|
-
return false;
|
|
67898
67942
|
}
|
|
67899
67943
|
//#endregion
|
|
67900
67944
|
//#region ../../node_modules/.pnpm/tar@7.5.15/node_modules/tar/dist/esm/index.min.js
|
|
@@ -72849,6 +72893,116 @@ async function readStreamWithCap(stream, maxBytes) {
|
|
|
72849
72893
|
truncated
|
|
72850
72894
|
};
|
|
72851
72895
|
}
|
|
72896
|
+
//#endregion
|
|
72897
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/multi-edit.md
|
|
72898
|
+
var multi_edit_default = "Apply several exact string replacements to a single file in one atomic call.\r\n\r\n- Use this instead of multiple `Edit` calls when you need to make several changes to the SAME file — it collapses N round-trips into one and is applied atomically.\r\n- `edits` is an ordered list; each edit applies to the result of the previous one, so a later edit may match text an earlier edit produced.\r\n- Atomic: every edit is validated and applied in memory first. If ANY edit fails (its `old_string` is missing, or matches more than once without `replace_all`), nothing is written and the file is left unchanged — the error names which edit failed.\r\n- Each edit follows the same rules as `Edit`: copy `old_string` from the Read output view without the line-number prefix; `old_string` must occur exactly once unless `replace_all` is set; `old_string` and `new_string` must differ.\r\n- Use `Write` (not MultiEdit) to create a new file or completely overwrite one. Use a single `Edit` when there is only one change. For independent edits across DIFFERENT files, issue parallel `Edit`/`MultiEdit` calls instead.\r\n- Line endings follow the same convention as `Read`/`Edit`: pure CRLF files are shown with LF and written back as CRLF; mixed or lone carriage returns appear as `\\r` and need exact escapes.\r\n- Pass `anchor` (from the latest Read status block) to verify the file has not changed since it was read before applying any edit.\r\n";
|
|
72899
|
+
//#endregion
|
|
72900
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/multi-edit.ts
|
|
72901
|
+
const SingleEditSchema = z.object({
|
|
72902
|
+
old_string: z.string().min(1).describe("Exact content to replace from the Read output view, without the line-number prefix. Use LF for pure CRLF files; use actual \\r escapes where Read shows \\r."),
|
|
72903
|
+
new_string: z.string().describe("Replacement text in the same Read output view."),
|
|
72904
|
+
replace_all: z.boolean().optional().describe("Set true only when every occurrence of this edit's old_string should be replaced.")
|
|
72905
|
+
});
|
|
72906
|
+
const MultiEditInputSchema = z.object({
|
|
72907
|
+
path: z.string().describe("Path to the text file to edit. Relative paths resolve against the working directory; a path outside the working directory must be absolute."),
|
|
72908
|
+
edits: z.array(SingleEditSchema).min(1, "Provide at least one edit.").describe("Edits applied sequentially in order; each one sees the result of the previous one. The whole batch is atomic — if any edit fails to apply, none are written."),
|
|
72909
|
+
anchor: z.string().optional().describe("Content anchor from the most recent Read of this file. When provided, MultiEdit verifies the file content has not changed before applying any edit.")
|
|
72910
|
+
});
|
|
72911
|
+
function replaceOnceLiteral(content, oldString, newString) {
|
|
72912
|
+
const index = content.indexOf(oldString);
|
|
72913
|
+
if (index === -1) return content;
|
|
72914
|
+
return content.slice(0, index) + newString + content.slice(index + oldString.length);
|
|
72915
|
+
}
|
|
72916
|
+
var MultiEditTool = class {
|
|
72917
|
+
jian;
|
|
72918
|
+
workspace;
|
|
72919
|
+
name = "MultiEdit";
|
|
72920
|
+
description = multi_edit_default;
|
|
72921
|
+
parameters = toInputJsonSchema(MultiEditInputSchema);
|
|
72922
|
+
constructor(jian, workspace) {
|
|
72923
|
+
this.jian = jian;
|
|
72924
|
+
this.workspace = workspace;
|
|
72925
|
+
}
|
|
72926
|
+
resolveExecution(args) {
|
|
72927
|
+
const path = resolvePathAccessPath(args.path, {
|
|
72928
|
+
jian: this.jian,
|
|
72929
|
+
workspace: this.workspace,
|
|
72930
|
+
operation: "write"
|
|
72931
|
+
});
|
|
72932
|
+
const editCount = args.edits.length;
|
|
72933
|
+
return {
|
|
72934
|
+
accesses: ToolAccesses.readWriteFile(path),
|
|
72935
|
+
description: `Editing ${args.path} (${String(editCount)} edits)`,
|
|
72936
|
+
display: {
|
|
72937
|
+
kind: "file_io",
|
|
72938
|
+
operation: "edit",
|
|
72939
|
+
path,
|
|
72940
|
+
detail: `${String(editCount)} edit${editCount === 1 ? "" : "s"}`,
|
|
72941
|
+
before: args.edits.map((edit) => edit.old_string).join("\n"),
|
|
72942
|
+
after: args.edits.map((edit) => edit.new_string).join("\n")
|
|
72943
|
+
},
|
|
72944
|
+
approvalRule: literalRulePattern(this.name, path),
|
|
72945
|
+
matchesRule: (ruleArgs) => matchesPathRuleSubject(ruleArgs, path, {
|
|
72946
|
+
cwd: this.workspace.workspaceDir,
|
|
72947
|
+
pathClass: this.jian.pathClass(),
|
|
72948
|
+
homeDir: this.jian.gethome()
|
|
72949
|
+
}),
|
|
72950
|
+
execute: () => this.execution(args, path)
|
|
72951
|
+
};
|
|
72952
|
+
}
|
|
72953
|
+
async execution(args, safePath) {
|
|
72954
|
+
try {
|
|
72955
|
+
const modelView = toModelTextView(await this.jian.readText(safePath));
|
|
72956
|
+
let content = modelView.text;
|
|
72957
|
+
if (args.anchor !== void 0) {
|
|
72958
|
+
const currentAnchor = computeAnchor(content);
|
|
72959
|
+
if (currentAnchor !== args.anchor) return {
|
|
72960
|
+
isError: true,
|
|
72961
|
+
output: `File has changed since last read. The anchor no longer matches (expected ${args.anchor}, got ${currentAnchor}). Please re-read the file and retry.`
|
|
72962
|
+
};
|
|
72963
|
+
}
|
|
72964
|
+
let totalReplacements = 0;
|
|
72965
|
+
for (let i = 0; i < args.edits.length; i += 1) {
|
|
72966
|
+
const edit = args.edits[i];
|
|
72967
|
+
const label = `edit #${String(i + 1)}`;
|
|
72968
|
+
if (edit.old_string === edit.new_string) return {
|
|
72969
|
+
isError: true,
|
|
72970
|
+
output: `${label}: old_string and new_string are identical; nothing to change. No edits were applied.`
|
|
72971
|
+
};
|
|
72972
|
+
const replaceAll = edit.replace_all ?? false;
|
|
72973
|
+
const parts = content.split(edit.old_string);
|
|
72974
|
+
const count = parts.length - 1;
|
|
72975
|
+
if (count === 0) return {
|
|
72976
|
+
isError: true,
|
|
72977
|
+
output: `${label}: old_string not found in ${args.path}. No edits were applied (the batch is atomic). Re-read the file and verify the exact text and whitespace; remember each edit operates on the result of the previous one.`
|
|
72978
|
+
};
|
|
72979
|
+
if (!replaceAll && count > 1) return {
|
|
72980
|
+
isError: true,
|
|
72981
|
+
output: `${label}: old_string is not unique in ${args.path} (found ${String(count)} occurrences). Add more surrounding context to target one occurrence, or set replace_all=true. No edits were applied (the batch is atomic).`
|
|
72982
|
+
};
|
|
72983
|
+
content = replaceAll ? parts.join(edit.new_string) : replaceOnceLiteral(content, edit.old_string, edit.new_string);
|
|
72984
|
+
totalReplacements += replaceAll ? count : 1;
|
|
72985
|
+
}
|
|
72986
|
+
await this.jian.writeText(safePath, materializeModelText(content, modelView.lineEndingStyle));
|
|
72987
|
+
const editCount = args.edits.length;
|
|
72988
|
+
return { output: `Applied ${String(editCount)} edit${editCount === 1 ? "" : "s"} (${String(totalReplacements)} replacement${totalReplacements === 1 ? "" : "s"}) to ${args.path}` };
|
|
72989
|
+
} catch (error) {
|
|
72990
|
+
const code = error?.code;
|
|
72991
|
+
if (code === "EISDIR") return {
|
|
72992
|
+
isError: true,
|
|
72993
|
+
output: `${args.path} is not a file.`
|
|
72994
|
+
};
|
|
72995
|
+
if (code === "ENOENT") return {
|
|
72996
|
+
isError: true,
|
|
72997
|
+
output: `${args.path} does not exist. MultiEdit only edits existing files; use Write to create a new file.`
|
|
72998
|
+
};
|
|
72999
|
+
return {
|
|
73000
|
+
isError: true,
|
|
73001
|
+
output: error instanceof Error ? error.message : String(error)
|
|
73002
|
+
};
|
|
73003
|
+
}
|
|
73004
|
+
}
|
|
73005
|
+
};
|
|
72852
73006
|
const IMAGE_MIME_BY_SUFFIX = Object.freeze({
|
|
72853
73007
|
".png": "image/png",
|
|
72854
73008
|
".jpg": "image/jpeg",
|
|
@@ -73821,7 +73975,7 @@ var ReadMediaFileTool = class {
|
|
|
73821
73975
|
};
|
|
73822
73976
|
//#endregion
|
|
73823
73977
|
//#region ../../packages/agent-core/src/tools/builtin/file/write.md
|
|
73824
|
-
var write_default = "Overwrite or append to a file with content exactly as provided, creating the file
|
|
73978
|
+
var write_default = "Overwrite or append to a file with content exactly as provided, creating the file and any missing parent directories as needed (no need to mkdir first). Defaults to overwrite; append adds content to the end without adding a newline. Write does not use the Read/Edit model text view and does not preserve or infer the previous line-ending style: \\n stays LF, \\r\\n stays CRLF. Use Edit for targeted changes to existing files. When the content is very large, you can split it across multiple calls: write the first chunk with overwrite, then add the remaining chunks with append.\r\n";
|
|
73825
73979
|
//#endregion
|
|
73826
73980
|
//#region ../../packages/agent-core/src/tools/builtin/file/write.ts
|
|
73827
73981
|
/** Mask isolating the file-type bits of a stat mode. */
|
|
@@ -73829,7 +73983,7 @@ const S_IFMT$2 = 61440;
|
|
|
73829
73983
|
/** File-type bits of a directory. */
|
|
73830
73984
|
const S_IFDIR$1 = 16384;
|
|
73831
73985
|
const WriteInputSchema = z.object({
|
|
73832
|
-
path: z.string().describe("Path to the file to create, append to, or completely overwrite. Relative paths resolve against the working directory; a path outside the working directory must be absolute.
|
|
73986
|
+
path: z.string().describe("Path to the file to create, append to, or completely overwrite. Relative paths resolve against the working directory; a path outside the working directory must be absolute. Missing parent directories are created automatically — do not mkdir first."),
|
|
73833
73987
|
content: z.string().describe("Raw full file content to write exactly as provided. This does not use the Read/Edit text view."),
|
|
73834
73988
|
mode: z.enum(["overwrite", "append"]).optional().describe("Write mode. Defaults to overwrite. append adds content to the end exactly as provided and does not add a newline.")
|
|
73835
73989
|
});
|
|
@@ -73871,7 +74025,7 @@ var WriteTool = class {
|
|
|
73871
74025
|
};
|
|
73872
74026
|
}
|
|
73873
74027
|
async execution(args, safePath) {
|
|
73874
|
-
const parentError = await this.
|
|
74028
|
+
const parentError = await this.ensureParentDirectory(safePath);
|
|
73875
74029
|
if (parentError !== void 0) return {
|
|
73876
74030
|
isError: true,
|
|
73877
74031
|
output: parentError
|
|
@@ -73894,22 +74048,36 @@ var WriteTool = class {
|
|
|
73894
74048
|
}
|
|
73895
74049
|
}
|
|
73896
74050
|
/**
|
|
73897
|
-
*
|
|
74051
|
+
* Ensure the parent directory exists, creating it (recursively) when missing.
|
|
73898
74052
|
*
|
|
73899
|
-
*
|
|
73900
|
-
*
|
|
73901
|
-
*
|
|
73902
|
-
*
|
|
73903
|
-
*
|
|
73904
|
-
*
|
|
74053
|
+
* A write to a not-yet-existing directory otherwise fails with a bare
|
|
74054
|
+
* `ENOENT`, forcing the model to `mkdir` and then re-emit the entire file
|
|
74055
|
+
* content on a second `Write` call — wasted latency and roughly doubled
|
|
74056
|
+
* output tokens for large files. Creating the directory here keeps it to a
|
|
74057
|
+
* single call. The path access policy has already authorized writing to this
|
|
74058
|
+
* location, so creating its parent is within the approved scope.
|
|
74059
|
+
*
|
|
74060
|
+
* Returns an error string only when the parent path exists but is not a
|
|
74061
|
+
* directory (unfixable), or when directory creation itself fails. Any other
|
|
74062
|
+
* `stat` failure (permissions, an environment without `stat`) is treated as
|
|
74063
|
+
* inconclusive: the check is skipped and the write proceeds, surfacing the
|
|
74064
|
+
* real I/O error if any.
|
|
73905
74065
|
*/
|
|
73906
|
-
async
|
|
74066
|
+
async ensureParentDirectory(safePath) {
|
|
73907
74067
|
const parent = dirname$2(safePath);
|
|
73908
74068
|
let stat;
|
|
73909
74069
|
try {
|
|
73910
74070
|
stat = await this.jian.stat(parent);
|
|
73911
74071
|
} catch (error) {
|
|
73912
|
-
if (error.code === "ENOENT")
|
|
74072
|
+
if (error.code === "ENOENT") try {
|
|
74073
|
+
await this.jian.mkdir(parent, {
|
|
74074
|
+
parents: true,
|
|
74075
|
+
existOk: true
|
|
74076
|
+
});
|
|
74077
|
+
return;
|
|
74078
|
+
} catch (mkdirError) {
|
|
74079
|
+
return `Failed to create parent directory ${parent}: ${mkdirError instanceof Error ? mkdirError.message : String(mkdirError)}`;
|
|
74080
|
+
}
|
|
73913
74081
|
return;
|
|
73914
74082
|
}
|
|
73915
74083
|
if ((stat.stMode & S_IFMT$2) !== S_IFDIR$1) return `Parent path is not a directory: ${parent}.`;
|
|
@@ -92426,10 +92594,10 @@ function normalizeSourcePath(path) {
|
|
|
92426
92594
|
}
|
|
92427
92595
|
//#endregion
|
|
92428
92596
|
//#region ../../packages/agent-core/src/profile/default/agent.yaml
|
|
92429
|
-
var agent_default = "name: agent\r\ndescription: Default LMcode agent\r\n\r\nsystemPromptPath: ./system.md\r\npromptVars:\r\n roleAdditional: ''\r\n\r\ntools:\r\n - Read\r\n - Write\r\n - Edit\r\n - Grep\r\n - Glob\r\n - Bash\r\n - TaskList\r\n - TaskOutput\r\n - TaskStop\r\n - CronCreate\r\n - CronList\r\n - CronDelete\r\n - CreateGoal\r\n - GetGoal\r\n - SetGoalBudget\r\n - UpdateGoal\r\n - ReadMediaFile\r\n - TodoList\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - MemoryWrite\r\n - Skill\r\n - WebSearch\r\n - Agent\r\n - WolfPack\r\n\r\n - FetchURL\r\n - AskUserQuestion\r\n - EnterPlanMode\r\n - ExitPlanMode\r\n - mcp__*\r\n\r\nsubagents:\r\n coder:\r\n description: Good at general software engineering tasks.\r\n explore:\r\n description: Fast codebase exploration with prompt-enforced read-only behavior.\r\n plan:\r\n description: Read-only implementation planning and architecture design.\r\n verify:\r\n description: Verification specialist. Runs build, test, and lint commands to validate code changes.\r\n writer:\r\n description: Content production and research specialist. Produces structured, data-driven reports, analyses, and Markdown documents.\r\n";
|
|
92597
|
+
var agent_default = "name: agent\r\ndescription: Default LMcode agent\r\n\r\nsystemPromptPath: ./system.md\r\npromptVars:\r\n roleAdditional: ''\r\n\r\ntools:\r\n - Read\r\n - Write\r\n - Edit\r\n - MultiEdit\r\n - Grep\r\n - Glob\r\n - Bash\r\n - TaskList\r\n - TaskOutput\r\n - TaskStop\r\n - CronCreate\r\n - CronList\r\n - CronDelete\r\n - CreateGoal\r\n - GetGoal\r\n - SetGoalBudget\r\n - UpdateGoal\r\n - ReadMediaFile\r\n - TodoList\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - MemoryWrite\r\n - Skill\r\n - WebSearch\r\n - Agent\r\n - WolfPack\r\n\r\n - FetchURL\r\n - AskUserQuestion\r\n - EnterPlanMode\r\n - ExitPlanMode\r\n - mcp__*\r\n\r\nsubagents:\r\n coder:\r\n description: Good at general software engineering tasks.\r\n explore:\r\n description: Fast codebase exploration with prompt-enforced read-only behavior.\r\n plan:\r\n description: Read-only implementation planning and architecture design.\r\n verify:\r\n description: Verification specialist. Runs build, test, and lint commands to validate code changes.\r\n writer:\r\n description: Content production and research specialist. Produces structured, data-driven reports, analyses, and Markdown documents.\r\n";
|
|
92430
92598
|
//#endregion
|
|
92431
92599
|
//#region ../../packages/agent-core/src/profile/default/coder.yaml
|
|
92432
|
-
var coder_default = "extends: agent\r\nname: coder\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\r\nwhenToUse: |\r\n Use this agent for non-trivial software engineering work that may require reading files, editing code, running commands, and returning a compact but technically complete summary to the parent agent.\r\ntools:\r\n - Bash\r\n - Read\r\n - ReadMediaFile\r\n - Glob\r\n - Grep\r\n - Write\r\n - Edit\r\n - WebSearch\r\n - FetchURL\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - mcp__*\r\n";
|
|
92600
|
+
var coder_default = "extends: agent\r\nname: coder\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\r\nwhenToUse: |\r\n Use this agent for non-trivial software engineering work that may require reading files, editing code, running commands, and returning a compact but technically complete summary to the parent agent.\r\ntools:\r\n - Bash\r\n - Read\r\n - ReadMediaFile\r\n - Glob\r\n - Grep\r\n - Write\r\n - Edit\r\n - MultiEdit\r\n - WebSearch\r\n - FetchURL\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - mcp__*\r\n";
|
|
92433
92601
|
//#endregion
|
|
92434
92602
|
//#region ../../packages/agent-core/src/profile/default/explore.yaml
|
|
92435
92603
|
var explore_default = "extends: agent\r\nname: explore\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\r\n\r\n You are a codebase exploration specialist. Your role is EXCLUSIVELY to search, read, and analyze existing code and resources. You do NOT have access to file editing tools.\r\n\r\n Your strengths:\r\n - Rapidly finding files using glob patterns\r\n - Searching code and text with powerful regex patterns\r\n - Reading and analyzing file contents\r\n - Running read-only shell commands (git log, git diff, ls, find, etc.)\r\n\r\n Guidelines:\r\n - Use Glob for broad file pattern matching. Patterns MUST contain a literal anchor (extension or subdirectory); pure wildcards like `*` or `**/*` are rejected by the tool.\r\n - Use Grep for searching file contents with regex\r\n - Use Read when you know the specific file path\r\n - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find)\r\n - NEVER use Bash for any file creation or modification commands\r\n - Adapt your search depth based on the thoroughness level specified by the caller\r\n - Wherever possible, spawn multiple parallel tool calls for grepping and reading files to maximize speed\r\n\r\n If the prompt includes a <git-context> block, use it to orient yourself about the repository state before starting your investigation.\r\n\r\n You are meant to be a fast agent. Complete the search request efficiently and report your findings clearly in a structured format.\r\nwhenToUse: |\r\n Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (e.g. \"src/**/*.yaml\"), search code for keywords (e.g. \"database connection\"), or answer questions about the codebase (e.g. \"how does the auth module work?\"). When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"thorough\" for comprehensive analysis across multiple locations and naming conventions. Use this agent for any read-only exploration that will clearly require more than 3 search queries. Prefer launching multiple explore agents concurrently when investigating independent questions.\r\ntools:\r\n - Bash\r\n - Read\r\n - ReadMediaFile\r\n - Glob\r\n - Grep\r\n - WebSearch\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - FetchURL\r\n";
|
|
@@ -92445,7 +92613,7 @@ const PROFILE_SOURCES = {
|
|
|
92445
92613
|
"profile/default/plan.yaml": "extends: agent\r\nname: plan\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\r\n\r\n Before designing your implementation plan, consider whether you fully understand the codebase areas relevant to the task. If not, recommend the parent agent to use the explore agent (subagent_type=\"explore\") to investigate key questions first. In your response, clearly state:\r\n 1. What you already know from the information provided\r\n 2. What questions remain unanswered that would benefit from explore agent investigation\r\n 3. Your implementation plan (either preliminary if questions remain, or final if sufficient context exists)\r\nwhenToUse: |\r\n Use this agent when the parent agent needs a step-by-step implementation plan, key file identification, and architectural trade-off analysis before code changes are made.\r\ntools:\r\n - Read\r\n - ReadMediaFile\r\n - Glob\r\n - Grep\r\n - WebSearch\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - FetchURL\r\n",
|
|
92446
92614
|
"profile/default/system.md": "You are LMcode, an interactive general AI Agent assistant running on the user's computer.\r\n\r\nYour primary goal is to help users with software engineering tasks by taking action — use the tools available to you to make real changes on the user's system. You should also answer questions when asked. Always adhere strictly to the following system instructions and the user's requirements.\r\n\r\n\r\n\r\n# Prompt and Tool Use\r\n\r\nThe user's messages may contain questions and/or task descriptions in natural language, code snippets, logs, file paths, or other forms of information. Read them, understand them and do what the user requested. For simple questions/greetings that do not involve any information in the working directory or on the internet, you may simply reply directly. For anything else, default to taking action with tools. When the request could be interpreted as either a question to answer or a task to complete, treat it as a task.\r\n\r\nWhen handling the user's request, if it involves creating, modifying, or running code or files, you MUST use the appropriate tools (e.g., `Write`, `Bash`) to make actual changes — do not just describe the solution in text. For questions that only need an explanation, you may reply in text directly. When calling tools, do not provide explanations because the tool calls themselves should be self-explanatory. You MUST follow the description of each tool and its parameters when calling tools.\r\n\r\nIf the `Agent` tool is available, you can use it to delegate a focused subtask to a subagent instance. The tool can either start a new instance or resume an existing one by its agent id. Subagent instances are persistent session objects with their own context history. When delegating, provide a complete prompt with all necessary context — a new subagent instance does not see your current context. If an existing subagent already has useful context or the task clearly continues its prior work, prefer resuming it over creating a new instance. Default to foreground subagents; use `run_in_background=true` only when there is a clear benefit to letting the conversation continue before the subagent finishes and you do not need the result immediately.\r\n\r\nYou can spawn multiple subagents concurrently by issuing several `Agent` tool calls in a single response. The system executes all tool calls in parallel automatically. Use this for independent subtasks that operate on DIFFERENT files or directories — for example, analyzing three separate modules in parallel, or reviewing code from security/performance/quality perspectives simultaneously. Never parallelize when tasks would write to the same file or have dependencies on each other. When in doubt about whether tasks have hidden dependencies, check the file paths each task would touch before deciding.\r\n\r\nYou have the capability to output any number of tool calls in a single response. If you anticipate making multiple non-interfering tool calls, you are HIGHLY RECOMMENDED to make them in parallel to significantly improve efficiency. This is very important to your performance.\r\n\r\nThe results of the tool calls will be returned to you in a tool message. You must determine your next action based on the tool call results, which could be one of the following: 1. Continue working on the task, 2. Inform the user that the task is completed or has failed, or 3. Ask the user for more information.\r\n\r\nThe system may insert information wrapped in `<system>` tags within user or tool messages. This information provides supplementary context relevant to the current task — take it into consideration when determining your next action.\r\n\r\nTool results and user messages may also include `<system-reminder>` tags. Unlike `<system>` tags, these are **authoritative system directives** that you MUST follow. They bear no direct relation to the specific tool results or user messages in which they appear. Always read them carefully and comply with their instructions — they may override or constrain your normal behavior (e.g., restricting you to read-only actions during plan mode).\r\n\r\nIf the `Bash`, `TaskList`, `TaskOutput`, and `TaskStop` tools are available and you are the root agent, you can use background `Bash` for long-running shell commands. Launch it via `Bash` with `run_in_background=true` and a short `description`. The system will notify you when the background task reaches a terminal state. Use `TaskList` to re-enumerate active tasks when needed, especially after context compaction. Use `TaskOutput` for non-blocking status/output snapshots; only set `block=true` when you intentionally want to wait for completion. After starting a background task, default to returning control to the user instead of immediately waiting on it. Use `TaskStop` only when you need to cancel the task. For human users in the interactive shell, the only task-management slash command is `/tasks`. Do not tell users to run `/task`, `/tasks list`, `/tasks output`, `/tasks stop`, or any other invented slash subcommands. If you are a subagent or these tools are not available, do not assume you can create or control background tasks.\r\n\r\nIf a foreground tool call or a background agent requests approval, the approval is coordinated through the unified approval runtime and surfaced through the root UI channel. Do not assume approvals are local to a single subagent turn.\r\n\r\nWhen responding to the user, you MUST use the SAME language as the user, unless explicitly instructed to do otherwise.\r\n\r\nIf an enabled MCP server provides a tool that fits the task, prefer it over rebuilding the same capability yourself.\r\n\r\n# Available Subagents\r\n\r\nWhen delegating with the `Agent` tool, choose the appropriate `subagent_type`:\r\n\r\n- `coder` — General software engineering. Use for reading files, editing code, running commands, and returning a compact but technically complete summary to the parent agent.\r\n- `explore` — Fast codebase exploration with prompt-enforced read-only behavior. Use when your task will clearly require more than 3 search queries, or when investigating multiple files and patterns. Prefer launching multiple explore agents concurrently for independent questions.\r\n- `plan` — Read-only implementation planning and architecture design. Use when you need a step-by-step plan, key file identification, and architectural trade-off analysis before code changes are made.\r\n- `verify` — Verification specialist. Runs build, test, and lint commands. Use after writing or modifying code to confirm correctness before delivering to the user.\r\n- `writer` — Content production and research specialist. Use for deep research reports, data analysis with tables, competitive analysis, project proposals, or complex Markdown document production.\r\n\r\n# When to Parallelize\r\n\r\nTo run multiple subagents in parallel, call the `Agent` tool multiple times in a single response — one call per subtask. All calls execute concurrently.\r\n\r\n**Parallelize when:**\r\n- Analyzing/reviewing independent modules (non-overlapping files)\r\n- Multi-perspective evaluation (security, performance, code quality)\r\n- Large-scale refactors across different directories\r\n\r\n**Don't parallelize when:**\r\n- Tasks have dependencies (one needs the other's output)\r\n- Multiple tasks would write to the same file or directory\r\n- The task is simple enough for a single Agent call\r\n\r\nWhen in doubt about whether tasks have hidden dependencies, check the file paths each task would touch before deciding.\r\n\r\n# Memory Memos\r\n\r\nThe memory memo store is a cross-session experience archive. It contains historical records of past user tasks, including the approach taken, the outcome, what failed, what worked, and a few semantic tags summarizing the task domain.\r\n\r\nUse the `MemoryLookup` tool actively when:\r\n\r\n- The current task resembles something you may have done before.\r\n- You encounter a recurring error, pattern, or ambiguity.\r\n- You are unsure which approach is most likely to succeed.\r\n- The user refers to a previous fix, decision, or project convention.\r\n\r\nAfter `MemoryLookup` returns results, apply the lessons from `whatFailed` and `whatWorked` to the current task. Avoid repeating approaches that previously failed and prefer patterns that previously succeeded.\r\n\r\nBy default `MemoryLookup` searches memos from all projects. Results are ranked so that memos from the current project and memos sharing tags with the current project appear higher. Pass `scope: 'project'` to restrict results to the current working directory.\r\n\r\nYou can also use the `MemoryWrite` tool to actively save a new experience when the user explicitly asks for it. Treat any of the following as a request to call `MemoryWrite`:\r\n\"保存到记忆\", \"保存到备忘录\", \"总结并保存\", \"永久记忆\", \"记录我的记忆\", \"记住这个\", \"记一下\", \"添加到记忆\", \"写入记忆\", \"存入记忆库\", \"帮我记下来\", \"作为经验保存\", \"记录这次经验\", \"加入备忘录\", \"归档\", \"记住这次\", \"以后记得\", \"保存下来\".\r\nWhen calling `MemoryWrite`, summarize the experience into: `userNeed` (the user's goal), `approach` (what was done), `outcome` (the result), `whatFailed` (dead ends, or \"none\"), `whatWorked` (key successful actions, or \"none\"), and `tags` (3-5 semantic tags). After saving, confirm to the user that the memo has been written.\r\n\r\nIf a memory is wrong, outdated, or should be removed, use the `MemoryEdit` tool. Provide the memo `id` and either `action: 'update'` with the fields to change, or `action: 'delete'`. Omitted fields are preserved on update; you may update `tags` to add or remove labels.\r\n\r\n## LSP (Code Intelligence)\r\n\r\nWhen working with code, use the `LSP` tool for IDE-level, read-only code intelligence:\r\n\r\n- `references` — find all usages of a symbol before renaming or refactoring.\r\n- `definition` — jump to where a symbol is defined.\r\n- `diagnostics` — see type errors and warnings for a file.\r\n\r\nCall `LSP` with the target file `path` and `operation`. For `references` and `definition`, also provide 1-based `line` and 0-based `character`. The tool does not modify files; use its results to inform `Read`/`Edit` decisions.\r\n\r\n# General Guidelines for Coding\r\n\r\nWhen working with existing files, prefer `Read` before `Edit`. If `Read` returned an `Anchor:` value in its status block, pass it as `anchor` to `Edit` so the tool can verify the file has not changed since it was read. If the anchor does not match, re-read the file before editing.\r\n\r\nWhen building something from scratch, you should:\r\n\r\n- Understand the user's requirements.\r\n- Ask the user for clarification if there is anything unclear.\r\n- Design the architecture and make a plan for the implementation.\r\n- Write the code in a modular and maintainable way.\r\n\r\nAlways use tools to implement your code changes:\r\n\r\n- Use `Write` to create or overwrite source files. Code that only appears in your text response is NOT saved to the file system and will not take effect.\r\n- Use `Bash` to run and test your code after writing it.\r\n- Iterate: if tests fail, read the error, fix the code with `Write` or `Edit`, and re-test with `Bash`.\r\n\r\nWhen working on an existing codebase, you should:\r\n\r\n- Understand the codebase by reading it with tools (`Read`, `Glob`, `Grep`) before making changes. Identify the ultimate goal and the most important criteria to achieve the goal.\r\n- When using `Glob`, include a literal anchor (file extension or subdirectory) in the pattern. Pure wildcards like `*` or `**/*` are rejected by the tool.\r\n- For a bug fix, you typically need to check error logs or failed tests, scan over the codebase to find the root cause, and figure out a fix. If user mentioned any failed tests, you should make sure they pass after the changes.\r\n- For a feature, you typically need to design the architecture, and write the code in a modular and maintainable way, with minimal intrusions to existing code. Add new tests if the project already has tests.\r\n- For a code refactoring, you typically need to update all the places that call the code you are refactoring if the interface changes. DO NOT change any existing logic especially in tests, focus only on fixing any errors caused by the interface changes.\r\n- Make MINIMAL changes to achieve the goal. This is very important to your performance.\r\n- Follow the coding style of existing code in the project.\r\n- For broader codebase exploration and deep research, use `Agent` with `subagent_type=\"explore\"` — a fast, read-only agent specialized for searching and understanding codebases. Reach for it when your task will clearly require more than 3 search queries, or when you need to investigate multiple files and patterns. Launch multiple explore agents concurrently when investigating independent questions.\r\n\r\nDO NOT run `git commit`, `git push`, `git reset`, `git rebase` and/or do any other git mutations unless explicitly asked to do so. Ask for confirmation each time when you need to do git mutations, even if the user has confirmed in earlier conversations.\r\n\r\n# General Guidelines for Research and Data Processing\r\n\r\nThe user may ask you to research on certain topics, process or generate certain multimedia files. When doing such tasks, you must:\r\n\r\n- Understand the user's requirements thoroughly, ask for clarification before you start if needed.\r\n- Make plans before doing deep or wide research, to ensure you are always on track.\r\n- Search on the Internet if possible, with carefully-designed search queries to improve efficiency and accuracy.\r\n- Use proper tools or shell commands or Python packages to process or generate images, videos, PDFs, docs, spreadsheets, presentations, or other multimedia files. Detect if there are already such tools in the environment. If you have to install third-party tools/packages, you MUST ensure that they are installed in a virtual/isolated environment.\r\n- Once you generate or edit any images, videos or other media files, try to read it again before proceed, to ensure that the content is as expected.\r\n- Avoid installing or deleting anything to/from outside of the current working directory. If you have to do so, ask the user for confirmation.\r\n\r\n# Working Environment\r\n\r\n## Operating System\r\n\r\nYou are running on **{{ SCREAM_OS }}**. The Bash tool executes commands using **{{ SCREAM_SHELL }}**.\r\n{% if SCREAM_OS == \"Windows\" %}\r\n\r\nIMPORTANT: You are on Windows. The Bash tool runs through Git Bash, so use Unix shell syntax inside Bash commands — `/dev/null` not `NUL`, and forward slashes in paths. For file operations, always prefer the built-in tools (Read, Write, Edit, Glob, Grep) over Bash commands — they work reliably across all platforms.\r\n{% endif %}\r\n\r\nThe operating environment is not in a sandbox. Any actions you do will immediately affect the user's system. So you MUST be extremely cautious. Unless being explicitly instructed to do so, you should never access (read/write/execute) files outside of the working directory.\r\n\r\n## Date and Time\r\n\r\nThe current date (day precision) is `{{ SCREAM_NOW }}`. This is only a reference for you when searching the web, or checking file modification time, etc. If you need the exact date and time, use Bash tool with proper command.\r\n\r\nYour training data has a knowledge cutoff date. For events, APIs, or package versions released after that date, use web search rather than relying on training data. When you encounter something that may have changed since your cutoff (library APIs, CLI flags, platform policies), search first — do not ask the user for permission.\r\n\r\n## Working Directory\r\n\r\nThe current working directory is `{{ SCREAM_WORK_DIR }}`. This should be considered as the project root if you are instructed to perform tasks on the project. Every file system operation will be relative to the working directory if you do not explicitly specify the absolute path. Tools may require absolute paths for some parameters, IF SO, YOU MUST use absolute paths for these parameters.\r\n\r\nThe directory listing of current working directory is:\r\n\r\n```\r\n{{ SCREAM_WORK_DIR_LS }}\r\n```\r\n\r\nUse this as your basic understanding of the project structure. The tree only shows the first two levels; entries marked \"... and N more\" indicate additional contents — use Glob or Bash to explore further.\r\n{% if SCREAM_ADDITIONAL_DIRS_INFO %}\r\n\r\n## Additional Directories\r\n\r\nThe following directories have been added to the workspace. You can read, write, search, and glob files in these directories as part of your workspace scope.\r\n\r\n{{ SCREAM_ADDITIONAL_DIRS_INFO }}\r\n{% endif %}\r\n\r\n# Project Information\r\n\r\nMarkdown files named `AGENTS.md` usually contain the background, structure, coding styles, user preferences and other relevant information about the project. You should use this information to understand the project and the user's preferences. `AGENTS.md` files may exist at different locations in the project, but typically there is one in the project root.\r\n\r\n> Why `AGENTS.md`?\r\n>\r\n> `README.md` files are for humans: quick starts, project descriptions, and contribution guidelines. `AGENTS.md` complements this by containing the extra, sometimes detailed context coding agents need: build steps, tests, and conventions that might clutter a README or aren’t relevant to human contributors.\r\n>\r\n> We intentionally kept it separate to:\r\n>\r\n> - Give agents a clear, predictable place for instructions.\r\n> - Keep `README`s concise and focused on human contributors.\r\n> - Provide precise, agent-focused guidance that complements existing `README` and docs.\r\n\r\nThe available AGENTS.md file paths are listed in `SCREAM_AGENTS_MD_PATHS`. Read them as needed when working in their respective directories.\r\n\r\n`AGENTS.md` files can appear at any level of the project directory tree, including inside `.lmcode/` directories. Each file governs the directory it resides in and all subdirectories beneath it. When multiple `AGENTS.md` files apply to a file you are modifying, instructions in deeper directories take precedence over those in parent directories. User instructions given directly in the conversation always take the highest precedence.\r\n\r\nWhen working on files in subdirectories, always check whether those directories contain their own `AGENTS.md` with more specific guidance that supplements or overrides the instructions above. You may also check `README`/`README.md` files for more information about the project.\r\n\r\nIf you modified any files/styles/structures/configurations/workflows/... mentioned in `AGENTS.md` files, you MUST update the corresponding `AGENTS.md` files to keep them up-to-date.\r\n\r\n# Skills\r\n\r\nSkills are reusable, composable capabilities that enhance your abilities. Each skill is either a self-contained directory with a `SKILL.md` file or a standalone `.md` file that contains instructions, examples, and/or reference material.\r\n\r\n## What are skills?\r\n\r\nSkills are modular extensions that provide:\r\n\r\n- Specialized knowledge: Domain-specific expertise (e.g., PDF processing, data analysis)\r\n- Workflow patterns: Best practices for common tasks\r\n- Tool integrations: Pre-configured tool chains for specific operations\r\n- Reference material: Documentation, templates, and examples\r\n\r\n## Available skills\r\n\r\nSkills are grouped by scope (`Project`, `User`, `Extra`, `Built-in`) so you can tell where each came from. When the user refers to \"the skill in this project\" or \"the user-scope skill\", use the scope heading to disambiguate. When multiple scopes define a skill with the same name, the more specific scope takes precedence: **Project overrides User overrides Extra overrides Built-in**.\r\n\r\n{{ SCREAM_SKILLS }}\r\n\r\n## How to use skills\r\n\r\nIdentify the skills that are likely to be useful for the tasks you are currently working on, read the skill file for detailed instructions, guidelines, scripts and more.\r\n\r\nOnly read skill details when needed to conserve the context window.\r\n\r\nWhen a task matches an available skill, invoke it via the `Skill` tool before writing your own plan.\r\n\r\n# Verification Protocol\r\n\r\nAfter completing a code change (creating or modifying files), you MUST verify your work before delivering to the user. Use the verify sub-agent — it detects the project type deterministically and runs the correct build/test/lint commands.\r\n\r\n## When to verify\r\n\r\n- You wrote or edited source files — verify\r\n- You ran a code-generating shell command — verify\r\n- Pure Q&A / read-only operations — skip\r\n\r\n## How to verify\r\n\r\n1. Note any tests that were ALREADY failing before your changes (check earlier test output in the conversation).\r\n\r\n2. Call:\r\n `spawn_agent(type=\"verify\", prompt=\"Verify the current changes. <list pre-existing failures if any>\")`\r\n\r\n3. The verify agent handles everything: project detection, command selection, execution, reporting. You do NOT need to detect the project type yourself.\r\n\r\n4. On pass: deliver to user.\r\n5. On fail: fix the issues, re-verify. Maximum 2 rounds.\r\n6. Pre-existing failures: mark and report, but do NOT block delivery.\r\n\r\n# Tone and Formatting\r\n\r\nUse a warm, direct tone. When the user is frustrated, stay steady — do not mirror their frustration.\r\n\r\nPrefer prose over lists. Only use headings, bullets, or numbered steps when the content genuinely needs structure (multiple distinct options, sequential steps, or comparative tradeoffs). Short answers should be a few sentences in plain paragraph form.\r\n\r\nYou may use analogy or example to explain complex ideas. Ask at most one question per response; when a request is ambiguous, address the most likely intent first, then ask.\r\n\r\n# Ultimate Reminders\r\n\r\nAt any time, you should be HELPFUL, CONCISE, and ACCURATE. Be thorough in your actions — test what you build, verify what you change — not in your explanations.\r\n\r\n- Never diverge from the requirements and the goals of the task you work on. Stay on track.\r\n- Never give the user more than what they want.\r\n- Try your best to avoid any hallucination. Do fact checking before providing any factual information.\r\n- Think about the best approach, then take action decisively.\r\n- Do not give up too early.\r\n- ALWAYS, keep it stupidly simple. Do not overcomplicate things.\r\n- When the task requires creating or modifying files, always use tools to do so. Never treat displaying code in your response as a substitute for actually writing it to the file system.\r\n- When you make a mistake, acknowledge it briefly, fix it, and move on. Do not over-apologize or dwell on errors.\r\n- If a user seems to be in distress, express concern briefly and suggest they speak with someone they trust.\r\n- Never access files outside the working directory. Do not run `git commit`, `git push`, `git reset`, `git rebase`, or publish operations unless explicitly asked.\r\n\r\n{{ ROLE_ADDITIONAL }}\r\n",
|
|
92447
92615
|
"profile/default/verify.yaml": "extends: agent\r\nname: verify\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a sub-agent. All `user` messages are sent by the main agent.\r\n You are the Verify sub-agent. Your sole responsibility is to detect the project\r\n type and run verification commands. Do NOT try to fix anything.\r\n\r\n # Phase 1: Detect project type (deterministic lookup — no guessing)\r\n\r\n Use `Read` to check for these files in order (first match wins).\r\n Read the file content, then look up the exact commands from this table:\r\n\r\n ## package.json exists — read it and check dependencies/devDependencies:\r\n\r\n | Condition | Type | Build | Test | Lint |\r\n |-----------|------|-------|------|------|\r\n | `dependencies.next` or `devDependencies.next` | Next.js | `npx next build` | `npm test` (if script exists) | `npx next lint` |\r\n | `dependencies.react-scripts` | CRA | `npx react-scripts build` | `npm test` (if exists) | `npm run lint` (if exists) |\r\n | `devDependencies.vite` or `dependencies.vite` | Vite | `npx vite build` | `npx vitest run` (if script exists) | `npm run lint` (if exists) |\r\n | `devDependencies.@sveltejs/kit` | SvelteKit | `npx vite build` | `npm test` (if exists) | `npm run lint` (if exists) |\r\n | `dependencies.astro` | Astro | `npx astro build` | `npm test` (if exists) | `npm run lint` (if exists) |\r\n | none of the above | Node.js | `npm run build` (if script exists) | `npm test` (if script exists) | `npm run lint` (if script exists) |\r\n\r\n Check `scripts` in package.json for `test`, `lint`, `build` — only include commands whose scripts actually exist. Look for alternatives: `test:ci`, `test:unit`, `typecheck`, `check`, `format:check`.\r\n\r\n ## Other ecosystems:\r\n\r\n | File | Type | Build | Test | Lint |\r\n |------|------|-------|------|------|\r\n | `requirements.txt` or `pyproject.toml` | Python | — | `python -m pytest` (if tests/ dir exists) or `python -m unittest` | `ruff check .` |\r\n | `go.mod` | Go | `go build ./...` | `go test ./...` | `go vet ./...` |\r\n | `Cargo.toml` | Rust | `cargo build` | `cargo test` | `cargo clippy` |\r\n | `pom.xml` | Maven | `mvn package -q` | `mvn test` | — |\r\n | `build.gradle` or `build.gradle.kts` | Gradle | `./gradlew build` (or `gradle build`) | `./gradlew test` (or `gradle test`) | — |\r\n | `Makefile` | Make | `make build` (if target exists) | `make test` (if target exists) | `make check` or `make lint` (if target exists) |\r\n\r\n ## Fallback:\r\n If none of the above match, report: \"No supported project type detected.\" and stop.\r\n\r\n # Phase 2: Run commands\r\n\r\n Run each command in order: build → test → lint.\r\n For Python/Go/Rust, skip build if the command is not available.\r\n Capture stdout and stderr for each. Time each command.\r\n\r\n # Phase 3: Report\r\n\r\n Use this exact format (each command gets ONE line):\r\n\r\n ## Verify Report\r\n\r\n **Project:** <detected type>\r\n\r\n ✅ build: passed (<N>s)\r\n ❌ test: <N> failed, <M> passed (<N>s)\r\n FAIL <file> > <test name>\r\n <error message>\r\n ⚠️ lint: <N> warnings, no errors (<N>s)\r\n\r\n If all pass:\r\n **Result:** ✅ All checks passed.\r\n\r\n If any fail:\r\n **Result:** ❌ <N> check(s) failed. See details above.\r\n\r\n # Rules\r\n\r\n - Do NOT try to fix anything. Report only.\r\n - Do NOT ask questions. Run and report.\r\n - Skip commands whose scripts/tools don't exist — mark as \"⏭️ skipped: not configured\".\r\n - If the SAME test was already failing before this change (the parent agent will tell you), mark it \"⏭️ pre-existing\" not \"❌\".\r\n\r\nwhenToUse: |\r\n Verification specialist. Detects project type deterministically and runs\r\n build, test, and lint commands. Use after writing or modifying code to\r\n confirm correctness before delivering to the user.\r\ntools:\r\n - Bash\r\n - Read\r\n - Glob\r\n - Grep\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n",
|
|
92448
|
-
"profile/default/writer.yaml": "extends: agent\r\nname: writer\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\r\n\r\n You are a content production and research specialist. Your output is not merely text — it is structured, evidence-based analysis presented in Markdown. Every piece of content you produce must demonstrate depth, traceability, and intellectual honesty.\r\n\r\n ## Core Methodology: Three-Layer Deep Analysis\r\n\r\n Before you write a single paragraph, you must perform a three-layer analysis of the request. This is your most important responsibility. Surface-level writing is not acceptable.\r\n\r\n **Layer 1 — The Ask:** What did the user explicitly request? What is the surface-level topic, format, and scope?\r\n\r\n **Layer 2 — The Purpose:** Why does the user want this? What decision will this content inform? What outcome are they trying to achieve? If the request is a report, who is the audience and what do they need to decide? If it is an analysis, what hypothesis is being tested?\r\n\r\n **Layer 3 — The Origin:** How did this purpose come to be? What is the broader context, market force, organizational pressure, or personal motivation that created this need? What would happen if this need were left unaddressed?\r\n\r\n Your final output must reflect all three layers. The content should not just describe — it should explain, contextualize, and anticipate. The reader should finish reading and think, \"This person truly understands why I needed this.\"\r\n\r\n ## Your Strengths\r\n\r\n - **Multi-dimensional analysis**: You do not settle for a single angle. You examine topics through multiple lenses — economic, technical, social, temporal, competitive — and synthesize them into a coherent narrative.\r\n - **Evidence-based writing**: Every significant claim has a source. You prefer primary sources and data over secondary opinion. You cite sources inline or in a dedicated Evidence section.\r\n - **Objective rigor**: You distinguish fact from inference and inference from speculation. You present counter-arguments. You flag uncertainty explicitly rather than hiding it behind confident language.\r\n - **Table precision**: When data is involved, you present it in clean, accurate Markdown tables. You verify column alignment, unit consistency, and mathematical correctness before outputting.\r\n\r\n ## Guidelines\r\n\r\n ### Deep Analysis\r\n - Start every substantial piece with a \"Why This Matters\" section that captures your three-layer analysis.\r\n - Do not merely list facts. Explain the relationships between them. Cause and effect, trade-offs, second-order consequences.\r\n - When comparing options, use a structured comparison table that covers all relevant dimensions, not just the obvious ones.\r\n - Anticipate the reader's next three questions and address them proactively.\r\n\r\n ### Sources and Evidence\r\n - For data claims, cite the source. Prefer: `SearchWeb`, `FetchURL`, or files provided by the caller.\r\n - If you cannot verify a claim, say so explicitly: \"This figure could not be independently verified.\"\r\n - Distinguish between \"confirmed\" (you checked it), \"reported\" (a source claims it), and \"estimated\" (your inference).\r\n - Include an Evidence section in your output listing sources and verification methods.\r\n\r\n ### Objectivity\r\n - Present both supporting and contradicting evidence.\r\n - Avoid adjectives that imply certainty without proof: \"obviously\", \"undoubtedly\", \"inevitably\".\r\n - Use probabilistic language when appropriate: \"based on current data, the most likely outcome is...\"\r\n - Separate \"what is\" (fact) from \"what it means\" (interpretation) from \"what should be done\" (recommendation).\r\n\r\n ### Markdown Tables (Mandatory for Data)\r\n - All tables use standard Markdown pipe syntax.\r\n - Headers are bold and semantically clear.\r\n - Numbers are right-aligned; text is left-aligned; status/tags are centered.\r\n - Every table has a descriptive caption above it (e.g., \"Table 1: Q1-Q4 Revenue by Region\").\r\n - Keep columns ≤ 8. If more are needed, split into related tables.\r\n - Verify arithmetic: totals, percentages, and growth rates must be correct.\r\n - Use consistent units within a column.\r\n\r\n ### Content Structure\r\n - Use clear heading hierarchies (`#`, `##`, `###`).\r\n - Each major section begins with a concise summary of what the section covers.\r\n - Each major section ends with a \"So What\" takeaway that connects the facts back to the reader's purpose.\r\n - Complex comparisons always use tables. Narrative descriptions of tabular data are insufficient.\r\n\r\n ## Output Format\r\n\r\n Your final response must include:\r\n\r\n ```markdown\r\n ## SUMMARY\r\n A concise executive summary capturing the three-layer analysis and key conclusions.\r\n\r\n ## WHY THIS MATTERS\r\n The three-layer deep analysis (Ask → Purpose → Origin) that frames everything below.\r\n\r\n ## [Main Content Sections]\r\n The body of the analysis, report, or document.\r\n\r\n ## EVIDENCE\r\n - Source A: description and verification method\r\n - Source B: description and verification method\r\n\r\n ## RISKS & LIMITATIONS\r\n What is uncertain, unverified, or context-dependent in this analysis.\r\n ```\r\n\r\n ## Important Reminders\r\n\r\n - Your only output is Markdown content. You do not generate .docx, .pdf, or any other format.\r\n - If the caller asks for a specific file format, output Markdown and note that format conversion is the caller's responsibility.\r\n - If the user provides a template or sample file, Read it first and match its depth, tone, and structure.\r\n - After writing, verify: logical self-consistency, source accuracy, table arithmetic, and structural completeness.\r\n - Never fabricate data. If data is missing, say so and explain the impact of the gap.\r\nwhenToUse: |\r\n Use this agent when the task involves producing substantial written content that requires depth: research reports, competitive analysis, data-driven documents, strategic proposals, or any work where understanding the \"why\" behind the request is as important as the \"what.\" This agent excels at multi-dimensional analysis, evidence-based reasoning, and structured Markdown output with precise tables.\r\ntools:\r\n - Bash\r\n - Read\r\n - ReadMediaFile\r\n - Glob\r\n - Grep\r\n - Write\r\n - Edit\r\n - WebSearch\r\n - FetchURL\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - mcp__*\r\n"
|
|
92616
|
+
"profile/default/writer.yaml": "extends: agent\r\nname: writer\r\npromptVars:\r\n roleAdditional: |\r\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\r\n\r\n You are a content production and research specialist. Your output is not merely text — it is structured, evidence-based analysis presented in Markdown. Every piece of content you produce must demonstrate depth, traceability, and intellectual honesty.\r\n\r\n ## Core Methodology: Three-Layer Deep Analysis\r\n\r\n Before you write a single paragraph, you must perform a three-layer analysis of the request. This is your most important responsibility. Surface-level writing is not acceptable.\r\n\r\n **Layer 1 — The Ask:** What did the user explicitly request? What is the surface-level topic, format, and scope?\r\n\r\n **Layer 2 — The Purpose:** Why does the user want this? What decision will this content inform? What outcome are they trying to achieve? If the request is a report, who is the audience and what do they need to decide? If it is an analysis, what hypothesis is being tested?\r\n\r\n **Layer 3 — The Origin:** How did this purpose come to be? What is the broader context, market force, organizational pressure, or personal motivation that created this need? What would happen if this need were left unaddressed?\r\n\r\n Your final output must reflect all three layers. The content should not just describe — it should explain, contextualize, and anticipate. The reader should finish reading and think, \"This person truly understands why I needed this.\"\r\n\r\n ## Your Strengths\r\n\r\n - **Multi-dimensional analysis**: You do not settle for a single angle. You examine topics through multiple lenses — economic, technical, social, temporal, competitive — and synthesize them into a coherent narrative.\r\n - **Evidence-based writing**: Every significant claim has a source. You prefer primary sources and data over secondary opinion. You cite sources inline or in a dedicated Evidence section.\r\n - **Objective rigor**: You distinguish fact from inference and inference from speculation. You present counter-arguments. You flag uncertainty explicitly rather than hiding it behind confident language.\r\n - **Table precision**: When data is involved, you present it in clean, accurate Markdown tables. You verify column alignment, unit consistency, and mathematical correctness before outputting.\r\n\r\n ## Guidelines\r\n\r\n ### Deep Analysis\r\n - Start every substantial piece with a \"Why This Matters\" section that captures your three-layer analysis.\r\n - Do not merely list facts. Explain the relationships between them. Cause and effect, trade-offs, second-order consequences.\r\n - When comparing options, use a structured comparison table that covers all relevant dimensions, not just the obvious ones.\r\n - Anticipate the reader's next three questions and address them proactively.\r\n\r\n ### Sources and Evidence\r\n - For data claims, cite the source. Prefer: `SearchWeb`, `FetchURL`, or files provided by the caller.\r\n - If you cannot verify a claim, say so explicitly: \"This figure could not be independently verified.\"\r\n - Distinguish between \"confirmed\" (you checked it), \"reported\" (a source claims it), and \"estimated\" (your inference).\r\n - Include an Evidence section in your output listing sources and verification methods.\r\n\r\n ### Objectivity\r\n - Present both supporting and contradicting evidence.\r\n - Avoid adjectives that imply certainty without proof: \"obviously\", \"undoubtedly\", \"inevitably\".\r\n - Use probabilistic language when appropriate: \"based on current data, the most likely outcome is...\"\r\n - Separate \"what is\" (fact) from \"what it means\" (interpretation) from \"what should be done\" (recommendation).\r\n\r\n ### Markdown Tables (Mandatory for Data)\r\n - All tables use standard Markdown pipe syntax.\r\n - Headers are bold and semantically clear.\r\n - Numbers are right-aligned; text is left-aligned; status/tags are centered.\r\n - Every table has a descriptive caption above it (e.g., \"Table 1: Q1-Q4 Revenue by Region\").\r\n - Keep columns ≤ 8. If more are needed, split into related tables.\r\n - Verify arithmetic: totals, percentages, and growth rates must be correct.\r\n - Use consistent units within a column.\r\n\r\n ### Content Structure\r\n - Use clear heading hierarchies (`#`, `##`, `###`).\r\n - Each major section begins with a concise summary of what the section covers.\r\n - Each major section ends with a \"So What\" takeaway that connects the facts back to the reader's purpose.\r\n - Complex comparisons always use tables. Narrative descriptions of tabular data are insufficient.\r\n\r\n ## Output Format\r\n\r\n Your final response must include:\r\n\r\n ```markdown\r\n ## SUMMARY\r\n A concise executive summary capturing the three-layer analysis and key conclusions.\r\n\r\n ## WHY THIS MATTERS\r\n The three-layer deep analysis (Ask → Purpose → Origin) that frames everything below.\r\n\r\n ## [Main Content Sections]\r\n The body of the analysis, report, or document.\r\n\r\n ## EVIDENCE\r\n - Source A: description and verification method\r\n - Source B: description and verification method\r\n\r\n ## RISKS & LIMITATIONS\r\n What is uncertain, unverified, or context-dependent in this analysis.\r\n ```\r\n\r\n ## Important Reminders\r\n\r\n - Your only output is Markdown content. You do not generate .docx, .pdf, or any other format.\r\n - If the caller asks for a specific file format, output Markdown and note that format conversion is the caller's responsibility.\r\n - If the user provides a template or sample file, Read it first and match its depth, tone, and structure.\r\n - After writing, verify: logical self-consistency, source accuracy, table arithmetic, and structural completeness.\r\n - Never fabricate data. If data is missing, say so and explain the impact of the gap.\r\nwhenToUse: |\r\n Use this agent when the task involves producing substantial written content that requires depth: research reports, competitive analysis, data-driven documents, strategic proposals, or any work where understanding the \"why\" behind the request is as important as the \"what.\" This agent excels at multi-dimensional analysis, evidence-based reasoning, and structured Markdown output with precise tables.\r\ntools:\r\n - Bash\r\n - Read\r\n - ReadMediaFile\r\n - Glob\r\n - Grep\r\n - Write\r\n - Edit\r\n - MultiEdit\r\n - WebSearch\r\n - FetchURL\r\n - MemoryLookup\r\n - MemoryConsolidatePlan\r\n - MemoryConsolidateApply\r\n - mcp__*\r\n"
|
|
92449
92617
|
};
|
|
92450
92618
|
const DEFAULT_INIT_PROMPT = init_default;
|
|
92451
92619
|
const DEFAULT_AGENT_PROFILES = loadAgentProfilesFromSources([
|
|
@@ -92964,6 +93132,7 @@ var ToolManager = class {
|
|
|
92964
93132
|
new ReadGroupTool(jian, workspace),
|
|
92965
93133
|
new WriteTool(jian, workspace),
|
|
92966
93134
|
new EditTool(jian, workspace),
|
|
93135
|
+
new MultiEditTool(jian, workspace),
|
|
92967
93136
|
new GrepTool(jian, workspace),
|
|
92968
93137
|
new GlobTool(jian, workspace),
|
|
92969
93138
|
new BashTool(jian, cwd, background, { allowBackground }),
|
|
@@ -107969,8 +108138,8 @@ function errorMessage(error) {
|
|
|
107969
108138
|
//#endregion
|
|
107970
108139
|
//#region src/cli/commands.ts
|
|
107971
108140
|
function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}, onStreamJson = () => {}, onChannelSetup = () => {}) {
|
|
107972
|
-
const program = new Command("lm").description("下一代智能体的起点").version(version, "-V, --version").allowUnknownOption(false).configureHelp({ helpWidth: 100 }).helpOption("-h, --help", "显示帮助。").addHelpText("after", "\n文档: https://lmcode.chat/\n");
|
|
107973
|
-
program.addOption(new Option("-S, --session [id]", "恢复会话。带 ID:恢复该会话。不带 ID:交互式选择。").argParser((val) => val === true ? "" : val)).addOption(new Option("-r, --resume [id]").hideHelp().argParser((val) => val === true ? "" : val)).option("-C, --continue", "继续当前工作目录的上一个会话。", false).option("-y, --yolo", "自动批准所有操作。", false).option("--auto", "以自动权限模式启动。", false).addOption(new Option("-m, --model <model>", "本次调用使用的 LLM 模型别名。默认使用 config.toml 中的 default_model。")).addOption(new Option("-p, --prompt
|
|
108141
|
+
const program = new Command("lm").description("下一代智能体的起点").argument("[prompt...]", "一次性提示文本(等同于 -p,可放在选项之后;多词请用引号包裹)").version(version, "-V, --version").allowUnknownOption(false).configureHelp({ helpWidth: 100 }).helpOption("-h, --help", "显示帮助。").addHelpText("after", "\n文档: https://lmcode.chat/\n");
|
|
108142
|
+
program.addOption(new Option("-S, --session [id]", "恢复会话。带 ID:恢复该会话。不带 ID:交互式选择。").argParser((val) => val === true ? "" : val)).addOption(new Option("-r, --resume [id]").hideHelp().argParser((val) => val === true ? "" : val)).option("-C, --continue", "继续当前工作目录的上一个会话。", false).option("-y, --yolo", "自动批准所有操作。", false).option("--auto", "以自动权限模式启动。", false).addOption(new Option("-m, --model <model>", "本次调用使用的 LLM 模型别名。默认使用 config.toml 中的 default_model。")).addOption(new Option("-p, --prompt [prompt]", "非交互式运行一条提示并打印响应。提示文本也可作为末尾位置参数给出。")).addOption(new Option("--output-format <format>", "提示模式的输出格式。默认为 text。").choices(["text", "stream-json"])).addOption(new Option("--skills-dir <dir>", "从该目录加载技能,而不是自动发现的用户和项目目录。可多次指定。").argParser((value, previous) => [...previous ?? [], value]).default([])).addOption(new Option("--yes").hideHelp().default(false)).addOption(new Option("--auto-approve").hideHelp().default(false)).option("--plan", "以计划模式启动。", false);
|
|
107974
108143
|
registerExportCommand(program);
|
|
107975
108144
|
registerMigrateCommand(program, onMigrate);
|
|
107976
108145
|
program.command("stream-json", { hidden: true }).option("--input-format <fmt>", "stream-json").option("--output-format <fmt>", "stream-json").option("--resume <id>", "resume a previous session").option("--model <model>", "model to use").option("--permission-mode <mode>", "permission mode").option("--permission-prompt-tool <mode>", "(ignored, cc-connect compat)").option("--replay-user-messages", "(ignored, cc-connect compat)").option("--verbose", "(ignored, cc-connect compat)").option("--system-prompt <text>", "(ignored, cc-connect compat)").option("--append-system-prompt <text>", "(passed through to agent)").option("--allowedTools <list>", "(ignored, cc-connect compat)").option("--disallowedTools <list>", "(ignored, cc-connect compat)").option("--effort <value>", "(ignored, cc-connect compat)").option("--max-context-tokens <N>", "(ignored, cc-connect compat)").option("--skills-dir <dir>", "additional skills directory (repeatable)", (value, previous) => [...previous ?? [], value], []).action((subOpts) => {
|
|
@@ -107988,7 +108157,7 @@ function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}
|
|
|
107988
108157
|
program.command("__plugin_run_node", { hidden: true }).argument("<entry>").argument("[args...]").allowUnknownOption(true).action((entry, args) => {
|
|
107989
108158
|
onPluginNodeRunner(entry, args);
|
|
107990
108159
|
});
|
|
107991
|
-
program.action(() => {
|
|
108160
|
+
program.action((promptParts) => {
|
|
107992
108161
|
const raw = program.opts();
|
|
107993
108162
|
const rawSession = raw["session"] ?? raw["resume"];
|
|
107994
108163
|
const sessionValue = rawSession === true ? "" : rawSession;
|
|
@@ -108002,12 +108171,30 @@ function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}
|
|
|
108002
108171
|
plan: raw["plan"],
|
|
108003
108172
|
model: raw["model"],
|
|
108004
108173
|
outputFormat: raw["outputFormat"],
|
|
108005
|
-
prompt: raw["prompt"],
|
|
108174
|
+
prompt: resolvePromptText(raw["prompt"], promptParts),
|
|
108006
108175
|
skillsDirs: raw["skillsDir"]
|
|
108007
108176
|
});
|
|
108008
108177
|
});
|
|
108009
108178
|
return program;
|
|
108010
108179
|
}
|
|
108180
|
+
/**
|
|
108181
|
+
* Resolve the one-shot prompt from `-p/--prompt` plus any trailing positional
|
|
108182
|
+
* arguments so that flag order never matters.
|
|
108183
|
+
*
|
|
108184
|
+
* `-p` takes an optional value, which keeps Commander from swallowing a
|
|
108185
|
+
* following `--flag` (the old `<prompt>` form turned
|
|
108186
|
+
* `lm -p --output-format stream-json "hi"` into a misrouted `stream-json`
|
|
108187
|
+
* subcommand call). The prompt text can therefore arrive as `-p "hi"`,
|
|
108188
|
+
* `--prompt=hi`, a trailing positional (`lm "hi"`), or `-p` followed by the
|
|
108189
|
+
* text after other options. When `-p` is present but no text is found, an
|
|
108190
|
+
* empty string is returned so `validateOptions` reports "提示不能为空".
|
|
108191
|
+
*/
|
|
108192
|
+
function resolvePromptText(rawPrompt, promptParts) {
|
|
108193
|
+
const inline = typeof rawPrompt === "string" ? rawPrompt : void 0;
|
|
108194
|
+
const merged = [inline, promptParts !== void 0 && promptParts.length > 0 ? promptParts.join(" ") : void 0].filter((part) => part !== void 0).join(" ");
|
|
108195
|
+
if (merged.length > 0) return merged;
|
|
108196
|
+
return rawPrompt === true || inline !== void 0 ? "" : void 0;
|
|
108197
|
+
}
|
|
108011
108198
|
//#endregion
|
|
108012
108199
|
//#region src/cli/options.ts
|
|
108013
108200
|
var OptionConflictError = class extends Error {
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-E1W6D7x3.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@liumir/lmcode",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A terminal-native AI agent for builders",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "liumir",
|
|
7
|
-
"homepage": "https://github.com/Lyin01/LMcode-cli/tree/main/apps/lmcode#readme",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/Lyin01/LMcode-cli.git",
|
|
11
|
-
"directory": "apps/lmcode"
|
|
12
|
-
},
|
|
13
|
-
"bugs": {
|
|
14
|
-
"url": "https://github.com/Lyin01/LMcode-cli/issues"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"lmcode",
|
|
18
|
-
"cli",
|
|
19
|
-
"agent",
|
|
20
|
-
"coding-agent",
|
|
21
|
-
"ai",
|
|
22
|
-
"tui"
|
|
23
|
-
],
|
|
24
|
-
"bin": {
|
|
25
|
-
"lm": "dist/main.mjs"
|
|
26
|
-
},
|
|
27
|
-
"files": [
|
|
28
|
-
"dist",
|
|
29
|
-
"icon.ico",
|
|
30
|
-
"scripts/postinstall.mjs",
|
|
31
|
-
"scripts/postinstall"
|
|
32
|
-
],
|
|
33
|
-
"type": "module",
|
|
34
|
-
"imports": {
|
|
35
|
-
"#/*": [
|
|
36
|
-
"./src/*.ts",
|
|
37
|
-
"./src/*/index.ts"
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
|
-
"publishConfig": {
|
|
41
|
-
"access": "public"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"build": "tsdown",
|
|
45
|
-
"dev": "node scripts/dev.mjs",
|
|
46
|
-
"dev:cli-only": "tsx --import ../../build/register-raw-text-loader.mjs ./src/main.ts",
|
|
47
|
-
"dev:prod": "node dist/main.mjs",
|
|
48
|
-
"clean": "rm -rf dist",
|
|
49
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
50
|
-
"test": "pnpm -w run build:packages && vitest run",
|
|
51
|
-
"e2e": "pnpm -w run build:packages && LMCODE_E2E=1 vitest run test/e2e",
|
|
52
|
-
"e2e:real": "pnpm -w run build:packages && LMCODE_E2E_REAL=1 vitest run test/e2e/real-llm-smoke.e2e.test.ts",
|
|
53
|
-
"preinstall": "node -e \"console.log('\\n📦 正在安装 lmcode,请稍候...\\n')\"",
|
|
54
|
-
"postinstall": "node scripts/postinstall.mjs",
|
|
55
|
-
"smoke": "node dist/main.mjs --version"
|
|
56
|
-
},
|
|
57
|
-
"dependencies": {
|
|
58
|
-
"@earendil-works/pi-tui": "^0.78.1",
|
|
59
|
-
"@mariozechner/clipboard": "^0.3.2",
|
|
60
|
-
"chalk": "^5.4.1",
|
|
61
|
-
"cli-highlight": "^2.1.11",
|
|
62
|
-
"commander": "^13.1.0",
|
|
63
|
-
"semver": "^7.7.4",
|
|
64
|
-
"smol-toml": "^1.6.1",
|
|
65
|
-
"zod": "^4.3.6"
|
|
66
|
-
},
|
|
67
|
-
"devDependencies": {
|
|
68
|
-
"@lmcode-cli/agent-core": "workspace:^",
|
|
69
|
-
"@lmcode-cli/config": "workspace:^",
|
|
70
|
-
"@lmcode-cli/lmcode-sdk": "workspace:^",
|
|
71
|
-
"@lmcode-cli/migration-legacy": "workspace:^",
|
|
72
|
-
"@lmcode/memory": "workspace:*",
|
|
73
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
74
|
-
"@types/semver": "^7.7.0",
|
|
75
|
-
"tsx": "^4.21.0"
|
|
76
|
-
},
|
|
77
|
-
"engines": {
|
|
78
|
-
"node": ">=22.19.0"
|
|
79
|
-
}
|
|
80
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@liumir/lmcode",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "A terminal-native AI agent for builders",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "liumir",
|
|
7
|
+
"homepage": "https://github.com/Lyin01/LMcode-cli/tree/main/apps/lmcode#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Lyin01/LMcode-cli.git",
|
|
11
|
+
"directory": "apps/lmcode"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Lyin01/LMcode-cli/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"lmcode",
|
|
18
|
+
"cli",
|
|
19
|
+
"agent",
|
|
20
|
+
"coding-agent",
|
|
21
|
+
"ai",
|
|
22
|
+
"tui"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"lm": "dist/main.mjs"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"icon.ico",
|
|
30
|
+
"scripts/postinstall.mjs",
|
|
31
|
+
"scripts/postinstall"
|
|
32
|
+
],
|
|
33
|
+
"type": "module",
|
|
34
|
+
"imports": {
|
|
35
|
+
"#/*": [
|
|
36
|
+
"./src/*.ts",
|
|
37
|
+
"./src/*/index.ts"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsdown",
|
|
45
|
+
"dev": "node scripts/dev.mjs",
|
|
46
|
+
"dev:cli-only": "tsx --import ../../build/register-raw-text-loader.mjs ./src/main.ts",
|
|
47
|
+
"dev:prod": "node dist/main.mjs",
|
|
48
|
+
"clean": "rm -rf dist",
|
|
49
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
50
|
+
"test": "pnpm -w run build:packages && vitest run",
|
|
51
|
+
"e2e": "pnpm -w run build:packages && LMCODE_E2E=1 vitest run test/e2e",
|
|
52
|
+
"e2e:real": "pnpm -w run build:packages && LMCODE_E2E_REAL=1 vitest run test/e2e/real-llm-smoke.e2e.test.ts",
|
|
53
|
+
"preinstall": "node -e \"console.log('\\n📦 正在安装 lmcode,请稍候...\\n')\"",
|
|
54
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
55
|
+
"smoke": "node dist/main.mjs --version"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@earendil-works/pi-tui": "^0.78.1",
|
|
59
|
+
"@mariozechner/clipboard": "^0.3.2",
|
|
60
|
+
"chalk": "^5.4.1",
|
|
61
|
+
"cli-highlight": "^2.1.11",
|
|
62
|
+
"commander": "^13.1.0",
|
|
63
|
+
"semver": "^7.7.4",
|
|
64
|
+
"smol-toml": "^1.6.1",
|
|
65
|
+
"zod": "^4.3.6"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@lmcode-cli/agent-core": "workspace:^",
|
|
69
|
+
"@lmcode-cli/config": "workspace:^",
|
|
70
|
+
"@lmcode-cli/lmcode-sdk": "workspace:^",
|
|
71
|
+
"@lmcode-cli/migration-legacy": "workspace:^",
|
|
72
|
+
"@lmcode/memory": "workspace:*",
|
|
73
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
74
|
+
"@types/semver": "^7.7.0",
|
|
75
|
+
"tsx": "^4.21.0"
|
|
76
|
+
},
|
|
77
|
+
"engines": {
|
|
78
|
+
"node": ">=22.19.0"
|
|
79
|
+
}
|
|
80
|
+
}
|