minimal-agent 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +136 -60
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -4,6 +4,19 @@
4
4
  import { render } from "ink";
5
5
  import { createRequire } from "module";
6
6
 
7
+ // src/bootstrap/workingDir.ts
8
+ import { resolve } from "path";
9
+ var _workingDir = null;
10
+ function initWorkingDir() {
11
+ if (_workingDir !== null) return _workingDir;
12
+ const override = process.env.MINIMAL_AGENT_CWD;
13
+ _workingDir = resolve(override ?? process.cwd());
14
+ return _workingDir;
15
+ }
16
+ function getWorkingDir() {
17
+ return _workingDir ?? initWorkingDir();
18
+ }
19
+
7
20
  // src/config/configFile.ts
8
21
  import { chmod, mkdir, readFile, writeFile } from "fs/promises";
9
22
  import { homedir } from "os";
@@ -111,16 +124,51 @@ async function loadProviderLayered() {
111
124
  }
112
125
 
113
126
  // src/context/persistContext.ts
114
- import { mkdir as mkdir2, readFile as readFile2, unlink, writeFile as writeFile2 } from "fs/promises";
127
+ import { mkdir as mkdir3, readFile as readFile2, unlink, writeFile as writeFile2 } from "fs/promises";
128
+ import { dirname as dirname3 } from "path";
129
+
130
+ // src/context/sessionPath.ts
131
+ import { createHash } from "crypto";
132
+ import { mkdir as mkdir2, rename, stat } from "fs/promises";
115
133
  import { homedir as homedir2 } from "os";
