@jun133/athlete 0.0.7 → 0.0.9

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 CHANGED
@@ -1,17 +1,17 @@
1
1
  # Athlete
2
2
 
3
- <p align="center">
4
- <strong>一个把 LLM 变成可持续执行系统的 Agent Harness</strong>
5
- </p>
6
-
7
- <p align="center">
8
- <img alt="terminal first" src="https://img.shields.io/badge/terminal-first-2ea44f?style=for-the-badge">
9
- <img alt="durable runtime" src="https://img.shields.io/badge/durable-runtime-1f6feb?style=for-the-badge">
10
- <img alt="checkpoint persisted" src="https://img.shields.io/badge/checkpoint-persisted-8250df?style=for-the-badge">
11
- <img alt="runtime stats" src="https://img.shields.io/badge/runtime-stats-f59e0b?style=for-the-badge">
12
- </p>
13
-
14
- 一个终端优先的 Agent Harness。
3
+ <p align="center">
4
+ <strong>一个专注于解决问题与持续推进任务的智能体</strong>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <img alt="problem solving agent" src="https://img.shields.io/badge/problem--solving-agent-2ea44f?style=for-the-badge">
9
+ <img alt="durable runtime" src="https://img.shields.io/badge/durable-runtime-1f6feb?style=for-the-badge">
10
+ <img alt="checkpoint persisted" src="https://img.shields.io/badge/checkpoint-persisted-8250df?style=for-the-badge">
11
+ <img alt="runtime stats" src="https://img.shields.io/badge/runtime-stats-f59e0b?style=for-the-badge">
12
+ </p>
13
+
14
+ 一个专注于解决问题的智能体。
15
15
 
16
16
  一个单纯的 LLM,往往擅长回答问题;一个加上 harness 的 LLM,才开始真正接住任务。它不只是“说下一句”,而是能在复杂任务里持续往前跑,知道什么时候该读文件、什么时候该调用工具、什么时候该拆任务、什么时候该把状态记下来,出了错以后还能接着做。✨
17
17
 
