jeo-code 0.4.4 → 0.4.5
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.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/package.json +1 -1
- package/src/agent/engine.ts +7 -3
- package/src/agent/subagents.ts +1 -1
- package/src/agent/tools.ts +62 -0
package/README.ja.md
CHANGED
|
@@ -150,11 +150,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
150
150
|
## 変更履歴 (Changelog)
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.4.5]** (2026-06-14) — First-class filesystem make/remove tools.
|
|
153
154
|
- **[0.4.4]** (2026-06-13) — Live subagent status mirroring, always-useful Ctrl+O activity tail, read lineRange crash guard.
|
|
154
155
|
- **[0.4.3]** (2026-06-13) — Readability pass for autopilot, subagent activity, and worked-history review.
|
|
155
156
|
- **[0.4.2]** (2026-06-13) — Thinking-loop termination guarantees (cycle guard + turn wall-clock budget), unboxed live status without step counters, self-contained `.jeo` namespace, live next-prompt input card, role-targeted model/thinking picker.
|
|
156
157
|
- **[0.4.1]** (2026-06-12) — TUI card parity polish + done-time todo reconciliation.
|
|
157
|
-
- **[0.4.0]** (2026-06-12) — Verified TUI, resilient engine, batch input, multilingual docs.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -150,11 +150,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
150
150
|
## 변경 이력 (Changelog)
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.4.5]** (2026-06-14) — First-class filesystem make/remove tools.
|
|
153
154
|
- **[0.4.4]** (2026-06-13) — Live subagent status mirroring, always-useful Ctrl+O activity tail, read lineRange crash guard.
|
|
154
155
|
- **[0.4.3]** (2026-06-13) — Readability pass for autopilot, subagent activity, and worked-history review.
|
|
155
156
|
- **[0.4.2]** (2026-06-13) — Thinking-loop termination guarantees (cycle guard + turn wall-clock budget), unboxed live status without step counters, self-contained `.jeo` namespace, live next-prompt input card, role-targeted model/thinking picker.
|
|
156
157
|
- **[0.4.1]** (2026-06-12) — TUI card parity polish + done-time todo reconciliation.
|
|
157
|
-
- **[0.4.0]** (2026-06-12) — Verified TUI, resilient engine, batch input, multilingual docs.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -150,11 +150,11 @@ Required npm token permissions (repository secret `NPM_TOKEN`):
|
|
|
150
150
|
## Changelog
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.4.5]** (2026-06-14) — First-class filesystem make/remove tools.
|
|
153
154
|
- **[0.4.4]** (2026-06-13) — Live subagent status mirroring, always-useful Ctrl+O activity tail, read lineRange crash guard.
|
|
154
155
|
- **[0.4.3]** (2026-06-13) — Readability pass for autopilot, subagent activity, and worked-history review.
|
|
155
156
|
- **[0.4.2]** (2026-06-13) — Thinking-loop termination guarantees (cycle guard + turn wall-clock budget), unboxed live status without step counters, self-contained `.jeo` namespace, live next-prompt input card, role-targeted model/thinking picker.
|
|
156
157
|
- **[0.4.1]** (2026-06-12) — TUI card parity polish + done-time todo reconciliation.
|
|
157
|
-
- **[0.4.0]** (2026-06-12) — Verified TUI, resilient engine, batch input, multilingual docs.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -150,11 +150,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
150
150
|
## 更新日志 (Changelog)
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.4.5]** (2026-06-14) — First-class filesystem make/remove tools.
|
|
153
154
|
- **[0.4.4]** (2026-06-13) — Live subagent status mirroring, always-useful Ctrl+O activity tail, read lineRange crash guard.
|
|
154
155
|
- **[0.4.3]** (2026-06-13) — Readability pass for autopilot, subagent activity, and worked-history review.
|
|
155
156
|
- **[0.4.2]** (2026-06-13) — Thinking-loop termination guarantees (cycle guard + turn wall-clock budget), unboxed live status without step counters, self-contained `.jeo` namespace, live next-prompt input card, role-targeted model/thinking picker.
|
|
156
157
|
- **[0.4.1]** (2026-06-12) — TUI card parity polish + done-time todo reconciliation.
|
|
157
|
-
- **[0.4.0]** (2026-06-12) — Verified TUI, resilient engine, batch input, multilingual docs.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
package/src/agent/engine.ts
CHANGED
|
@@ -11,7 +11,7 @@ import * as fs from "node:fs/promises";
|
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import type { Message } from "./loop";
|
|
13
13
|
import { extractJsonObject } from "./json";
|
|
14
|
-
import { readTool, writeTool, editTool, bashTool, findTool, searchTool, lsTool, type ToolResult } from "./tools";
|
|
14
|
+
import { readTool, writeTool, editTool, bashTool, findTool, searchTool, lsTool, mkdirTool, deleteTool, type ToolResult } from "./tools";
|
|
15
15
|
import { webSearchTool, setWebSearchActiveModel } from "./web-search";
|
|
16
16
|
import { friendlyProviderError, isContextOverflowError, isRefusalError } from "../util/provider-error";
|
|
17
17
|
import { isRateLimitError } from "../util/retry";
|
|
@@ -50,6 +50,8 @@ export const DEFAULT_TOOLS: Record<string, ToolHandler> = {
|
|
|
50
50
|
find: (a, cwd) => findTool(a.globPattern ?? a.pattern, cwd),
|
|
51
51
|
search: (a, cwd) => searchTool(a.pattern, a.globPattern ?? "*", cwd, !!(a.ignoreCase ?? a.i), { before: a.before, after: a.after, context: a.context, maxMatches: a.maxMatches }),
|
|
52
52
|
ls: (a, cwd) => lsTool(a.dirPath ?? a.path ?? a.dir ?? ".", cwd),
|
|
53
|
+
mkdir: (a, cwd) => mkdirTool(a.dirPath ?? a.path ?? a.dir, cwd),
|
|
54
|
+
delete: (a, cwd) => deleteTool(a.path ?? a.filePath ?? a.targetPath ?? a.dirPath, cwd, !!(a.recursive ?? a.r)),
|
|
53
55
|
web_search: (a, cwd) => webSearchTool(a, cwd),
|
|
54
56
|
};
|
|
55
57
|
|
|
@@ -63,8 +65,10 @@ export const TOOL_PROTOCOL = [
|
|
|
63
65
|
"5. find {globPattern} — find files by name",
|
|
64
66
|
"6. search {pattern, globPattern?, ignoreCase?, context?, maxMatches?} — grep (context: N lines around each match)",
|
|
65
67
|
"7. ls {dirPath} — list a directory's entries (dirs first)",
|
|
66
|
-
"8.
|
|
67
|
-
"9.
|
|
68
|
+
"8. mkdir {dirPath} — create a directory (parents included; idempotent)",
|
|
69
|
+
"9. delete {path, recursive?} — remove a file (or directory with recursive:true)",
|
|
70
|
+
"10. web_search {query, recency?, limit?} — search the web (Anthropic-native: synthesized answer + sources + citations)",
|
|
71
|
+
"11. done {reason?} — call when the task is fully implemented AND verified",
|
|
68
72
|
"",
|
|
69
73
|
"Reply with STRICT JSON only — no code fences. You MAY include an optional leading",
|
|
70
74
|
'"reasoning" string (one short sentence on your plan) before "tool":',
|
package/src/agent/subagents.ts
CHANGED
|
@@ -233,7 +233,7 @@ export function bashCommandAllowed(command: string, prefixes: string[]): boolean
|
|
|
233
233
|
*/
|
|
234
234
|
export function subagentToolset(role: SubagentRole): Record<string, ToolHandler> {
|
|
235
235
|
if (role.readOnly) {
|
|
236
|
-
const MUTATING = new Set(["write", "edit", "bash"]);
|
|
236
|
+
const MUTATING = new Set(["write", "edit", "bash", "mkdir", "delete"]);
|
|
237
237
|
const ro: Record<string, ToolHandler> = {};
|
|
238
238
|
for (const [name, handler] of Object.entries(DEFAULT_TOOLS)) {
|
|
239
239
|
if (MUTATING.has(name)) continue;
|
package/src/agent/tools.ts
CHANGED
|
@@ -812,3 +812,65 @@ export async function lsTool(
|
|
|
812
812
|
return { success: false, output: "", error: err.message };
|
|
813
813
|
}
|
|
814
814
|
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Create a directory (and any missing parents). Idempotent: an already-existing
|
|
818
|
+
* directory is a success, not an error — the model should not need to branch on
|
|
819
|
+
* existence. Respects the deep-interview mutation lock like write/edit.
|
|
820
|
+
*/
|
|
821
|
+
export async function mkdirTool(
|
|
822
|
+
dirPath: string,
|
|
823
|
+
cwd: string = process.cwd()
|
|
824
|
+
): Promise<ToolResult> {
|
|
825
|
+
try {
|
|
826
|
+
if (typeof dirPath !== "string" || dirPath.trim() === "") {
|
|
827
|
+
return { success: false, output: "", error: 'mkdir requires a non-empty "dirPath".' };
|
|
828
|
+
}
|
|
829
|
+
await assertMutationAllowed(dirPath, cwd);
|
|
830
|
+
const abs = path.resolve(cwd, dirPath);
|
|
831
|
+
const existing = await fs.stat(abs).catch(() => null);
|
|
832
|
+
if (existing && !existing.isDirectory()) {
|
|
833
|
+
return { success: false, output: "", error: `Path exists and is not a directory: ${dirPath}` };
|
|
834
|
+
}
|
|
835
|
+
await fs.mkdir(abs, { recursive: true });
|
|
836
|
+
return { success: true, output: `Directory ready: ${dirPath}` };
|
|
837
|
+
} catch (err: any) {
|
|
838
|
+
return { success: false, output: "", error: err.message };
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Delete a file or directory. A directory requires `recursive: true` so a stray
|
|
844
|
+
* call cannot wipe a populated tree by accident. Missing paths are a soft error
|
|
845
|
+
* (nothing to delete) rather than a crash. Respects the mutation lock like
|
|
846
|
+
* write/edit; the file-freshness snapshot is cleared so a later write to the
|
|
847
|
+
* same path is not rejected as stale.
|
|
848
|
+
*/
|
|
849
|
+
export async function deleteTool(
|
|
850
|
+
targetPath: string,
|
|
851
|
+
cwd: string = process.cwd(),
|
|
852
|
+
recursive: boolean = false
|
|
853
|
+
): Promise<ToolResult> {
|
|
854
|
+
try {
|
|
855
|
+
if (typeof targetPath !== "string" || targetPath.trim() === "") {
|
|
856
|
+
return { success: false, output: "", error: 'delete requires a non-empty "path".' };
|
|
857
|
+
}
|
|
858
|
+
await assertMutationAllowed(targetPath, cwd);
|
|
859
|
+
const abs = path.resolve(cwd, targetPath);
|
|
860
|
+
if (abs === path.resolve(cwd)) {
|
|
861
|
+
return { success: false, output: "", error: "Refusing to delete the working directory itself." };
|
|
862
|
+
}
|
|
863
|
+
const st = await fs.stat(abs).catch(() => null);
|
|
864
|
+
if (!st) {
|
|
865
|
+
return { success: false, output: "", error: `Nothing to delete: ${targetPath} (does not exist).` };
|
|
866
|
+
}
|
|
867
|
+
if (st.isDirectory() && !recursive) {
|
|
868
|
+
return { success: false, output: "", error: `${targetPath} is a directory — pass recursive:true to remove it and its contents.` };
|
|
869
|
+
}
|
|
870
|
+
await fs.rm(abs, { recursive, force: false });
|
|
871
|
+
lastReadSnapshots.delete(abs); // a future write to this path must not be flagged stale
|
|
872
|
+
return { success: true, output: `Deleted ${st.isDirectory() ? "directory" : "file"}: ${targetPath}` };
|
|
873
|
+
} catch (err: any) {
|
|
874
|
+
return { success: false, output: "", error: err.message };
|
|
875
|
+
}
|
|
876
|
+
}
|