116
- import { dirname as dirname2, join as join2 } from "path";
134
+ import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
135
+ function sessionFileFor(cwd) {
136
+ const normalized = resolve2(cwd).replace(/\\/g, "/").toLowerCase();
137
+ const sanitized = normalized.replace(/:/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
138
+ const hash = createHash("sha1").update(normalized).digest("hex").slice(0, 6);
139
+ return join2(
140
+ homedir2(),
141
+ ".minimal-agent",
142
+ "sessions",
143
+ `${sanitized}-${hash}.json`
144
+ );
145
+ }
146
+ async function migrateLegacyContext(cwd) {
147
+ const legacy = join2(homedir2(), ".minimal-agent", "last-context.json");
148
+ try {
149
+ await stat(legacy);
150
+ } catch {
151
+ return;
152
+ }
153
+ const target = sessionFileFor(cwd);
154
+ try {
155
+ await mkdir2(dirname2(target), { recursive: true });
156
+ await rename(legacy, target);
157
+ } catch {
158
+ }
159
+ }
160
+
161
+ // src/context/persistContext.ts
117
162
  function getContextPath() {
118
- return process.env.MINIMAL_AGENT_CONTEXT_FILE ?? join2(homedir2(), ".minimal-agent", "last-context.json");
163
+ if (process.env.MINIMAL_AGENT_CONTEXT_FILE) {
164
+ return process.env.MINIMAL_AGENT_CONTEXT_FILE;
165
+ }
166
+ return sessionFileFor(getWorkingDir());
119
167
  }
120
- async function loadContext() {
121
- const file = getContextPath();
168
+ async function loadContext(file) {
169
+ const target = file ?? getContextPath();
122
170
  try {
123
- const raw = await readFile2(file, "utf8");
171
+ const raw = await readFile2(target, "utf8");
124
172
  const data = JSON.parse(raw);
125
173
  if (!Array.isArray(data.messages)) return null;
126
174
  return data.messages;
@@ -128,19 +176,19 @@ async function loadContext() {
128
176
  return null;
129
177
  }
130
178
  }
131
- async function saveContext(messages) {
132
- const file = getContextPath();
179
+ async function saveContext(messages, file) {
180
+ const target = file ?? getContextPath();
133
181
  try {
134
- await mkdir2(dirname2(file), { recursive: true });
182
+ await mkdir3(dirname3(target), { recursive: true });
135
183
  const data = { updatedAt: Date.now(), messages };
136
- await writeFile2(file, JSON.stringify(data), "utf8");
184
+ await writeFile2(target, JSON.stringify(data), "utf8");
137
185
  } catch {
138
186
  }
139
187
  }
140
- async function clearContext() {
141
- const file = getContextPath();
188
+ async function clearContext(file) {
189
+ const target = file ?? getContextPath();
142
190
  try {
143
- await unlink(file);
191
+ await unlink(target);
144
192
  } catch {
145
193
  }
146
194
  }
@@ -177,20 +225,20 @@ import { join as join4 } from "path";
177
225
 
178
226
  // src/utils/packageRoot.ts
179
227
  import { existsSync } from "fs";
180
- import { dirname as dirname3, resolve } from "path";
228
+ import { dirname as dirname4, resolve as resolve3 } from "path";
181
229
  import { fileURLToPath } from "url";
182
230
  var cache = /* @__PURE__ */ new Map();
183
231
  var MAX_DEPTH = 8;
184
232
  function findPackageRoot(metaUrl) {
185
233
  const cached2 = cache.get(metaUrl);
186
234
  if (cached2 !== void 0) return cached2;
187
- let dir = dirname3(fileURLToPath(metaUrl));
235
+ let dir = dirname4(fileURLToPath(metaUrl));
188
236
  for (let i = 0; i < MAX_DEPTH; i++) {
189
- if (existsSync(resolve(dir, "package.json"))) {
237
+ if (existsSync(resolve3(dir, "package.json"))) {
190
238
  cache.set(metaUrl, dir);
191
239
  return dir;
192
240
  }
193
- const parent = dirname3(dir);
241
+ const parent = dirname4(dir);
194
242
  if (parent === dir) break;
195
243
  dir = parent;
196
244
  }
@@ -249,10 +297,14 @@ function formatSkillHint(skills) {
249
297
  const lines = [];
250
298
  lines.push("# \u53EF\u7528\u6280\u80FD\uFF08/\u547D\u4EE4\uFF09");
251
299
  lines.push("");
300
+ lines.push(`> Skills \u6839\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF1A\`${SKILLS_DIR}\``);
301
+ lines.push("");
252
302
  lines.push(
253
303
  "\u4EE5\u4E0B\u662F\u5F53\u524D\u53EF\u7528\u7684\u6280\u80FD\u3002**\u5F53\u7528\u6237\u610F\u56FE\u5339\u914D\u67D0\u4E2A\u6280\u80FD\u7684\u89E6\u53D1\u65F6\u673A\u65F6\uFF0C\u4F60\u5E94\u8BE5\u4E3B\u52A8\u4F7F\u7528\u5B83**\u3002"
254
304
  );
255
- lines.push("\u5728\u4F7F\u7528\u524D\uFF0C\u5148\u7528 Read \u5DE5\u5177\u8BFB\u53D6 `skills/{name}/SKILL.md` \u4E86\u89E3\u5B8C\u6574\u6D41\u7A0B\u3002");
305
+ lines.push(
306
+ `\u5728\u4F7F\u7528\u524D\uFF0C\u5148\u7528 Read \u5DE5\u5177\u8BFB\u53D6 \`${SKILLS_DIR}/{name}/SKILL.md\` \u4E86\u89E3\u5B8C\u6574\u6D41\u7A0B\u3002`
307
+ );
256
308
  lines.push("");
257
309
  for (const skill of skills) {
258
310
  const type = skill.type ?? "prompt\uFF08\u5C55\u5F00\u4E3A\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF0C\u6307\u5BFC\u6A21\u578B\u6267\u884C\u590D\u6742\u4EFB\u52A1\uFF09";
@@ -261,15 +313,17 @@ function formatSkillHint(skills) {
261
313
  lines.push(`- **\u89E6\u53D1\u65F6\u673A**: ${triggers}`);
262
314
  lines.push(`- **\u529F\u80FD**: ${skill.description}`);
263
315
  lines.push(`- **\u7C7B\u578B**: ${type}`);
316
+ lines.push(`- **\u6280\u80FD\u76EE\u5F55**: \`${SKILLS_DIR}/${skill.name}/\``);
264
317
  lines.push("");
265
318
  }
266
319
  lines.push("## \u6280\u80FD\u8C03\u7528\u6D41\u7A0B");
267
320
  lines.push("");
268
321
  lines.push("```");
269
322
  lines.push("1. \u5728 T \u9636\u6BB5\u5224\u65AD\u7528\u6237\u610F\u56FE\u662F\u5426\u5339\u914D\u67D0\u4E2A\u6280\u80FD\u7684\u89E6\u53D1\u65F6\u673A");
270
- lines.push("2. \u5339\u914D \u2192 \u5728 A \u9636\u6BB5\u7528 Read \u5DE5\u5177\u8BFB\u53D6 skills/{name}/SKILL.md");
323
+ lines.push(`2. \u5339\u914D \u2192 \u5728 A \u9636\u6BB5\u7528 Read \u5DE5\u5177\u8BFB\u53D6 ${SKILLS_DIR}/{name}/SKILL.md`);
271
324
  lines.push("3. \u6309\u7167 SKILL.md \u7684 Quick Reference \u548C\u6D41\u7A0B\u6267\u884C");
272
- lines.push("4. \u5982\u679C\u6280\u80FD\u7C7B\u578B\u662F prompt\uFF0C\u5C06\u5176\u5185\u5BB9\u4F5C\u4E3A\u989D\u5916\u4E0A\u4E0B\u6587\u6307\u5BFC\u540E\u7EED\u64CD\u4F5C");
325
+ lines.push("4. \u6280\u80FD\u811A\u672C\uFF08scripts/\uFF09\u4E0E SKILL.md \u4F4D\u4E8E\u540C\u4E00\u76EE\u5F55\u4E0B\uFF0C\u7528\u7EDD\u5BF9\u8DEF\u5F84\u6267\u884C");
326
+ lines.push("5. \u5982\u679C\u6280\u80FD\u7C7B\u578B\u662F prompt\uFF0C\u5C06\u5176\u5185\u5BB9\u4F5C\u4E3A\u989D\u5916\u4E0A\u4E0B\u6587\u6307\u5BFC\u540E\u7EED\u64CD\u4F5C");
273
327
  lines.push("```");
274
328
  lines.push("");
275
329
  lines.push("> \u{1F4A1} \u6280\u80FD\u662F\u5DE5\u5177\u7684\u7EC4\u5408\u62F3\u3002\u5355\u4E2A\u5DE5\u5177\u662F\u57FA\u7840\u64CD\u4F5C\uFF1B\u6280\u80FD\u662F\u9488\u5BF9\u7279\u5B9A\u573A\u666F\u7684\u6807\u51C6\u5316\u5DE5\u4F5C\u6D41\u3002");
@@ -561,7 +615,7 @@ async function call(input, signal) {
561
615
  await new Promise((resolveP, rejectP) => {
562
616
  const child = spawn(command, {
563
617
  shell: true,
564
- cwd: process.cwd(),
618
+ cwd: getWorkingDir(),
565
619
  signal: ac.signal,
566
620
  env: process.env,
567
621
  windowsHide: true
@@ -639,9 +693,9 @@ var bashTool = {
639
693
  };
640
694
 
641
695
  // src/tools/edit/edit.ts
642
- import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
696
+ import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
643
697
  import { existsSync as existsSync2 } from "fs";
644
- import { dirname as dirname4, resolve as resolve2 } from "path";
698
+ import { dirname as dirname5, resolve as resolve4 } from "path";
645
699
  import { z as z2 } from "zod";
646
700
  var MAX_EDIT_FILE_SIZE_BYTES = 1024 * 1024 * 1024;
647
701
  var inputSchema2 = z2.object({
@@ -674,7 +728,7 @@ function validatePath(filePath) {
674
728
  return { ok: true };
675
729
  }
676
730
  async function call2(input) {
677
- const filePath = resolve2(input.file_path);
731
+ const filePath = resolve4(input.file_path);
678
732
  const { old_string, new_string } = input;
679
733
  const replaceAll = input.replace_all ?? false;
680
734
  const pathCheck = validatePath(filePath);
@@ -684,7 +738,7 @@ async function call2(input) {
684
738
  }
685
739
  if (old_string === "" && !existsSync2(filePath)) {
686
740
  try {
687
- await mkdir3(dirname4(filePath), { recursive: true });
741
+ await mkdir4(dirname5(filePath), { recursive: true });
688
742
  await writeFile3(filePath, new_string, "utf8");
689
743
  return {
690
744
  ok: true,
@@ -839,8 +893,8 @@ var editTool = {
839
893
  };
840
894
 
841
895
  // src/tools/glob/glob.ts
842
- import { stat } from "fs/promises";
843
- import { isAbsolute, resolve as resolve3 } from "path";
896
+ import { stat as stat2 } from "fs/promises";
897
+ import { isAbsolute, resolve as resolve5 } from "path";
844
898
  import fg from "fast-glob";
845
899
  import { z as z3 } from "zod";
846
900
  var inputSchema3 = z3.object({
@@ -854,7 +908,7 @@ var description3 = `- Fast file pattern matching tool that works with any codeba
854
908
  - Use this tool when you need to find files by name patterns
855
909
  - When you need to do an open ended search that may require multiple rounds, prefer the Grep tool for content search`;
856
910
  async function call3(input) {
857
- const cwd = input.path ? resolve3(input.path) : process.cwd();
911
+ const cwd = input.path ? resolve5(input.path) : getWorkingDir();
858
912
  const pattern = input.pattern.replace(/\\/g, "/");
859
913
  let matches;
860
914
  try {
@@ -875,9 +929,9 @@ async function call3(input) {
875
929
  }
876
930
  const withMtime = await Promise.all(
877
931
  matches.map(async (rel) => {
878
- const abs = isAbsolute(rel) ? rel : resolve3(cwd, rel);
932
+ const abs = isAbsolute(rel) ? rel : resolve5(cwd, rel);
879
933
  try {
880
- const st = await stat(abs);
934
+ const st = await stat2(abs);
881
935
  return { path: rel, mtime: st.mtimeMs };
882
936
  } catch {
883
937
  return { path: rel, mtime: 0 };
@@ -911,13 +965,13 @@ var globTool = {
911
965
 
912
966
  // src/tools/grep/grep.ts
913
967
  import { spawn as spawn3 } from "child_process";
914
- import { resolve as resolve5 } from "path";
968
+ import { resolve as resolve7 } from "path";
915
969
  import { z as z4 } from "zod";
916
970
 
917
971
  // src/tools/grep/rgPath.ts
918
972
  import { spawn as spawn2 } from "child_process";
919
973
  import { chmodSync, existsSync as existsSync3 } from "fs";
920
- import { resolve as resolve4 } from "path";
974
+ import { resolve as resolve6 } from "path";
921
975
  var cached;
922
976
  async function resolveRgPath() {
923
977
  if (cached !== void 0) return cached;
@@ -944,7 +998,7 @@ async function detect() {
944
998
  function vendoredRgPath() {
945
999
  try {
946
1000
  const projectRoot = findPackageRoot(import.meta.url);
947
- return resolve4(projectRoot, "vendor", "ripgrep", subdir(), exeName());
1001
+ return resolve6(projectRoot, "vendor", "ripgrep", subdir(), exeName());
948
1002
  } catch {
949
1003
  return null;
950
1004
  }
@@ -1003,26 +1057,26 @@ function claudeCodeCandidates() {
1003
1057
  const npmRoots = [];
1004
1058
  if (platform === "win32") {
1005
1059
  if (process.env.APPDATA) {
1006
- npmRoots.push(resolve4(process.env.APPDATA, "npm", "node_modules"));
1060
+ npmRoots.push(resolve6(process.env.APPDATA, "npm", "node_modules"));
1007
1061
  }
1008
1062
  if (process.env.USERPROFILE) {
1009
1063
  npmRoots.push(
1010
- resolve4(process.env.USERPROFILE, "AppData", "Roaming", "npm", "node_modules")
1064
+ resolve6(process.env.USERPROFILE, "AppData", "Roaming", "npm", "node_modules")
1011
1065
  );
1012
1066
  }
1013
1067
  } else {
1014
1068
  const home = process.env.HOME ?? "";
1015
1069
  if (home) {
1016
- npmRoots.push(resolve4(home, ".npm-global", "lib", "node_modules"));
1017
- npmRoots.push(resolve4(home, ".npm", "lib", "node_modules"));
1018
- npmRoots.push(resolve4(home, "node_modules"));
1070
+ npmRoots.push(resolve6(home, ".npm-global", "lib", "node_modules"));
1071
+ npmRoots.push(resolve6(home, ".npm", "lib", "node_modules"));
1072
+ npmRoots.push(resolve6(home, "node_modules"));
1019
1073
  }
1020
1074
  npmRoots.push("/usr/local/lib/node_modules");
1021
1075
  npmRoots.push("/usr/lib/node_modules");
1022
1076
  npmRoots.push("/opt/homebrew/lib/node_modules");
1023
1077
  }
1024
1078
  return npmRoots.map(
1025
- (root) => resolve4(root, "@anthropic-ai", "claude-code", "vendor", "ripgrep", subdir2, exe)
1079
+ (root) => resolve6(root, "@anthropic-ai", "claude-code", "vendor", "ripgrep", subdir2, exe)
1026
1080
  );
1027
1081
  }
1028
1082
 
@@ -1068,7 +1122,7 @@ async function call4(input, signal) {
1068
1122
  args.push("--max-columns-preview");
1069
1123
  args.push("--sort", "modified");
1070
1124
  args.push("-e", input.pattern);
1071
- args.push(input.path ? resolve5(input.path) : ".");
1125
+ args.push(input.path ? resolve7(input.path) : ".");
1072
1126
  const rgPath = await resolveRgPath();
1073
1127
  if (!rgPath) {
1074
1128
  return {
@@ -1082,7 +1136,7 @@ async function call4(input, signal) {
1082
1136
  try {
1083
1137
  await new Promise((resolveP, rejectP) => {
1084
1138
  const child = spawn3(rgPath, args, {
1085
- cwd: process.cwd(),
1139
+ cwd: getWorkingDir(),
1086
1140
  signal,
1087
1141
  windowsHide: true
1088
1142
  });
@@ -1136,8 +1190,8 @@ var grepTool = {
1136
1190
  };
1137
1191
 
1138
1192
  // src/tools/read/read.ts
1139
- import { readFile as readFile6, stat as stat2 } from "fs/promises";
1140
- import { resolve as resolve6 } from "path";
1193
+ import { readFile as readFile6, stat as stat3 } from "fs/promises";
1194
+ import { resolve as resolve8 } from "path";
1141
1195
  import { z as z5 } from "zod";
1142
1196
  var inputSchema5 = z5.object({
1143
1197
  file_path: z5.string().min(1, "\u5FC5\u987B\u63D0\u4F9B file_path").describe("\u8981\u8BFB\u53D6\u7684\u6587\u4EF6\u8DEF\u5F84\uFF0C\u7EDD\u5BF9\u8DEF\u5F84\u4F18\u5148"),
@@ -1156,12 +1210,12 @@ Usage:
1156
1210
  - This tool can only read text files, not directories. To read a directory, use the Glob tool.
1157
1211
  - If you read a file that exists but has empty contents you will receive a warning in place of file contents.`;
1158
1212
  async function call5(input) {
1159
- const filePath = resolve6(input.file_path);
1213
+ const filePath = resolve8(input.file_path);
1160
1214
  const offset = input.offset ?? 1;
1161
1215
  const limit = input.limit ?? MAX_LINES_TO_READ;
1162
1216
  let st;
1163
1217
  try {
1164
- st = await stat2(filePath);
1218
+ st = await stat3(filePath);
1165
1219
  } catch (e) {
1166
1220
  return {
1167
1221
  ok: false,
@@ -2026,8 +2080,8 @@ var webSearchTool = {
2026
2080
 
2027
2081
  // src/tools/write/write.ts
2028
2082
  import { existsSync as existsSync4 } from "fs";
2029
- import { mkdir as mkdir4, stat as stat3, writeFile as writeFile4 } from "fs/promises";
2030
- import { dirname as dirname5, resolve as resolve7 } from "path";
2083
+ import { mkdir as mkdir5, stat as stat4, writeFile as writeFile4 } from "fs/promises";
2084
+ import { dirname as dirname6, resolve as resolve9 } from "path";
2031
2085
  import { z as z9 } from "zod";
2032
2086
  var MAX_WRITE_SIZE_BYTES = 1024 * 1024 * 1024;
2033
2087
  var inputSchema9 = z9.object({
@@ -2052,7 +2106,7 @@ function validatePath2(filePath) {
2052
2106
  return { ok: true };
2053
2107
  }
2054
2108
  async function call9(input) {
2055
- const filePath = resolve7(input.file_path);
2109
+ const filePath = resolve9(input.file_path);
2056
2110
  const pathCheck = validatePath2(filePath);
2057
2111
  if (!pathCheck.ok) return pathCheck;
2058
2112
  const contentSize = Buffer.byteLength(input.content, "utf8");
@@ -2063,12 +2117,12 @@ async function call9(input) {
2063
2117
  };
2064
2118
  }
2065
2119
  try {
2066
- await mkdir4(dirname5(filePath), { recursive: true });
2120
+ await mkdir5(dirname6(filePath), { recursive: true });
2067
2121
  let originalSize = 0;
2068
2122
  const fileExisted = existsSync4(filePath);
2069
2123
  if (fileExisted) {
2070
2124
  try {
2071
- const st = await stat3(filePath);
2125
+ const st = await stat4(filePath);
2072
2126
  originalSize = st.size;
2073
2127
  } catch {
2074
2128
  }
@@ -2908,6 +2962,8 @@ function MessageRow({ message }) {
2908
2962
 
2909
2963
  // src/ui/StatusLine.tsx
2910
2964
  import { Box as Box4, Text as Text4 } from "ink";
2965
+ import { homedir as homedir4 } from "os";
2966
+ import { sep } from "path";
2911
2967
 
2912
2968
  // src/llm/client.ts
2913
2969
  async function* chat(args) {
@@ -3299,7 +3355,11 @@ function StatusLine({ provider, history }) {
3299
3355
  const usage = useTokenUsage(history, provider);
3300
3356
  const ratio = usage.tokens / usage.threshold;
3301
3357
  const color = ratio >= 1 ? "red" : ratio >= 0.7 ? "yellow" : "green";
3358
+ const cwdDisplay = shortenPath(getWorkingDir());
3302
3359
  return /* @__PURE__ */ jsxs4(Box4, { children: [
3360
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "cwd " }),
3361
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", children: cwdDisplay }),
3362
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", children: " \xB7 " }),
3303
3363
  /* @__PURE__ */ jsxs4(Text4, { color: "gray", children: [
3304
3364
  provider.name,
3305
3365
  "/",
@@ -3321,6 +3381,19 @@ function fmt(n) {
3321
3381
  if (n < 1e6) return `${(n / 1e3).toFixed(1)}K`;
3322
3382
  return `${(n / 1e6).toFixed(2)}M`;
3323
3383
  }
3384
+ function shortenPath(abs) {
3385
+ const home = homedir4();
3386
+ let p = abs;
3387
+ if (home && (p === home || p.startsWith(home + sep))) {
3388
+ p = "~" + p.slice(home.length);
3389
+ }
3390
+ if (p.length <= 40) return p;
3391
+ const parts = p.split(/[\\/]/).filter(Boolean);
3392
+ if (parts.length <= 3) return p;
3393
+ const head = p.startsWith("~") ? "~" : parts[0];
3394
+ const tail = parts.slice(-2).join(sep);
3395
+ return `${head}${sep}\u2026${sep}${tail}`;
3396
+ }
3324
3397
 
3325
3398
  // src/ui/ToolStatus.tsx
3326
3399
  import { Box as Box5, Text as Text5 } from "ink";
@@ -3472,7 +3545,7 @@ async function reactiveCompactIfApplicable(messages, provider, error) {
3472
3545
  }
3473
3546
 
3474
3547
  // src/context/microCompactLite.ts
3475
- import { createHash } from "crypto";
3548
+ import { createHash as createHash2 } from "crypto";
3476
3549
  var MAX_REPEAT_COUNT = 3;
3477
3550
  var MAX_RESULT_SIZE = 4e3;
3478
3551
  var HEAD_KEEP_CHARS = 2e3;
@@ -3524,7 +3597,7 @@ function expireOldEntries() {
3524
3597
  return expired;
3525
3598
  }
3526
3599
  function sha1(str) {
3527
- return createHash("sha1").update(str).digest("hex");
3600
+ return createHash2("sha1").update(str).digest("hex");
3528
3601
  }
3529
3602
  function truncateContent(content) {
3530
3603
  const omitted = content.length - HEAD_KEEP_CHARS - TAIL_KEEP_CHARS;
@@ -3756,7 +3829,7 @@ function useChat(args) {
3756
3829
  }, []);
3757
3830
  const clearHistory = useCallback5(async () => {
3758
3831
  if (isLoading) return;
3759
- const newSystemPrompt = await buildFullSystemPrompt(process.cwd(), ALL_TOOLS);
3832
+ const newSystemPrompt = await buildFullSystemPrompt(getWorkingDir(), ALL_TOOLS);
3760
3833
  historyRef.current.length = 0;
3761
3834
  historyRef.current.push({ role: "system", content: newSystemPrompt });
3762
3835
  resetReactiveCompactState();
@@ -3933,7 +4006,7 @@ function Root({ initialProvider }) {
3933
4006
  return /* @__PURE__ */ jsx7(App, { provider: phase.provider, initialHistory: phase.initialHistory });
3934
4007
  }
3935
4008
  async function buildInitialHistory() {
3936
- const content = await buildFullSystemPrompt(process.cwd(), ALL_TOOLS);
4009
+ const content = await buildFullSystemPrompt(getWorkingDir(), ALL_TOOLS);
3937
4010
  const fresh = { role: "system", content };
3938
4011
  const persisted = await loadContext();
3939
4012
  if (!persisted || persisted.length === 0) return [fresh];
@@ -4055,13 +4128,13 @@ function handleEvent2(event, output, verbose) {
4055
4128
  }
4056
4129
  }
4057
4130
  function readFromStdin() {
4058
- return new Promise((resolve8) => {
4131
+ return new Promise((resolve10) => {
4059
4132
  let data = "";
4060
4133
  let settled = false;
4061
4134
  const timer = setTimeout(() => {
4062
4135
  if (!settled) {
4063
4136
  settled = true;
4064
- resolve8("");
4137
+ resolve10("");
4065
4138
  }
4066
4139
  }, STDIN_TIMEOUT_MS);
4067
4140
  process.stdin.setEncoding("utf8");
@@ -4072,7 +4145,7 @@ function readFromStdin() {
4072
4145
  if (!settled) {
4073
4146
  clearTimeout(timer);
4074
4147
  settled = true;
4075
- resolve8(data.trim());
4148
+ resolve10(data.trim());
4076
4149
  }
4077
4150
  }
4078
4151
  process.stdin.on("data", onData);
@@ -4085,6 +4158,8 @@ import { jsx as jsx8 } from "react/jsx-runtime";
4085
4158
  var require2 = createRequire(import.meta.url);
4086
4159
  var pkg = require2("../package.json");
4087
4160
  async function main() {
4161
+ initWorkingDir();
4162
+ await migrateLegacyContext(getWorkingDir());
4088
4163
  const args = process.argv.slice(2);
4089
4164
  if (args.includes("-h") || args.includes("--help")) {
4090
4165
  printHelp();
@@ -4120,7 +4195,7 @@ ${e.message}
4120
4195
  await waitUntilExit();
4121
4196
  }
4122
4197
  async function buildInitialHistory2() {
4123
- const content = await buildFullSystemPrompt(process.cwd(), ALL_TOOLS);
4198
+ const content = await buildFullSystemPrompt(getWorkingDir(), ALL_TOOLS);
4124
4199
  const fresh = { role: "system", content };
4125
4200
  const persisted = await loadContext();
4126
4201
  if (!persisted || persisted.length === 0) return [fresh];
@@ -4141,8 +4216,9 @@ minimal-agent - \u8F7B\u91CF\u7EA7 AI \u7F16\u7A0B\u52A9\u624B
4141
4216
  -h, --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
4142
4217
 
4143
4218
  \u4F1A\u8BDD\u8BB0\u5FC6:
4144
- \u81EA\u52A8\u52A0\u8F7D / \u4FDD\u5B58 ~/.minimal-agent/last-context.json
4145
- TUI \u4E0E -p \u5171\u4EAB\u540C\u4E00\u4EFD\u4E0A\u4E0B\u6587\uFF1BTUI \u4E2D\u8F93\u5165 /new \u6E05\u7A7A
4219
+ \u6309\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u9694\u79BB\uFF0C\u81EA\u52A8\u52A0\u8F7D / \u4FDD\u5B58\u5230
4220
+ ~/.minimal-agent/sessions/<\u76EE\u5F55\u54C8\u5E0C>.json
4221
+ TUI \u4E0E -p \u5171\u4EAB\u540C\u4E00\u76EE\u5F55\u7684\u4E0A\u4E0B\u6587\uFF1BTUI \u4E2D\u8F93\u5165 /new \u4EC5\u6E05\u5F53\u524D\u76EE\u5F55\u7684\u4F1A\u8BDD
4146
4222
 
4147
4223
  \u793A\u4F8B:
4148
4224
  minimal-agent -p "\u5E2E\u6211\u5199\u4E00\u4E2A hello world"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minimal-agent",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "最小化 Agent 系统 —— 单对话 + 9 工具 + 自动压缩 + OpenAI 兼容 + Ink TUI(学习/教学用)",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Bill Wang <leiwang0359@gmail.com>",