package/dist/cli.js CHANGED
@@ -37,14 +37,14 @@ var init_package = __esm({
37
37
  "package.json"() {
38
38
  package_default = {
39
39
  name: "@jun133/athlete",
40
- version: "0.0.7",
41
- description: "A global terminal AI coding assistant.",
40
+ version: "0.0.9",
41
+ description: "A problem-solving agent focused on durable task execution.",
42
42
  keywords: [
43
43
  "athlete",
44
- "cli",
45
- "ai",
46
44
  "agent",
47
- "coding"
45
+ "automation",
46
+ "runtime",
47
+ "problem-solving"
48
48
  ],
49
49
  bin: {
50
50
  athlete: "dist/cli.js"
@@ -963,14 +963,12 @@ function parseAgentMode(value) {
963
963
  return void 0;
964
964
  }
965
965
  function normalizeConfig(config, runtime = {}) {
966
- const allowedRoots = Array.isArray(config.allowedRoots) && config.allowedRoots.length > 0 ? [...new Set(config.allowedRoots.map((value) => String(value).trim()).filter(Boolean))] : ["."];
967
966
  return {
968
967
  schemaVersion: CURRENT_CONFIG_SCHEMA_VERSION,
969
968
  provider: String(config.provider ?? DEFAULT_CONFIG.provider).trim() || DEFAULT_CONFIG.provider,
970
969
  baseUrl: config.baseUrl?.trim() || DEFAULT_CONFIG.baseUrl,
971
970
  model: config.model?.trim() || DEFAULT_CONFIG.model,
972
971
  mode: parseAgentMode(config.mode) ?? DEFAULT_CONFIG.mode,
973
- allowedRoots,
974
972
  yieldAfterToolSteps: clampNumber5(
975
973
  config.yieldAfterToolSteps,
976
974
  0,
@@ -1079,7 +1077,6 @@ var init_schema = __esm({
1079
1077
  baseUrl: "https://api.deepseek.com",
1080
1078
  model: "deepseek-reasoner",
1081
1079
  mode: "agent",
1082
- allowedRoots: ["."],
1083
1080
  yieldAfterToolSteps: 12,
1084
1081
  contextWindowMessages: 30,
1085
1082
  maxContextChars: 48e3,
@@ -1126,13 +1123,6 @@ function coerceConfigValue(key, rawValue) {
1126
1123
  switch (key) {
1127
1124
  case "schemaVersion":
1128
1125
  throw new Error("schemaVersion is managed by Athlete and cannot be set manually.");
1129
- case "allowedRoots": {
1130
- const parsed = tryParseJson(rawValue);
1131
- if (Array.isArray(parsed)) {
1132
- return parsed.map((item) => String(item));
1133
- }
1134
- return rawValue.split(",").map((item) => item.trim()).filter(Boolean);
1135
- }
1136
1126
  case "showReasoning":
1137
1127
  return rawValue === "true" || rawValue === "1";
1138
1128
  case "contextWindowMessages":
@@ -1204,7 +1194,6 @@ var init_configValues = __esm({
1204
1194
  "baseUrl",
1205
1195
  "model",
1206
1196
  "mode",
1207
- "allowedRoots",
1208
1197
  "yieldAfterToolSteps",
1209
1198
  "contextWindowMessages",
1210
1199
  "maxContextChars",
@@ -1229,7 +1218,6 @@ var init_configValues = __esm({
1229
1218
  "baseUrl",
1230
1219
  "model",
1231
1220
  "mode",
1232
- "allowedRoots",
1233
1221
  "yieldAfterToolSteps",
1234
1222
  "contextWindowMessages",
1235
1223
  "maxContextChars",
@@ -1804,7 +1792,7 @@ function registerConfigCommands(program, options) {
1804
1792
  model: runtime.config.model,
1805
1793
  mode: runtime.config.mode,
1806
1794
  baseUrl: runtime.config.baseUrl,
1807
- allowedRoots: runtime.config.allowedRoots,
1795
+ pathAccess: "unrestricted",
1808
1796
  apiKey: runtime.config.apiKey ? "set" : "missing",
1809
1797
  telegram: {
1810
1798
  ...runtime.config.telegram,
@@ -5244,20 +5232,6 @@ function resolveUserPath(inputPath, cwd) {
5244
5232
  }
5245
5233
  return import_node_path16.default.resolve(cwd, inputPath);
5246
5234
  }
5247
- function assertPathAllowed(targetPath, cwd, config) {
5248
- const resolved = resolveUserPath(targetPath, cwd);
5249
- if (config.allowedRoots.includes("*")) {
5250
- return resolved;
5251
- }
5252
- const allowedRoots = config.allowedRoots.map((root) => resolveUserPath(root, cwd));
5253
- for (const root of allowedRoots) {
5254
- const relative = import_node_path16.default.relative(root, resolved);
5255
- if (!relative.startsWith("..") && !import_node_path16.default.isAbsolute(relative)) {
5256
- return resolved;
5257
- }
5258
- }
5259
- throw new Error(`Path not allowed by config.allowedRoots: ${resolved}`);
5260
- }
5261
5235
  async function ensureParentDirectory(filePath) {
5262
5236
  await import_promises8.default.mkdir(import_node_path16.default.dirname(filePath), { recursive: true });
5263
5237
  }
@@ -5775,7 +5749,7 @@ var init_applyPatchTool = __esm({
5775
5749
  if (!targetPath) {
5776
5750
  throw new Error("Patch target path is missing.");
5777
5751
  }
5778
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
5752
+ const resolved = resolveUserPath(targetPath, context.cwd);
5779
5753
  const exists = await fileExists2(resolved);
5780
5754
  const before = exists ? await import_promises10.default.readFile(resolved, "utf8") : "";
5781
5755
  const source = oldPath === null ? "" : before;
@@ -7107,7 +7081,7 @@ var init_backgroundRunTool = __esm({
7107
7081
  const args = parseArgs(rawArgs);
7108
7082
  const command = readString2(args.command, "command");
7109
7083
  const shellCwd = typeof args.cwd === "string" ? args.cwd : context.cwd;
7110
- const resolvedCwd = assertPathAllowed(shellCwd, context.cwd, context.config);
7084
+ const resolvedCwd = resolveUserPath(shellCwd, context.cwd);
7111
7085
  const timeoutMs = clampNumber7(args.timeout_ms, 1e3, 6e5, 12e4);
7112
7086
  const stallTimeoutMs = clampNumber7(context.config.commandStallTimeoutMs, 2e3, 3e5, 3e4);
7113
7087
  const store = new BackgroundJobStore(context.projectContext.stateRootDir);
@@ -9147,7 +9121,7 @@ var init_downloadUrlTool = __esm({
9147
9121
  type: "function",
9148
9122
  function: {
9149
9123
  name: "download_url",
9150
- description: "Download a public URL into the workspace. Use this to acquire remote documents before reading them with local tools.",
9124
+ description: "Download a public URL onto the local filesystem. Use this to acquire remote documents before reading them with local tools.",
9151
9125
  parameters: {
9152
9126
  type: "object",
9153
9127
  properties: {
@@ -9157,7 +9131,7 @@ var init_downloadUrlTool = __esm({
9157
9131
  },
9158
9132
  path: {
9159
9133
  type: "string",
9160
- description: "Destination file path inside the workspace."
9134
+ description: "Destination file path on the local filesystem."
9161
9135
  },
9162
9136
  timeout_ms: {
9163
9137
  type: "number",
@@ -9179,7 +9153,7 @@ var init_downloadUrlTool = __esm({
9179
9153
  code: "DOWNLOAD_URL_PROTOCOL_UNSUPPORTED"
9180
9154
  });
9181
9155
  }
9182
- const resolvedPath = assertPathAllowed(targetPath, context.cwd, context.config);
9156
+ const resolvedPath = resolveUserPath(targetPath, context.cwd);
9183
9157
  const controller = new AbortController();
9184
9158
  const timer = setTimeout(() => controller.abort(new Error("download_url timed out")), timeoutMs);
9185
9159
  if (context.abortSignal) {
@@ -10156,7 +10130,7 @@ var init_editDocxTool = __esm({
10156
10130
  const variables = readTemplateVariables(args.variables);
10157
10131
  const createIfMissing = readBoolean(args.create_if_missing, false);
10158
10132
  const createDirectories = readBoolean(args.create_directories, true);
10159
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
10133
+ const resolved = resolveUserPath(targetPath, context.cwd);
10160
10134
  const extension = import_node_path26.default.extname(resolved).toLowerCase();
10161
10135
  if (extension === ".doc" || extension === ".docm") {
10162
10136
  throw new ToolExecutionError(`Word output in ${extension} format is not supported. Write a .docx file instead.`, {
@@ -10310,7 +10284,7 @@ var init_editFileTool = __esm({
10310
10284
  const oldString = readString2(args.old_string, "old_string");
10311
10285
  const newString = readString2(args.new_string, "new_string");
10312
10286
  const replaceAll = readBoolean(args.replace_all, false);
10313
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
10287
+ const resolved = resolveUserPath(targetPath, context.cwd);
10314
10288
  const before = await import_promises18.default.readFile(resolved, "utf8");
10315
10289
  const occurrences = countOccurrences(before, oldString);
10316
10290
  if (occurrences === 0) {
@@ -10540,7 +10514,7 @@ var init_listFilesTool = __esm({
10540
10514
  type: "function",
10541
10515
  function: {
10542
10516
  name: "list_files",
10543
- description: "List local files or directories in the workspace. Use this to explore a folder before reading or editing local files, not for webpages.",
10517
+ description: "List local files or directories on the local filesystem. Use this to explore a folder before reading or editing local files, not for webpages.",
10544
10518
  parameters: {
10545
10519
  type: "object",
10546
10520
  properties: {
@@ -10567,7 +10541,7 @@ var init_listFilesTool = __esm({
10567
10541
  const targetPath = readString2(args.path, "path");
10568
10542
  const recursive = readBoolean(args.recursive, false);
10569
10543
  const maxEntries = clampNumber7(args.max_entries, 1, 1e3, 200);
10570
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
10544
+ const resolved = resolveUserPath(targetPath, context.cwd);
10571
10545
  const stats = await import_promises19.default.stat(resolved);
10572
10546
  if (stats.isFile()) {
10573
10547
  return okResult(
@@ -10790,7 +10764,7 @@ var init_readDocxTool = __esm({
10790
10764
  async execute(rawArgs, context) {
10791
10765
  const args = parseArgs(rawArgs);
10792
10766
  const targetPath = readString2(args.path, "path");
10793
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
10767
+ const resolved = resolveUserPath(targetPath, context.cwd);
10794
10768
  const extension = import_node_path27.default.extname(resolved).toLowerCase();
10795
10769
  if (extension === ".doc" || extension === ".docm") {
10796
10770
  return okResult(
@@ -11216,7 +11190,7 @@ var init_pageCount = __esm({
11216
11190
  async function prepareMineruReadRequest(rawArgs, context, options) {
11217
11191
  const args = parseArgs(rawArgs);
11218
11192
  const targetPath = readString2(args.path, "path");
11219
- const resolvedPath = assertPathAllowed(targetPath, context.cwd, context.config);
11193
+ const resolvedPath = resolveUserPath(targetPath, context.cwd);
11220
11194
  const extension = import_node_path28.default.extname(resolvedPath).toLowerCase();
11221
11195
  if (!options.supportedExtensions.includes(extension)) {
11222
11196
  throw new ToolExecutionError(
@@ -12472,7 +12446,7 @@ function buildRuntimeEnvironmentBlock(input) {
12472
12446
  { label: "Current working directory", value: input.cwd },
12473
12447
  { label: "Project root", value: input.projectContext.rootDir },
12474
12448
  { label: "Project state root", value: input.projectContext.stateRootDir },
12475
- { label: "Allowed roots", value: input.config.allowedRoots.join(", ") },
12449
+ { label: "Path access", value: "Unrestricted local filesystem access" },
12476
12450
  { label: "Mode", value: input.config.mode },
12477
12451
  { label: "Model", value: input.config.model },
12478
12452
  { label: "Date", value: (/* @__PURE__ */ new Date()).toISOString() }
@@ -12691,7 +12665,7 @@ function buildStaticPromptBlocks(input) {
12691
12665
  function buildIdentityContract(config, runtimeState) {
12692
12666
  const identity = runtimeState.identity;
12693
12667
  const lines = [
12694
- "You are Athlete, a terminal-first AI agent for coding and general problem solving.",
12668
+ "You are Athlete, a problem-solving agent focused on durable task execution.",
12695
12669
  "Use tools for real actions instead of role-playing filesystem, shell, browser, task, or team work.",
12696
12670
  config.mode === "agent" ? "Mode: agent. You may edit files and run commands inside allowed roots." : "Mode: read-only. Inspect and analyze only; do not attempt mutating actions."
12697
12671
  ];
@@ -13644,7 +13618,7 @@ var init_readFileTool = __esm({
13644
13618
  type: "function",
13645
13619
  function: {
13646
13620
  name: "read_file",
13647
- description: "Read a local text file from the workspace. Returns numbered lines to make edits easier, and is not for webpage content.",
13621
+ description: "Read a local text file from the local filesystem. Returns numbered lines to make edits easier, and is not for webpage content.",
13648
13622
  parameters: {
13649
13623
  type: "object",
13650
13624
  properties: {
@@ -13671,7 +13645,7 @@ var init_readFileTool = __esm({
13671
13645
  const targetPath = readString2(args.path, "path");
13672
13646
  const startLine = readOptionalNumber(args.start_line);
13673
13647
  const endLine = readOptionalNumber(args.end_line);
13674
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
13648
+ const resolved = resolveUserPath(targetPath, context.cwd);
13675
13649
  let inspected;
13676
13650
  try {
13677
13651
  inspected = await inspectTextFile(resolved, context.config.maxReadBytes);
@@ -13901,7 +13875,7 @@ var init_readSpreadsheetTool = __esm({
13901
13875
  const requestedSheet = typeof args.sheet === "number" && Number.isFinite(args.sheet) ? String(Math.trunc(args.sheet)) : typeof args.sheet === "string" ? args.sheet.trim() : "";
13902
13876
  const maxRows = clampNumber7(args.max_rows, 1, 200, context.config.maxSpreadsheetPreviewRows);
13903
13877
  const maxColumns = clampNumber7(args.max_columns, 1, 100, context.config.maxSpreadsheetPreviewColumns);
13904
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
13878
+ const resolved = resolveUserPath(targetPath, context.cwd);
13905
13879
  let stat;
13906
13880
  try {
13907
13881
  stat = await import_promises26.default.stat(resolved);
@@ -14626,7 +14600,7 @@ var init_runShellTool = __esm({
14626
14600
  const command = readString2(args.command, "command");
14627
14601
  const shellCwd = typeof args.cwd === "string" ? args.cwd : context.cwd;
14628
14602
  const timeoutMs = clampNumber7(args.timeout_ms, 1e3, 6e5, 12e4);
14629
- const resolvedCwd = assertPathAllowed(shellCwd, context.cwd, context.config);
14603
+ const resolvedCwd = resolveUserPath(shellCwd, context.cwd);
14630
14604
  const classification = classifyCommand(command);
14631
14605
  const stallTimeoutMs = clampNumber7(
14632
14606
  context.config.commandStallTimeoutMs,
@@ -14742,7 +14716,7 @@ var init_searchFilesTool = __esm({
14742
14716
  const glob = typeof args.glob === "string" ? args.glob : "**/*";
14743
14717
  const caseSensitive = readBoolean(args.case_sensitive, false);
14744
14718
  const maxResults = clampNumber7(args.max_results, 1, 1e3, context.config.maxSearchResults);
14745
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
14719
+ const resolved = resolveUserPath(targetPath, context.cwd);
14746
14720
  const stats = await import_promises27.default.stat(resolved);
14747
14721
  const regex = buildSearchPattern(pattern, caseSensitive);
14748
14722
  const filePaths = stats.isDirectory() ? (await (0, import_fast_glob2.default)(glob, {
@@ -17592,9 +17566,6 @@ function buildToolRecoveryHint(toolName, rawArgs, message) {
17592
17566
  if (lower.includes("unsupported binary") || lower.includes("binary file detected")) {
17593
17567
  return `The target is not a readable text file. Skip raw content reading and reason from metadata, filenames, or other text files instead.`;
17594
17568
  }
17595
- if (lower.includes("path not allowed")) {
17596
- return "The target path is outside allowedRoots. Try a path inside the current project or ask the user to widen access.";
17597
- }
17598
17569
  if (lower.includes("unknown tool")) {
17599
17570
  return `The ${toolName} tool is unavailable in the current mode. Use the tools exposed now, or switch to agent mode if you need editing or shell access.`;
17600
17571
  }
@@ -19927,7 +19898,7 @@ var init_writeDocxTool = __esm({
19927
19898
  const titleTemplate = typeof args.title === "string" ? args.title.trim() : void 0;
19928
19899
  const descriptionTemplate = typeof args.description === "string" ? args.description.trim() : void 0;
19929
19900
  const createDirectories = readBoolean(args.create_directories, true);
19930
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
19901
+ const resolved = resolveUserPath(targetPath, context.cwd);
19931
19902
  const extension = import_node_path43.default.extname(resolved).toLowerCase();
19932
19903
  if (extension === ".doc" || extension === ".docm") {
19933
19904
  throw new ToolExecutionError(`Word output in ${extension} format is not supported. Write a .docx file instead.`, {
@@ -20055,7 +20026,7 @@ var init_writeFileTool = __esm({
20055
20026
  const targetPath = readString2(args.path, "path");
20056
20027
  const content = readString2(args.content, "content");
20057
20028
  const createDirectories = readBoolean(args.create_directories, true);
20058
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
20029
+ const resolved = resolveUserPath(targetPath, context.cwd);
20059
20030
  const existed = await fileExists2(resolved);
20060
20031
  const before = existed ? await import_promises36.default.readFile(resolved, "utf8") : "";
20061
20032
  const preview = buildDiffPreview(before, content);
@@ -26317,7 +26288,7 @@ function createTelegramSendFileTool(options) {
26317
26288
  async execute(rawArgs, context) {
26318
26289
  const args = parseArgs(rawArgs);
26319
26290
  const targetPath = readString2(args.path, "path");
26320
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
26291
+ const resolved = resolveUserPath(targetPath, context.cwd);
26321
26292
  const stats = await import_promises44.default.stat(resolved);
26322
26293
  if (!stats.isFile()) {
26323
26294
  throw new Error(`Only regular files can be sent to Telegram: ${resolved}`);
@@ -28852,7 +28823,7 @@ function createWeixinSendFileTool(options) {
28852
28823
  async execute(rawArgs, context) {
28853
28824
  const args = parseArgs(rawArgs);
28854
28825
  const targetPath = readString2(args.path, "path");
28855
- const resolved = assertPathAllowed(targetPath, context.cwd, context.config);
28826
+ const resolved = resolveUserPath(targetPath, context.cwd);
28856
28827
  const stats = await import_promises49.default.stat(resolved);
28857
28828
  if (!stats.isFile()) {
28858
28829
  throw new Error(`Only regular files can be sent to Weixin: ${resolved}`);
@@ -29956,7 +29927,7 @@ function buildCliProgram(dependencies = {}) {
29956
29927
  const program = new import_commander.Command();
29957
29928
  const resolveRuntime = dependencies.resolveRuntime ?? resolveCliRuntime;
29958
29929
  const getCliOverrides = () => extractCliOverrides(program.opts());
29959
- program.name("athlete").description("Athlete - a terminal AI coding assistant.").version(package_default.version, "-v, --version", "Print the current Athlete version.").configureOutput({
29930
+ program.name("athlete").description("Athlete - a problem-solving agent focused on durable task execution.").version(package_default.version, "-v, --version", "Print the current Athlete version.").configureOutput({
29960
29931
  writeOut: (text) => {
29961
29932
  writeStdout(text);
29962
29933
  },