@jixo/cli 0.6.0 → 0.8.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.
@@ -4,10 +4,10 @@ import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { safeEnv } from "../env.js";
6
6
  export const init = (dir) => {
7
- const jixoDirname = path.join(dir, ".jixo");
8
- /// 创建 .jixo 目录
9
- fs.mkdirSync(jixoDirname, { recursive: true });
10
7
  {
8
+ const jixoDirname = path.join(dir, ".jixo");
9
+ /// 创建 .jixo 目录
10
+ fs.mkdirSync(jixoDirname, { recursive: true });
11
11
  /// .jixo/readme.task.md
12
12
  const readmeTaskFilepath = path.join(jixoDirname, "readme.task.md");
13
13
  if (!fs.existsSync(readmeTaskFilepath)) {
@@ -19,9 +19,9 @@ export const init = (dir) => {
19
19
  });
20
20
  }
21
21
  }
22
- /// 配置文件
22
+ /// jixo.config.json
23
23
  {
24
- const jixoConfigFilepath = path.join(jixoDirname, "jixo.config.json");
24
+ const jixoConfigFilepath = path.join(dir, "jixo.config.json");
25
25
  if (!fs.existsSync(jixoConfigFilepath)) {
26
26
  writeJson(jixoConfigFilepath, {
27
27
  tasks: { type: "dir", dirname: ".jixo" },
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;IAClC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5C,eAAe;IACf,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;IAC7C,CAAC;QACC,wBAAwB;QACxB,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;QACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACvC,aAAa,CACX,kBAAkB,EAClB,eAAe,CAAC;;;SAGf,CAAC,EACF;gBACE,MAAM,EAAE,CAAC,eAAe,CAAC;aAC1B,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,QAAQ;IACR,CAAC;QACC,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;QACtE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACvC,SAAS,CAAC,kBAAkB,EAAE;gBAC5B,KAAK,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAC;aAClB,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,aAAa;IACb,CAAC;QACC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACpC,SAAS,CACP,eAAe,EACf,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;iBACjB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;iBACxC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC;iBACzB,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;QACJ,CAAC;IACH,CAAC;IACD,cAAc;IACd,CAAC;QACC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACvD,MAAM,cAAc,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1H,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,CAAC;YACjE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC7B,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC,CAAC","sourcesContent":["import {writeJson, writeMarkdown, writeText} from \"@gaubee/nodekit\";\nimport {str_trim_indent} from \"@gaubee/util\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {JixoConfig} from \"../config.js\";\nimport {safeEnv} from \"../env.js\";\nexport const init = (dir: string) => {\n const jixoDirname = path.join(dir, \".jixo\");\n /// 创建 .jixo 目录\n fs.mkdirSync(jixoDirname, {recursive: true});\n {\n /// .jixo/readme.task.md\n const readmeTaskFilepath = path.join(jixoDirname, \"readme.task.md\");\n if (!fs.existsSync(readmeTaskFilepath)) {\n writeMarkdown(\n readmeTaskFilepath,\n str_trim_indent(`\n <!-- 您可以自定义 readme.md 文件的格式 -->\n 请JIXO帮我生成或者追加 README 文件\n `),\n {\n agents: [\"readme-writer\"],\n },\n );\n }\n }\n /// 配置文件\n {\n const jixoConfigFilepath = path.join(jixoDirname, \"jixo.config.json\");\n if (!fs.existsSync(jixoConfigFilepath)) {\n writeJson(jixoConfigFilepath, {\n tasks: {type: \"dir\", dirname: \".jixo\"},\n } satisfies JixoConfig);\n }\n }\n /// .jixo.env\n {\n const jixoEnvFilepath = path.join(dir, \".jixo.env\");\n if (!fs.existsSync(jixoEnvFilepath)) {\n writeText(\n jixoEnvFilepath,\n Object.keys(safeEnv)\n .filter((key) => key.startsWith(\"JIXO_\"))\n .map((key) => `${key}=\"\"`)\n .join(\"\\n\"),\n );\n }\n }\n /// .gitignore\n {\n const gitignoreFilepath = path.join(dir, \".gitignore\");\n const gitignoreLines = (fs.existsSync(gitignoreFilepath) ? fs.readFileSync(gitignoreFilepath, \"utf-8\") : \"\").split(/\\n+/);\n let changed = false;\n for (const line of [\"*.memory.json\", \"memory.json\", \".jixo.env\"]) {\n if (!gitignoreLines.includes(line)) {\n gitignoreLines.unshift(line);\n changed = true;\n }\n }\n if (changed) {\n fs.writeFileSync(gitignoreFilepath, gitignoreLines.join(\"\\n\"));\n }\n }\n};\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;IAClC,CAAC;QACC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC5C,eAAe;QACf,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;QAC7C,wBAAwB;QACxB,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;QACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACvC,aAAa,CACX,kBAAkB,EAClB,eAAe,CAAC;;;SAGf,CAAC,EACF;gBACE,MAAM,EAAE,CAAC,eAAe,CAAC;aAC1B,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,oBAAoB;IACpB,CAAC;QACC,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAC9D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACvC,SAAS,CAAC,kBAAkB,EAAE;gBAC5B,KAAK,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAC;aAClB,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,aAAa;IACb,CAAC;QACC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACpC,SAAS,CACP,eAAe,EACf,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;iBACjB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;iBACxC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC;iBACzB,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;QACJ,CAAC;IACH,CAAC;IACD,cAAc;IACd,CAAC;QACC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACvD,MAAM,cAAc,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1H,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,CAAC;YACjE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC7B,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC,CAAC","sourcesContent":["import {writeJson, writeMarkdown, writeText} from \"@gaubee/nodekit\";\nimport {str_trim_indent} from \"@gaubee/util\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {JixoConfig} from \"../config.js\";\nimport {safeEnv} from \"../env.js\";\nexport const init = (dir: string) => {\n {\n const jixoDirname = path.join(dir, \".jixo\");\n /// 创建 .jixo 目录\n fs.mkdirSync(jixoDirname, {recursive: true});\n /// .jixo/readme.task.md\n const readmeTaskFilepath = path.join(jixoDirname, \"readme.task.md\");\n if (!fs.existsSync(readmeTaskFilepath)) {\n writeMarkdown(\n readmeTaskFilepath,\n str_trim_indent(`\n <!-- 您可以自定义 readme.md 文件的格式 -->\n 请JIXO帮我生成或者追加 README 文件\n `),\n {\n agents: [\"readme-writer\"],\n },\n );\n }\n }\n /// jixo.config.json\n {\n const jixoConfigFilepath = path.join(dir, \"jixo.config.json\");\n if (!fs.existsSync(jixoConfigFilepath)) {\n writeJson(jixoConfigFilepath, {\n tasks: {type: \"dir\", dirname: \".jixo\"},\n } satisfies JixoConfig);\n }\n }\n /// .jixo.env\n {\n const jixoEnvFilepath = path.join(dir, \".jixo.env\");\n if (!fs.existsSync(jixoEnvFilepath)) {\n writeText(\n jixoEnvFilepath,\n Object.keys(safeEnv)\n .filter((key) => key.startsWith(\"JIXO_\"))\n .map((key) => `${key}=\"\"`)\n .join(\"\\n\"),\n );\n }\n }\n /// .gitignore\n {\n const gitignoreFilepath = path.join(dir, \".gitignore\");\n const gitignoreLines = (fs.existsSync(gitignoreFilepath) ? fs.readFileSync(gitignoreFilepath, \"utf-8\") : \"\").split(/\\n+/);\n let changed = false;\n for (const line of [\"*.memory.json\", \"memory.json\", \".jixo.env\"]) {\n if (!gitignoreLines.includes(line)) {\n gitignoreLines.unshift(line);\n changed = true;\n }\n }\n if (changed) {\n fs.writeFileSync(gitignoreFilepath, gitignoreLines.join(\"\\n\"));\n }\n }\n};\n"]}
@@ -1,4 +1,4 @@
1
1
  import { FileEntry } from "@gaubee/nodekit";
2
2
  import type { AiTask } from "../../helper/resolve-ai-tasks.js";
3
- export declare const runAiTask: (ai_task: AiTask, allFiles: FileEntry[], changedFiles: FileEntry[]) => Promise<void>;
3
+ export declare const runAiTask: (ai_task: AiTask, allFiles: FileEntry[], changedFilesSet: Record<string, FileEntry[]>) => Promise<void>;
4
4
  //# sourceMappingURL=run-ai-task.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-ai-task.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/run-ai-task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,SAAS,EAA6B,MAAM,iBAAiB,CAAC;AASlF,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,kCAAkC,CAAC;AAoC7D,eAAO,MAAM,SAAS,GAAU,SAAS,MAAM,EAAE,UAAU,SAAS,EAAE,EAAE,cAAc,SAAS,EAAE,kBAyNhG,CAAC"}
1
+ {"version":3,"file":"run-ai-task.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/run-ai-task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,SAAS,EAA0C,MAAM,iBAAiB,CAAC;AAU/F,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,kCAAkC,CAAC;AAqC7D,eAAO,MAAM,SAAS,GAAU,SAAS,MAAM,EAAE,UAAU,SAAS,EAAE,EAAE,iBAAiB,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,kBAqPnH,CAAC"}
@@ -1,7 +1,8 @@
1
- import { blue, cyan, FileEntry, gray, green, spinner, YAML } from "@gaubee/nodekit";
1
+ import { blue, cyan, FileEntry, gray, green, red, spinner, YAML, yellow } from "@gaubee/nodekit";
2
2
  import { func_catch } from "@gaubee/util";
3
3
  import { streamText } from "ai";
4
4
  import debug from "debug";
5
+ import ms from "ms";
5
6
  import os from "node:os";
6
7
  import path from "node:path";
7
8
  import { match, P } from "ts-pattern";
@@ -40,7 +41,7 @@ const getModel = (model) => {
40
41
  return providers.deepseek("deepseek-reasoner");
41
42
  });
42
43
  };
43
- export const runAiTask = async (ai_task, allFiles, changedFiles) => {
44
+ export const runAiTask = async (ai_task, allFiles, changedFilesSet) => {
44
45
  const model = getModel(ai_task.model);
45
46
  const availableTools = {
46
47
  ...(await tools.fileSystem(ai_task.cwd)),
@@ -63,28 +64,34 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
63
64
  .otherwise(() => "");
64
65
  return envValue;
65
66
  })
66
- .replaceAll("{{allFiles}}", [
67
- //
68
- `# files dir: ${ai_task.dir}`,
69
- `# files count: ${allFiles.length}`,
70
- YAML.stringify(allFiles.map((e) => e.relativePath)),
71
- ].join("\n"))
72
- .replaceAll("{{changedFiles}}", [
73
- //
74
- `# files dir: ${ai_task.dir}`,
75
- `# files count: ${changedFiles.length}`,
76
- YAML.stringify(changedFiles.map((e) => e.relativePath)),
77
- ].join("\n"));
67
+ .replaceAll("{{allFiles}}", YAML.stringify({
68
+ [ai_task.cwd]: {
69
+ count: allFiles.length,
70
+ file: allFiles.map((e) => e.relativePath),
71
+ },
72
+ }))
73
+ .replaceAll("{{changedFiles}}", YAML.stringify(Object.entries(changedFilesSet).reduce((tree, [dir, changedFiles]) => {
74
+ tree[dir] = {
75
+ count: changedFiles.length,
76
+ files: changedFiles.map((e) => e.relativePath),
77
+ };
78
+ return tree;
79
+ }, {})));
78
80
  log("USER PROMPT:", userPrompt);
79
81
  initialMessages.push({
80
82
  role: "user",
81
83
  content: userPrompt,
82
84
  });
83
85
  let currentMessages = [...initialMessages];
84
- const maxTurns = 10; // Safeguard against infinite loops
86
+ const maxTurns = 20; // Safeguard against infinite loops
85
87
  const loading = spinner("Initializing AI task...");
86
88
  loading.prefixText = "⏳ ";
87
89
  loading.start();
90
+ const endInfo = {
91
+ prefixText: "",
92
+ text: "",
93
+ suffixText: `⏱️ ${gray(ms(new Date().getTime() - new Date(ai_task.startTime).getTime(), { long: true }))}`,
94
+ };
88
95
  loop: for (let turn = 0; turn < maxTurns; turn++) {
89
96
  loading.text = turn === 0 ? `Connecting To ${model.provider}...` : `Processing turn ${turn + 1}...`;
90
97
  const result = await streamText({
@@ -93,8 +100,8 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
93
100
  tools: availableTools,
94
101
  toolChoice: "auto", // Changed to auto for more flexibility
95
102
  });
96
- let reasoning = "";
97
- let fulltext = "";
103
+ let fullReasoningText = "";
104
+ let fullText = "";
98
105
  let firstStreamPart = true;
99
106
  const requestedToolCalls = []; // Using any for now, should be ToolCallPart from 'ai'
100
107
  const assistantMessageContent = [];
@@ -118,14 +125,14 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
118
125
  assistantMessageContent.push(assistantTextPart);
119
126
  }
120
127
  assistantTextPart.text += textPart.text;
121
- if (fulltext === "")
122
- fulltext = "\n"; // For consistent display
123
- fulltext += textPart.text;
124
- loading.text = fulltext;
128
+ if (fullText === "")
129
+ fullText = "\n"; // For consistent display
130
+ fullText += textPart.text;
131
+ loading.text = fullText.split("\n").slice(-10).join("\n");
125
132
  })
126
133
  .with({ type: "tool-call" }, (callPart) => {
127
134
  loading.prefixText = "🛠️ ";
128
- loading.text = "Requesting tool:" + blue(callPart.toolName) + gray(": " + YAML.stringify(callPart.args));
135
+ loading.text = "Requesting tool:" + blue(callPart.toolName) + gray(": " + YAML.stringify(callPart.args).split("\n").slice(0, 3) + "...");
129
136
  log("\nQAQ tool-call", callPart);
130
137
  requestedToolCalls.push(callPart);
131
138
  // Update assistant message to include tool calls
@@ -137,21 +144,34 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
137
144
  });
138
145
  })
139
146
  .with({ type: "error" }, (errorPart) => {
140
- loading.prefixText = "❌ ";
141
147
  console.error("\nQAQ error", errorPart.error);
142
- loading.fail(`Error: ${errorPart.error?.toString()}`);
148
+ loading.prefixText = endInfo.prefixText = "❌ ";
149
+ loading.text = endInfo.text = red(`Error: ${errorPart.error?.toString()}`);
143
150
  return LOOP_SIGNALS.BREAK; // Stop processing on error
144
151
  })
145
152
  .with({ type: "reasoning" }, (reasoningPart) => {
146
153
  loading.prefixText = "🤔 ";
147
- if (reasoning === "")
154
+ if (fullReasoningText === "")
148
155
  loading.text = "";
149
- reasoning += reasoningPart.text;
150
- loading.text = gray(reasoning.split("\n").slice(-3).join("\n"));
156
+ fullReasoningText += reasoningPart.text;
157
+ loading.text = gray(fullReasoningText.split("\n").slice(-3).join("\n"));
151
158
  })
152
159
  // Add other console logs for debugging if needed, but keep them minimal for production
153
- .with({ type: "file" }, (p) => log("\nQAQ file", p.file))
154
- .with({ type: "source" }, (p) => log("\nQAQ source", p))
160
+ .with({ type: "file" }, (p) => {
161
+ loading.prefixText = "📃 ";
162
+ loading.text = p.file.mediaType;
163
+ log("\nQAQ file", p.file);
164
+ })
165
+ .with({ type: "source" }, (p) => {
166
+ loading.prefixText = "🔗 ";
167
+ if (p.title) {
168
+ loading.text = `[${p.title}](${p.url})`;
169
+ }
170
+ else {
171
+ loading.text = p.url;
172
+ }
173
+ log("\nQAQ source", p);
174
+ })
155
175
  .with({ type: "tool-result" }, (p) => log("\nQAQ tool-result", p))
156
176
  .with({ type: "tool-call-streaming-start" }, (p) => log("\nQAQ tool-call-streaming-start", p))
157
177
  .with({ type: "tool-call-delta" }, (p) => log("\nQAQ tool-call-delta", p))
@@ -164,14 +184,15 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
164
184
  // Add the assistant's message from this turn to the history
165
185
  currentMessages.push(_currentAssistantMessage);
166
186
  if (finishPart.finishReason === "stop" || finishPart.finishReason === "length") {
167
- loading.prefixText = "✅ ";
168
- loading.text = green(`${cyan(`[${ai_task.name}]`)} Completed`);
187
+ loading.prefixText = endInfo.prefixText = "✅ ";
188
+ loading.text = endInfo.text = green(`${cyan(`[${ai_task.name}]`)} Completed`);
169
189
  // Task finished without tool calls or after tool calls that didn't lead to more calls.
170
190
  return LOOP_SIGNALS.RETURN; // Exit the outer loop and function
171
191
  }
172
192
  if (finishPart.finishReason === "tool-calls") {
173
193
  if (requestedToolCalls.length === 0) {
174
- loading.warn("Finished with 'tool-calls' but no tools were requested.");
194
+ loading.prefixText = endInfo.prefixText = "🚧 ";
195
+ loading.text = endInfo.text = yellow(`${cyan(`[${ai_task.name}]`)} finished with 'tool-calls' but no tools were requested.`);
175
196
  return LOOP_SIGNALS.RETURN; // Exit, something is off
176
197
  }
177
198
  const toolResultMessages = [];
@@ -222,7 +243,8 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
222
243
  }
223
244
  else {
224
245
  // Other finish reasons, potentially an error or unexpected state
225
- loading.warn(`Task finished with unhandled reason: ${finishPart.finishReason}`);
246
+ loading.prefixText = endInfo.prefixText = "🛑 ";
247
+ loading.text = endInfo.text = red(`${cyan(`[${ai_task.name}]`)} task finished with unhandled reason: ${finishPart.finishReason}`);
226
248
  return LOOP_SIGNALS.RETURN;
227
249
  }
228
250
  })
@@ -236,11 +258,12 @@ export const runAiTask = async (ai_task, allFiles, changedFiles) => {
236
258
  }
237
259
  // If the stream finishes without a 'finish' part (e.g. error thrown inside), this loop might exit. Ensure spinner stops.
238
260
  if (turn === maxTurns - 1) {
239
- loading.warn("Max interaction turns reached.");
240
- return;
261
+ loading.prefixText = endInfo.prefixText = "🚧 ";
262
+ loading.text = endInfo.text = yellow(`${cyan(`[${ai_task.name}]`)} Max interaction turns reached.`);
263
+ break;
241
264
  }
242
265
  }
243
266
  // Fallback spinner stop if loop exits unexpectedly
244
- loading.stop();
267
+ loading.stopAndPersist(endInfo);
245
268
  };
246
269
  //# sourceMappingURL=run-ai-task.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-ai-task.js","sourceRoot":"","sources":["../../../src/commands/tasks/run-ai-task.ts"],"names":[],"mappings":"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","sourcesContent":["import {blue, cyan, FileEntry, gray, green, spinner, YAML} from \"@gaubee/nodekit\";\nimport {func_catch} from \"@gaubee/util\";\nimport {streamText, type AssistantModelMessage, type ModelMessage, type ToolCallPart} from \"ai\";\nimport debug from \"debug\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport {match, P} from \"ts-pattern\";\nimport {safeEnv} from \"../../env.js\";\nimport {getModelMessage, getPromptConfigs} from \"../../helper/prompts-loader.js\";\nimport type {AiTask} from \"../../helper/resolve-ai-tasks.js\";\nimport {tools} from \"./ai-tools.js\";\nimport {providers} from \"./model-providers.js\";\nconst log = debug(\"jixo:run-ai-task\");\n\nconst getModel = (model?: string) => {\n return match(model)\n .with(P.string.startsWith(\"deepseek-\"), (model) => providers.deepseek(model))\n .with(P.string.startsWith(\"gemini-\"), (model) => providers.google(model))\n .with(P.string.startsWith(\"o3-\"), P.string.startsWith(\"o1-\"), P.string.startsWith(\"gpt-\"), (model) => providers.openai(model))\n .with(P.string.startsWith(\"claude-\"), (model) => providers.anthropic(model))\n .with(P.string.startsWith(\"grok-\"), (model) => providers.xai(model))\n .with(P.string.includes(\"/\"), (model) => providers.deepinfra(model))\n .otherwise(() => {\n if (safeEnv.JIXO_DEEPSEEK_API_KEY) {\n return providers.deepseek(\"deepseek-chat\");\n }\n if (safeEnv.JIXO_GOOGLE_API_KEY) {\n return providers.google(\"gemini-2.5-pro-preview-05-06\");\n }\n if (safeEnv.JIXO_OPENAI_API_KEY) {\n return providers.openai(\"o3-mini\");\n }\n if (safeEnv.JIXO_ANTHROPIC_API_KEY) {\n return providers.anthropic(\"claude-4-sonnet-20250514\");\n }\n if (safeEnv.JIXO_XAI_API_KEY) {\n return providers.xai(\"grok-3-beta\");\n }\n if (safeEnv.JIXO_DEEPINFRA_API_KEY) {\n return providers.deepinfra(\"meta-llama/Meta-Llama-3.1-405B-Instruct\");\n }\n return providers.deepseek(\"deepseek-reasoner\");\n });\n};\n\nexport const runAiTask = async (ai_task: AiTask, allFiles: FileEntry[], changedFiles: FileEntry[]) => {\n const model = getModel(ai_task.model);\n const availableTools = {\n ...(await tools.fileSystem(ai_task.cwd)),\n ...(await tools.memory(path.join(ai_task.cwd, `.jixo/${ai_task.name}.memory.json`))),\n // ...(await tools.fetch()),\n // ...(await tools.git(ai_task.cwd)),\n };\n\n const initialMessages: ModelMessage[] = getModelMessage(ai_task.agents);\n ai_task.startTime;\n const userPrompt = getPromptConfigs()\n .user.content //\n .replace(/\\{\\{task.(\\w+)\\}\\}/g, (_, key) => {\n return Reflect.get(ai_task, key);\n })\n .replace(/\\{\\{env.(\\w+)\\}\\}/g, (_, key) => {\n const envKey = key.toUpperCase();\n const envValue =\n Reflect.get(process.env, envKey) ??\n match(envKey)\n .with(\"USER\", () => os.userInfo().username)\n .otherwise(() => \"\");\n return envValue;\n })\n .replaceAll(\n \"{{allFiles}}\",\n [\n //\n `# files dir: ${ai_task.dir}`,\n `# files count: ${allFiles.length}`,\n YAML.stringify(allFiles.map((e) => e.relativePath)),\n ].join(\"\\n\"),\n )\n .replaceAll(\n \"{{changedFiles}}\",\n [\n //\n `# files dir: ${ai_task.dir}`,\n `# files count: ${changedFiles.length}`,\n YAML.stringify(changedFiles.map((e) => e.relativePath)),\n ].join(\"\\n\"),\n );\n log(\"USER PROMPT:\", userPrompt);\n initialMessages.push({\n role: \"user\",\n content: userPrompt,\n });\n\n let currentMessages: ModelMessage[] = [...initialMessages];\n const maxTurns = 10; // Safeguard against infinite loops\n const loading = spinner(\"Initializing AI task...\");\n loading.prefixText = \"⏳ \";\n loading.start();\n\n loop: for (let turn = 0; turn < maxTurns; turn++) {\n loading.text = turn === 0 ? `Connecting To ${model.provider}...` : `Processing turn ${turn + 1}...`;\n\n const result = await streamText({\n model: model,\n messages: currentMessages,\n tools: availableTools,\n toolChoice: \"auto\", // Changed to auto for more flexibility\n });\n\n let reasoning = \"\";\n let fulltext = \"\";\n let firstStreamPart = true;\n const requestedToolCalls: ToolCallPart[] = []; // Using any for now, should be ToolCallPart from 'ai'\n\n const assistantMessageContent: AssistantModelMessage[\"content\"] & unknown[] = [];\n const _currentAssistantMessage: AssistantModelMessage = {role: \"assistant\", content: assistantMessageContent};\n\n const LOOP_SIGNALS = {\n RETURN: \"RETURN\",\n BREAK: \"BREAK\",\n CONTINUE: \"CONTINUE\",\n } as const;\n for await (const part of result.fullStream) {\n if (firstStreamPart) {\n firstStreamPart = false;\n loading.text = \"\"; // Clear initial connecting/processing message\n }\n const LOOP_SIGNAL = await match(part)\n .with({type: \"text\"}, (textPart) => {\n loading.prefixText = \"🤖 \";\n let assistantTextPart = assistantMessageContent.findLast((part) => part.type === \"text\");\n if (assistantTextPart == null) {\n assistantTextPart = {type: \"text\", text: \"\"};\n assistantMessageContent.push(assistantTextPart);\n }\n assistantTextPart.text += textPart.text;\n if (fulltext === \"\") fulltext = \"\\n\"; // For consistent display\n fulltext += textPart.text;\n loading.text = fulltext;\n })\n .with({type: \"tool-call\"}, (callPart) => {\n loading.prefixText = \"🛠️ \";\n loading.text = \"Requesting tool:\" + blue(callPart.toolName) + gray(\": \" + YAML.stringify(callPart.args));\n log(\"\\nQAQ tool-call\", callPart);\n requestedToolCalls.push(callPart);\n // Update assistant message to include tool calls\n assistantMessageContent.push({\n type: \"tool-call\",\n toolCallId: callPart.toolCallId,\n toolName: callPart.toolName,\n args: callPart.args,\n });\n })\n .with({type: \"error\"}, (errorPart) => {\n loading.prefixText = \"❌ \";\n console.error(\"\\nQAQ error\", errorPart.error);\n loading.fail(`Error: ${errorPart.error?.toString()}`);\n return LOOP_SIGNALS.BREAK; // Stop processing on error\n })\n .with({type: \"reasoning\"}, (reasoningPart) => {\n loading.prefixText = \"🤔 \";\n if (reasoning === \"\") loading.text = \"\";\n reasoning += reasoningPart.text;\n loading.text = gray(reasoning.split(\"\\n\").slice(-3).join(\"\\n\"));\n })\n // Add other console logs for debugging if needed, but keep them minimal for production\n .with({type: \"file\"}, (p) => log(\"\\nQAQ file\", p.file))\n .with({type: \"source\"}, (p) => log(\"\\nQAQ source\", p))\n .with({type: \"tool-result\"}, (p) => log(\"\\nQAQ tool-result\", p))\n .with({type: \"tool-call-streaming-start\"}, (p) => log(\"\\nQAQ tool-call-streaming-start\", p))\n .with({type: \"tool-call-delta\"}, (p) => log(\"\\nQAQ tool-call-delta\", p))\n .with({type: \"reasoning-part-finish\"}, (p) => log(\"\\nQAQ reasoning-part-finish\", p))\n .with({type: \"start-step\"}, (p) => log(\"\\nQAQ start-step\", p))\n .with({type: \"finish-step\"}, (p) => log(\"\\nQAQ finish-step\", p))\n .with({type: \"start\"}, (p) => log(\"\\nQAQ start\", p))\n .with({type: \"finish\"}, async (finishPart) => {\n log(\"\\nQAQ finish\", finishPart);\n // Add the assistant's message from this turn to the history\n currentMessages.push(_currentAssistantMessage);\n\n if (finishPart.finishReason === \"stop\" || finishPart.finishReason === \"length\") {\n loading.prefixText = \"✅ \";\n loading.text = green(`${cyan(`[${ai_task.name}]`)} Completed`);\n // Task finished without tool calls or after tool calls that didn't lead to more calls.\n return LOOP_SIGNALS.RETURN; // Exit the outer loop and function\n }\n\n if (finishPart.finishReason === \"tool-calls\") {\n if (requestedToolCalls.length === 0) {\n loading.warn(\"Finished with 'tool-calls' but no tools were requested.\");\n return LOOP_SIGNALS.RETURN; // Exit, something is off\n }\n\n const toolResultMessages: ModelMessage[] = [];\n for (const toolCall of requestedToolCalls) {\n const toolToExecute = availableTools[toolCall.toolName];\n if (!toolToExecute || typeof toolToExecute.execute !== \"function\") {\n console.error(`Tool ${toolCall.toolName} not found or not executable.`);\n toolResultMessages.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n result: JSON.stringify({error: `Tool ${toolCall.toolName} not found or not executable.`}),\n isError: true,\n },\n ],\n });\n continue;\n }\n loading.text = `Executing tool: ${toolCall.toolName}...`;\n const executionResult = await func_catch(() =>\n toolToExecute.execute!(toolCall.args, {\n toolCallId: toolCall.toolCallId,\n messages: currentMessages,\n }),\n )();\n toolResultMessages.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n isError: !executionResult.success,\n result: JSON.stringify(executionResult.success ? executionResult.result : executionResult.error),\n },\n ],\n });\n if (executionResult.success) {\n loading.text = `Tool ${toolCall.toolName} executed.`;\n } else {\n loading.text = `Error executing tool ${toolCall.toolName}.`;\n }\n }\n currentMessages.push(...toolResultMessages);\n // Loop continues for the next turn\n } else {\n // Other finish reasons, potentially an error or unexpected state\n loading.warn(`Task finished with unhandled reason: ${finishPart.finishReason}`);\n return LOOP_SIGNALS.RETURN;\n }\n })\n .otherwise(() => {}); // Handle any other part types if necessary\n\n if (LOOP_SIGNAL === LOOP_SIGNALS.RETURN) {\n break loop;\n } else if (LOOP_SIGNAL === LOOP_SIGNALS.BREAK) {\n break;\n }\n }\n // If the stream finishes without a 'finish' part (e.g. error thrown inside), this loop might exit. Ensure spinner stops.\n if (turn === maxTurns - 1) {\n loading.warn(\"Max interaction turns reached.\");\n return;\n }\n }\n // Fallback spinner stop if loop exits unexpectedly\n loading.stop();\n};\n"]}
1
+ {"version":3,"file":"run-ai-task.js","sourceRoot":"","sources":["../../../src/commands/tasks/run-ai-task.ts"],"names":[],"mappings":"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","sourcesContent":["import {blue, cyan, FileEntry, gray, green, red, spinner, YAML, yellow} from \"@gaubee/nodekit\";\nimport {func_catch} from \"@gaubee/util\";\nimport {streamText, type AssistantModelMessage, type ModelMessage, type ToolCallPart} from \"ai\";\nimport debug from \"debug\";\nimport ms from \"ms\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport {match, P} from \"ts-pattern\";\nimport {safeEnv} from \"../../env.js\";\nimport {getModelMessage, getPromptConfigs} from \"../../helper/prompts-loader.js\";\nimport type {AiTask} from \"../../helper/resolve-ai-tasks.js\";\nimport {tools} from \"./ai-tools.js\";\nimport {providers} from \"./model-providers.js\";\n\nconst log = debug(\"jixo:run-ai-task\");\n\nconst getModel = (model?: string) => {\n return match(model)\n .with(P.string.startsWith(\"deepseek-\"), (model) => providers.deepseek(model))\n .with(P.string.startsWith(\"gemini-\"), (model) => providers.google(model))\n .with(P.string.startsWith(\"o3-\"), P.string.startsWith(\"o1-\"), P.string.startsWith(\"gpt-\"), (model) => providers.openai(model))\n .with(P.string.startsWith(\"claude-\"), (model) => providers.anthropic(model))\n .with(P.string.startsWith(\"grok-\"), (model) => providers.xai(model))\n .with(P.string.includes(\"/\"), (model) => providers.deepinfra(model))\n .otherwise(() => {\n if (safeEnv.JIXO_DEEPSEEK_API_KEY) {\n return providers.deepseek(\"deepseek-chat\");\n }\n if (safeEnv.JIXO_GOOGLE_API_KEY) {\n return providers.google(\"gemini-2.5-pro-preview-05-06\");\n }\n if (safeEnv.JIXO_OPENAI_API_KEY) {\n return providers.openai(\"o3-mini\");\n }\n if (safeEnv.JIXO_ANTHROPIC_API_KEY) {\n return providers.anthropic(\"claude-4-sonnet-20250514\");\n }\n if (safeEnv.JIXO_XAI_API_KEY) {\n return providers.xai(\"grok-3-beta\");\n }\n if (safeEnv.JIXO_DEEPINFRA_API_KEY) {\n return providers.deepinfra(\"meta-llama/Meta-Llama-3.1-405B-Instruct\");\n }\n return providers.deepseek(\"deepseek-reasoner\");\n });\n};\n\nexport const runAiTask = async (ai_task: AiTask, allFiles: FileEntry[], changedFilesSet: Record<string, FileEntry[]>) => {\n const model = getModel(ai_task.model);\n const availableTools = {\n ...(await tools.fileSystem(ai_task.cwd)),\n ...(await tools.memory(path.join(ai_task.cwd, `.jixo/${ai_task.name}.memory.json`))),\n // ...(await tools.fetch()),\n // ...(await tools.git(ai_task.cwd)),\n };\n\n const initialMessages: ModelMessage[] = getModelMessage(ai_task.agents);\n ai_task.startTime;\n const userPrompt = getPromptConfigs()\n .user.content //\n .replace(/\\{\\{task.(\\w+)\\}\\}/g, (_, key) => {\n return Reflect.get(ai_task, key);\n })\n .replace(/\\{\\{env.(\\w+)\\}\\}/g, (_, key) => {\n const envKey = key.toUpperCase();\n const envValue =\n Reflect.get(process.env, envKey) ??\n match(envKey)\n .with(\"USER\", () => os.userInfo().username)\n .otherwise(() => \"\");\n return envValue;\n })\n .replaceAll(\n \"{{allFiles}}\",\n YAML.stringify({\n [ai_task.cwd]: {\n count: allFiles.length,\n file: allFiles.map((e) => e.relativePath),\n },\n }),\n )\n .replaceAll(\n \"{{changedFiles}}\",\n YAML.stringify(\n Object.entries(changedFilesSet).reduce(\n (tree, [dir, changedFiles]) => {\n tree[dir] = {\n count: changedFiles.length,\n files: changedFiles.map((e) => e.relativePath),\n };\n return tree;\n },\n {} as Record<string, {count: number; files: string[]}>,\n ),\n ),\n );\n log(\"USER PROMPT:\", userPrompt);\n initialMessages.push({\n role: \"user\",\n content: userPrompt,\n });\n\n let currentMessages: ModelMessage[] = [...initialMessages];\n const maxTurns = 20; // Safeguard against infinite loops\n const loading = spinner(\"Initializing AI task...\");\n loading.prefixText = \"⏳ \";\n loading.start();\n const endInfo = {\n prefixText: \"\",\n text: \"\",\n suffixText: `⏱️ ${gray(ms(new Date().getTime() - new Date(ai_task.startTime).getTime(), {long: true}))}`,\n };\n\n loop: for (let turn = 0; turn < maxTurns; turn++) {\n loading.text = turn === 0 ? `Connecting To ${model.provider}...` : `Processing turn ${turn + 1}...`;\n\n const result = await streamText({\n model: model,\n messages: currentMessages,\n tools: availableTools,\n toolChoice: \"auto\", // Changed to auto for more flexibility\n });\n\n let fullReasoningText = \"\";\n let fullText = \"\";\n let firstStreamPart = true;\n const requestedToolCalls: ToolCallPart[] = []; // Using any for now, should be ToolCallPart from 'ai'\n\n const assistantMessageContent: AssistantModelMessage[\"content\"] & unknown[] = [];\n const _currentAssistantMessage: AssistantModelMessage = {role: \"assistant\", content: assistantMessageContent};\n\n const LOOP_SIGNALS = {\n RETURN: \"RETURN\",\n BREAK: \"BREAK\",\n CONTINUE: \"CONTINUE\",\n } as const;\n for await (const part of result.fullStream) {\n if (firstStreamPart) {\n firstStreamPart = false;\n loading.text = \"\"; // Clear initial connecting/processing message\n }\n const LOOP_SIGNAL = await match(part)\n .with({type: \"text\"}, (textPart) => {\n loading.prefixText = \"🤖 \";\n let assistantTextPart = assistantMessageContent.findLast((part) => part.type === \"text\");\n if (assistantTextPart == null) {\n assistantTextPart = {type: \"text\", text: \"\"};\n assistantMessageContent.push(assistantTextPart);\n }\n assistantTextPart.text += textPart.text;\n if (fullText === \"\") fullText = \"\\n\"; // For consistent display\n fullText += textPart.text;\n loading.text = fullText.split(\"\\n\").slice(-10).join(\"\\n\");\n })\n .with({type: \"tool-call\"}, (callPart) => {\n loading.prefixText = \"🛠️ \";\n loading.text = \"Requesting tool:\" + blue(callPart.toolName) + gray(\": \" + YAML.stringify(callPart.args).split(\"\\n\").slice(0, 3) + \"...\");\n log(\"\\nQAQ tool-call\", callPart);\n requestedToolCalls.push(callPart);\n // Update assistant message to include tool calls\n assistantMessageContent.push({\n type: \"tool-call\",\n toolCallId: callPart.toolCallId,\n toolName: callPart.toolName,\n args: callPart.args,\n });\n })\n .with({type: \"error\"}, (errorPart) => {\n console.error(\"\\nQAQ error\", errorPart.error);\n loading.prefixText = endInfo.prefixText = \"❌ \";\n loading.text = endInfo.text = red(`Error: ${errorPart.error?.toString()}`);\n return LOOP_SIGNALS.BREAK; // Stop processing on error\n })\n .with({type: \"reasoning\"}, (reasoningPart) => {\n loading.prefixText = \"🤔 \";\n if (fullReasoningText === \"\") loading.text = \"\";\n fullReasoningText += reasoningPart.text;\n loading.text = gray(fullReasoningText.split(\"\\n\").slice(-3).join(\"\\n\"));\n })\n // Add other console logs for debugging if needed, but keep them minimal for production\n .with({type: \"file\"}, (p) => {\n loading.prefixText = \"📃 \";\n loading.text = p.file.mediaType;\n\n log(\"\\nQAQ file\", p.file);\n })\n .with({type: \"source\"}, (p) => {\n loading.prefixText = \"🔗 \";\n if (p.title) {\n loading.text = `[${p.title}](${p.url})`;\n } else {\n loading.text = p.url;\n }\n\n log(\"\\nQAQ source\", p);\n })\n .with({type: \"tool-result\"}, (p) => log(\"\\nQAQ tool-result\", p))\n .with({type: \"tool-call-streaming-start\"}, (p) => log(\"\\nQAQ tool-call-streaming-start\", p))\n .with({type: \"tool-call-delta\"}, (p) => log(\"\\nQAQ tool-call-delta\", p))\n .with({type: \"reasoning-part-finish\"}, (p) => log(\"\\nQAQ reasoning-part-finish\", p))\n .with({type: \"start-step\"}, (p) => log(\"\\nQAQ start-step\", p))\n .with({type: \"finish-step\"}, (p) => log(\"\\nQAQ finish-step\", p))\n .with({type: \"start\"}, (p) => log(\"\\nQAQ start\", p))\n .with({type: \"finish\"}, async (finishPart) => {\n log(\"\\nQAQ finish\", finishPart);\n // Add the assistant's message from this turn to the history\n currentMessages.push(_currentAssistantMessage);\n\n if (finishPart.finishReason === \"stop\" || finishPart.finishReason === \"length\") {\n loading.prefixText = endInfo.prefixText = \"✅ \";\n loading.text = endInfo.text = green(`${cyan(`[${ai_task.name}]`)} Completed`);\n // Task finished without tool calls or after tool calls that didn't lead to more calls.\n return LOOP_SIGNALS.RETURN; // Exit the outer loop and function\n }\n\n if (finishPart.finishReason === \"tool-calls\") {\n if (requestedToolCalls.length === 0) {\n loading.prefixText = endInfo.prefixText = \"🚧 \";\n loading.text = endInfo.text = yellow(`${cyan(`[${ai_task.name}]`)} finished with 'tool-calls' but no tools were requested.`);\n return LOOP_SIGNALS.RETURN; // Exit, something is off\n }\n\n const toolResultMessages: ModelMessage[] = [];\n for (const toolCall of requestedToolCalls) {\n const toolToExecute = availableTools[toolCall.toolName];\n if (!toolToExecute || typeof toolToExecute.execute !== \"function\") {\n console.error(`Tool ${toolCall.toolName} not found or not executable.`);\n toolResultMessages.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n result: JSON.stringify({error: `Tool ${toolCall.toolName} not found or not executable.`}),\n isError: true,\n },\n ],\n });\n continue;\n }\n loading.text = `Executing tool: ${toolCall.toolName}...`;\n const executionResult = await func_catch(() =>\n toolToExecute.execute!(toolCall.args, {\n toolCallId: toolCall.toolCallId,\n messages: currentMessages,\n }),\n )();\n toolResultMessages.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n isError: !executionResult.success,\n result: JSON.stringify(executionResult.success ? executionResult.result : executionResult.error),\n },\n ],\n });\n if (executionResult.success) {\n loading.text = `Tool ${toolCall.toolName} executed.`;\n } else {\n loading.text = `Error executing tool ${toolCall.toolName}.`;\n }\n }\n currentMessages.push(...toolResultMessages);\n // Loop continues for the next turn\n } else {\n // Other finish reasons, potentially an error or unexpected state\n loading.prefixText = endInfo.prefixText = \"🛑 \";\n loading.text = endInfo.text = red(`${cyan(`[${ai_task.name}]`)} task finished with unhandled reason: ${finishPart.finishReason}`);\n return LOOP_SIGNALS.RETURN;\n }\n })\n .otherwise(() => {}); // Handle any other part types if necessary\n\n if (LOOP_SIGNAL === LOOP_SIGNALS.RETURN) {\n break loop;\n } else if (LOOP_SIGNAL === LOOP_SIGNALS.BREAK) {\n break;\n }\n }\n // If the stream finishes without a 'finish' part (e.g. error thrown inside), this loop might exit. Ensure spinner stops.\n if (turn === maxTurns - 1) {\n loading.prefixText = endInfo.prefixText = \"🚧 \";\n loading.text = endInfo.text = yellow(`${cyan(`[${ai_task.name}]`)} Max interaction turns reached.`);\n break;\n }\n }\n // Fallback spinner stop if loop exits unexpectedly\n loading.stopAndPersist(endInfo);\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/run.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,GAAG,GAAU,MAAM,MAAM,EAAE,SAAS;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAC,kBAyC3F,CAAC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/run.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,GAAG,GAAU,MAAM,MAAM,EAAE,SAAS;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAC,kBA+C3F,CAAC"}
@@ -14,9 +14,9 @@ export const run = async (_cwd, options) => {
14
14
  const nameMatcher = options.nameFilter.length ? new Ignore(options.nameFilter, cwd) : { isMatch: () => true };
15
15
  const dirMatcher = options.dirFilter.length ? new Ignore(options.dirFilter, cwd) : { isMatch: () => true };
16
16
  const cwdIgnoreFilepath = path.join(cwd, ".gitignore");
17
- let ignore;
17
+ const ignore = [".git"];
18
18
  if (fs.existsSync(cwdIgnoreFilepath)) {
19
- ignore = fs.readFileSync(cwdIgnoreFilepath, "utf-8").split("\n");
19
+ ignore.push(...fs.readFileSync(cwdIgnoreFilepath, "utf-8").split("\n"));
20
20
  }
21
21
  const allFiles = [...walkFiles(cwd, { ignore })];
22
22
  const changedFiles = (await findChangedFilesSinceCommit("@jixo", cwd)).filter((file) => {
@@ -24,21 +24,25 @@ export const run = async (_cwd, options) => {
24
24
  });
25
25
  // const run_tasks: Array<Func> = [];
26
26
  for (const ai_task of ai_tasks) {
27
- const { dir: task_dir } = ai_task;
28
- if (!dirMatcher.isMatch(task_dir)) {
27
+ const { dirs: task_dirs } = ai_task;
28
+ if (!task_dirs.some((dir) => dirMatcher.isMatch(dir))) {
29
29
  continue;
30
30
  }
31
31
  if (!nameMatcher.isMatch(ai_task.name)) {
32
32
  continue;
33
33
  }
34
- const task_changedFiles = cwd === task_dir
35
- ? changedFiles
36
- : iter_map_not_null(changedFiles, (file) => {
37
- if (file.path.startsWith(task_dir + "/")) {
38
- return new FileEntry(file.path, { cwd: task_dir, state: file.stats });
39
- }
40
- });
41
- const task_allFiles = cwd === task_dir ? allFiles : [...walkFiles(task_dir, { ignore })];
34
+ const isCwdTask = cwd === task_dirs[0] && task_dirs.length === 1;
35
+ const task_changedFiles = isCwdTask
36
+ ? { [cwd]: changedFiles }
37
+ : task_dirs.reduce((tree, task_dir) => {
38
+ tree[task_dir] = iter_map_not_null(changedFiles, (file) => {
39
+ if (file.path.startsWith(task_dirs + "/")) {
40
+ return new FileEntry(file.path, { cwd: task_dir, state: file.stats });
41
+ }
42
+ });
43
+ return tree;
44
+ }, {});
45
+ const task_allFiles = isCwdTask ? allFiles : task_dirs.map((task_dir) => [...walkFiles(task_dir, { ignore })]).flat();
42
46
  loadJixoEnv(cwd);
43
47
  await runAiTask(ai_task, task_allFiles, task_changedFiles);
44
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/tasks/run.ts"],"names":[],"mappings":"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","sourcesContent":["import {FileEntry, Ignore, normalizeFilePath, walkFiles} from \"@gaubee/nodekit\";\nimport {iter_map_not_null} from \"@gaubee/util\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {loadConfig} from \"../../config.js\";\nimport {loadJixoEnv} from \"../../env.js\";\nimport {findChangedFilesSinceCommit} from \"../../helper/find-changes.js\";\nimport {resolveAiTasks} from \"../../helper/resolve-ai-tasks.js\";\nimport {runAiTask} from \"./run-ai-task.js\";\n\nexport const run = async (_cwd: string, options: {nameFilter: string[]; dirFilter: string[]}) => {\n const cwd = normalizeFilePath(_cwd);\n const config = await loadConfig(cwd);\n const ai_tasks = resolveAiTasks(cwd, config.tasks);\n const nameMatcher = options.nameFilter.length ? new Ignore(options.nameFilter, cwd) : {isMatch: () => true};\n const dirMatcher = options.dirFilter.length ? new Ignore(options.dirFilter, cwd) : {isMatch: () => true};\n const cwdIgnoreFilepath = path.join(cwd, \".gitignore\");\n let ignore: undefined | string[];\n if (fs.existsSync(cwdIgnoreFilepath)) {\n ignore = fs.readFileSync(cwdIgnoreFilepath, \"utf-8\").split(\"\\n\");\n }\n\n const allFiles = [...walkFiles(cwd, {ignore})];\n const changedFiles = (await findChangedFilesSinceCommit(\"@jixo\", cwd)).filter((file) => {\n return file.path.startsWith(cwd + \"/\");\n });\n\n // const run_tasks: Array<Func> = [];\n for (const ai_task of ai_tasks) {\n const {dir: task_dir} = ai_task;\n if (!dirMatcher.isMatch(task_dir)) {\n continue;\n }\n if (!nameMatcher.isMatch(ai_task.name)) {\n continue;\n }\n\n const task_changedFiles =\n cwd === task_dir\n ? changedFiles\n : iter_map_not_null(changedFiles, (file) => {\n if (file.path.startsWith(task_dir + \"/\")) {\n return new FileEntry(file.path, {cwd: task_dir, state: file.stats});\n }\n });\n\n const task_allFiles = cwd === task_dir ? allFiles : [...walkFiles(task_dir, {ignore})];\n\n loadJixoEnv(cwd);\n await runAiTask(ai_task, task_allFiles, task_changedFiles);\n }\n};\n"]}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/tasks/run.ts"],"names":[],"mappings":"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","sourcesContent":["import {FileEntry, Ignore, normalizeFilePath, walkFiles} from \"@gaubee/nodekit\";\nimport {iter_map_not_null} from \"@gaubee/util\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {loadConfig} from \"../../config.js\";\nimport {loadJixoEnv} from \"../../env.js\";\nimport {findChangedFilesSinceCommit} from \"../../helper/find-changes.js\";\nimport {resolveAiTasks} from \"../../helper/resolve-ai-tasks.js\";\nimport {runAiTask} from \"./run-ai-task.js\";\n\nexport const run = async (_cwd: string, options: {nameFilter: string[]; dirFilter: string[]}) => {\n const cwd = normalizeFilePath(_cwd);\n const config = await loadConfig(cwd);\n const ai_tasks = resolveAiTasks(cwd, config.tasks);\n const nameMatcher = options.nameFilter.length ? new Ignore(options.nameFilter, cwd) : {isMatch: () => true};\n const dirMatcher = options.dirFilter.length ? new Ignore(options.dirFilter, cwd) : {isMatch: () => true};\n const cwdIgnoreFilepath = path.join(cwd, \".gitignore\");\n const ignore = [\".git\"];\n if (fs.existsSync(cwdIgnoreFilepath)) {\n ignore.push(...fs.readFileSync(cwdIgnoreFilepath, \"utf-8\").split(\"\\n\"));\n }\n\n const allFiles = [...walkFiles(cwd, {ignore})];\n const changedFiles = (await findChangedFilesSinceCommit(\"@jixo\", cwd)).filter((file) => {\n return file.path.startsWith(cwd + \"/\");\n });\n\n // const run_tasks: Array<Func> = [];\n for (const ai_task of ai_tasks) {\n const {dirs: task_dirs} = ai_task;\n if (!task_dirs.some((dir) => dirMatcher.isMatch(dir))) {\n continue;\n }\n if (!nameMatcher.isMatch(ai_task.name)) {\n continue;\n }\n const isCwdTask = cwd === task_dirs[0] && task_dirs.length === 1;\n\n const task_changedFiles = isCwdTask\n ? {[cwd]: changedFiles}\n : task_dirs.reduce(\n (tree, task_dir) => {\n tree[task_dir] = iter_map_not_null(changedFiles, (file) => {\n if (file.path.startsWith(task_dirs + \"/\")) {\n return new FileEntry(file.path, {cwd: task_dir, state: file.stats});\n }\n });\n return tree;\n },\n {} as Record<string, FileEntry[]>,\n );\n\n const task_allFiles = isCwdTask ? allFiles : task_dirs.map((task_dir) => [...walkFiles(task_dir, {ignore})]).flat();\n\n loadJixoEnv(cwd);\n await runAiTask(ai_task, task_allFiles, task_changedFiles);\n }\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"find-changes.d.ts","sourceRoot":"","sources":["../../src/helper/find-changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AAUhE,wBAAsB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,GAAE,MAAY,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAkGjH"}
1
+ {"version":3,"file":"find-changes.d.ts","sourceRoot":"","sources":["../../src/helper/find-changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AAUhE,wBAAsB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,GAAE,MAAY,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAyGjH"}
@@ -21,47 +21,54 @@ export async function findChangedFilesSinceCommit(messagePattern, cwd = ".") {
21
21
  baseCommitForDiff = targetCommitSha;
22
22
  }
23
23
  else {
24
- console.warn(gray(`No commit found with message pattern: "${messagePattern}". Only uncommitted changes will be listed if any.`));
24
+ console.warn(gray(`No commit found with message pattern: "${messagePattern}". All files (includes uncommitted changes) will be listed.`));
25
25
  }
26
26
  }
27
27
  catch (error) {
28
28
  // git log --grep 通常在没有匹配时返回空输出和退出码0。
29
29
  // 如果这里出错,可能是更严重的问题。
30
30
  const gitError = error;
31
- console.warn(red(`Could not determine base commit with pattern "${messagePattern}". Only uncommitted changes will be listed. Details:`));
31
+ console.warn(red(`Could not determine base commit with pattern "${messagePattern}". All files (includes uncommitted changes) will be listed. Details:`));
32
32
  console.error(gitError.message);
33
33
  }
34
+ if (!baseCommitForDiff) {
35
+ return execSync("git ls-tree HEAD --name-only -r", { cwd, encoding: "utf8", stdio: "pipe" })
36
+ .toString()
37
+ .trim()
38
+ .split("\n")
39
+ .map((filepath) => {
40
+ return new FileEntry(path.join(cwd, filepath), { cwd });
41
+ });
42
+ }
34
43
  const changedFiles = new Set();
35
44
  // 2. 列出从该 commit 之后到 HEAD (最新已提交) 的所有变更文件
36
- if (baseCommitForDiff) {
37
- try {
38
- const committedChangesOutput = execSync(`git diff ${baseCommitForDiff} HEAD --name-only`, gitCommandOptions).toString().trim();
39
- if (committedChangesOutput) {
40
- committedChangesOutput.split("\n").forEach((file) => {
45
+ try {
46
+ const committedChangesOutput = execSync(`git diff ${baseCommitForDiff} HEAD --name-only`, gitCommandOptions).toString().trim();
47
+ if (committedChangesOutput) {
48
+ committedChangesOutput.split("\n").forEach((file) => {
49
+ if (file.trim())
50
+ changedFiles.add(file.trim());
51
+ });
52
+ }
53
+ }
54
+ catch (error) {
55
+ const gitError = error;
56
+ // `git diff` 在有差异时退出码为1,无差异时为0。execSync 默认在非0时抛错。
57
+ if (gitError.status === 1 && gitError.stdout) {
58
+ // 有差异
59
+ const output = gitError.stdout ?? "";
60
+ if (output) {
61
+ output.split("\n").forEach((file) => {
41
62
  if (file.trim())
42
63
  changedFiles.add(file.trim());
43
64
  });
44
65
  }
45
66
  }
46
- catch (error) {
47
- const gitError = error;
48
- // `git diff` 在有差异时退出码为1,无差异时为0。execSync 默认在非0时抛错。
49
- if (gitError.status === 1 && gitError.stdout) {
50
- // 有差异
51
- const output = gitError.stdout ?? "";
52
- if (output) {
53
- output.split("\n").forEach((file) => {
54
- if (file.trim())
55
- changedFiles.add(file.trim());
56
- });
57
- }
58
- }
59
- else if (gitError.status !== 0) {
60
- // 其他错误
61
- console.error(`Error getting committed changes since ${baseCommitForDiff}: ${gitError.stderr || gitError.message}`);
62
- }
63
- // status 0 (无差异) 表示没有输出,是正常情况
67
+ else if (gitError.status !== 0) {
68
+ // 其他错误
69
+ console.error(`Error getting committed changes since ${baseCommitForDiff}: ${gitError.stderr || gitError.message}`);
64
70
  }
71
+ // status 0 (无差异) 表示没有输出,是正常情况
65
72
  }
66
73
  // 3. 列出工作区中未提交的变更文件
67
74
  const uncommittedCommands = [
@@ -1 +1 @@
1
- {"version":3,"file":"find-changes.js","sourceRoot":"","sources":["../../src/helper/find-changes.ts"],"names":[],"mappings":"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","sourcesContent":["import {FileEntry, gray, red, walkFiles} from \"@gaubee/nodekit\";\nimport {type ExecException, execSync} from \"node:child_process\";\nimport path from \"node:path\";\n\ninterface GitError extends ExecException {\n status?: number | null;\n // stderr?: Buffer | string;\n // stdout?: Buffer | string;\n}\n\nexport async function findChangedFilesSinceCommit(messagePattern: string, cwd: string = \".\"): Promise<FileEntry[]> {\n let repoPath = cwd;\n try {\n // 获取 Git 仓库位置,同时确保在 Git 仓库中运行\n repoPath = execSync(\"git rev-parse --show-toplevel\", {cwd, encoding: \"utf8\", stdio: \"pipe\"}).toString().trim();\n } catch (e) {\n return [...walkFiles(repoPath)];\n }\n const gitCommandOptions = {cwd: repoPath, encoding: \"utf8\" as BufferEncoding, stdio: \"pipe\" as \"pipe\"}; // stdio: 'pipe' to access stdout/stderr on error\n\n let baseCommitForDiff: string | null = null;\n\n try {\n // 1. 找到包含特定标记的最新 commit SHA\n // 使用 --fixed-strings 来精确匹配字符串 \"@jixo\",而不是作为正则表达式\n const targetCommitSha = execSync(`git log --grep=\"${messagePattern}\" --fixed-strings -n 1 --pretty=format:%H`, gitCommandOptions).toString().trim();\n\n if (targetCommitSha) {\n console.log(`Found target commit SHA: ${targetCommitSha} for message pattern: \"${messagePattern}\"`);\n baseCommitForDiff = targetCommitSha;\n } else {\n console.warn(gray(`No commit found with message pattern: \"${messagePattern}\". Only uncommitted changes will be listed if any.`));\n }\n } catch (error) {\n // git log --grep 通常在没有匹配时返回空输出和退出码0。\n // 如果这里出错,可能是更严重的问题。\n const gitError = error as GitError;\n console.warn(red(`Could not determine base commit with pattern \"${messagePattern}\". Only uncommitted changes will be listed. Details:`));\n console.error(gitError.message);\n }\n\n const changedFiles = new Set<string>();\n\n // 2. 列出从该 commit 之后到 HEAD (最新已提交) 的所有变更文件\n if (baseCommitForDiff) {\n try {\n const committedChangesOutput = execSync(`git diff ${baseCommitForDiff} HEAD --name-only`, gitCommandOptions).toString().trim();\n if (committedChangesOutput) {\n committedChangesOutput.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } catch (error) {\n const gitError = error as GitError;\n // `git diff` 在有差异时退出码为1,无差异时为0。execSync 默认在非0时抛错。\n if (gitError.status === 1 && gitError.stdout) {\n // 有差异\n const output = gitError.stdout ?? \"\";\n if (output) {\n output.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } else if (gitError.status !== 0) {\n // 其他错误\n console.error(`Error getting committed changes since ${baseCommitForDiff}: ${gitError.stderr || gitError.message}`);\n }\n // status 0 (无差异) 表示没有输出,是正常情况\n }\n }\n\n // 3. 列出工作区中未提交的变更文件\n const uncommittedCommands = [\n {cmd: \"git diff --name-only --cached\", desc: \"staged changes\"}, // 已暂存\n {cmd: \"git diff --name-only\", desc: \"unstaged changes\"}, // 未暂存 (对比工作区和暂存区)\n {cmd: \"git ls-files --others --exclude-standard\", desc: \"untracked files\"}, // 未跟踪\n ];\n\n for (const item of uncommittedCommands) {\n try {\n const output = execSync(item.cmd, gitCommandOptions).toString().trim();\n if (output) {\n output.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } catch (error) {\n const gitError = error as GitError;\n if (item.cmd.startsWith(\"git diff\") && gitError.status === 1 && gitError.stdout) {\n // git diff 有差异\n const output = gitError.stdout ?? \"\";\n if (output) {\n output.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } else if (gitError.status !== 0 && !(item.cmd.startsWith(\"git diff\") && gitError.status === 1)) {\n // 其他错误\n // 对于 ls-files,如果出错,也记录\n console.error(`Error getting ${item.desc}: ${gitError.stderr || gitError.message}`);\n }\n // `git ls-files` 在没有文件时退出码为0,输出为空。\n // `git diff` 在没有差异时退出码为0,输出为空。\n }\n }\n\n // 返回相对于仓库根目录的文件路径\n return [...changedFiles].map((filepath) => new FileEntry(path.resolve(repoPath, filepath), {cwd: repoPath}));\n}\n"]}
1
+ {"version":3,"file":"find-changes.js","sourceRoot":"","sources":["../../src/helper/find-changes.ts"],"names":[],"mappings":"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","sourcesContent":["import {FileEntry, gray, red, walkFiles} from \"@gaubee/nodekit\";\nimport {type ExecException, execSync} from \"node:child_process\";\nimport path from \"node:path\";\n\ninterface GitError extends ExecException {\n status?: number | null;\n // stderr?: Buffer | string;\n // stdout?: Buffer | string;\n}\n\nexport async function findChangedFilesSinceCommit(messagePattern: string, cwd: string = \".\"): Promise<FileEntry[]> {\n let repoPath = cwd;\n try {\n // 获取 Git 仓库位置,同时确保在 Git 仓库中运行\n repoPath = execSync(\"git rev-parse --show-toplevel\", {cwd, encoding: \"utf8\", stdio: \"pipe\"}).toString().trim();\n } catch (e) {\n return [...walkFiles(repoPath)];\n }\n const gitCommandOptions = {cwd: repoPath, encoding: \"utf8\" as BufferEncoding, stdio: \"pipe\" as \"pipe\"}; // stdio: 'pipe' to access stdout/stderr on error\n\n let baseCommitForDiff: string | null = null;\n\n try {\n // 1. 找到包含特定标记的最新 commit SHA\n // 使用 --fixed-strings 来精确匹配字符串 \"@jixo\",而不是作为正则表达式\n const targetCommitSha = execSync(`git log --grep=\"${messagePattern}\" --fixed-strings -n 1 --pretty=format:%H`, gitCommandOptions).toString().trim();\n\n if (targetCommitSha) {\n console.log(`Found target commit SHA: ${targetCommitSha} for message pattern: \"${messagePattern}\"`);\n baseCommitForDiff = targetCommitSha;\n } else {\n console.warn(gray(`No commit found with message pattern: \"${messagePattern}\". All files (includes uncommitted changes) will be listed.`));\n }\n } catch (error) {\n // git log --grep 通常在没有匹配时返回空输出和退出码0。\n // 如果这里出错,可能是更严重的问题。\n const gitError = error as GitError;\n console.warn(red(`Could not determine base commit with pattern \"${messagePattern}\". All files (includes uncommitted changes) will be listed. Details:`));\n console.error(gitError.message);\n }\n if (!baseCommitForDiff) {\n return execSync(\"git ls-tree HEAD --name-only -r\", {cwd, encoding: \"utf8\", stdio: \"pipe\"})\n .toString()\n .trim()\n .split(\"\\n\")\n .map((filepath) => {\n return new FileEntry(path.join(cwd, filepath), {cwd});\n });\n }\n\n const changedFiles = new Set<string>();\n\n // 2. 列出从该 commit 之后到 HEAD (最新已提交) 的所有变更文件\n\n try {\n const committedChangesOutput = execSync(`git diff ${baseCommitForDiff} HEAD --name-only`, gitCommandOptions).toString().trim();\n if (committedChangesOutput) {\n committedChangesOutput.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } catch (error) {\n const gitError = error as GitError;\n // `git diff` 在有差异时退出码为1,无差异时为0。execSync 默认在非0时抛错。\n if (gitError.status === 1 && gitError.stdout) {\n // 有差异\n const output = gitError.stdout ?? \"\";\n if (output) {\n output.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } else if (gitError.status !== 0) {\n // 其他错误\n console.error(`Error getting committed changes since ${baseCommitForDiff}: ${gitError.stderr || gitError.message}`);\n }\n // status 0 (无差异) 表示没有输出,是正常情况\n }\n // 3. 列出工作区中未提交的变更文件\n const uncommittedCommands = [\n {cmd: \"git diff --name-only --cached\", desc: \"staged changes\"}, // 已暂存\n {cmd: \"git diff --name-only\", desc: \"unstaged changes\"}, // 未暂存 (对比工作区和暂存区)\n {cmd: \"git ls-files --others --exclude-standard\", desc: \"untracked files\"}, // 未跟踪\n ];\n\n for (const item of uncommittedCommands) {\n try {\n const output = execSync(item.cmd, gitCommandOptions).toString().trim();\n if (output) {\n output.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } catch (error) {\n const gitError = error as GitError;\n if (item.cmd.startsWith(\"git diff\") && gitError.status === 1 && gitError.stdout) {\n // git diff 有差异\n const output = gitError.stdout ?? \"\";\n if (output) {\n output.split(\"\\n\").forEach((file) => {\n if (file.trim()) changedFiles.add(file.trim());\n });\n }\n } else if (gitError.status !== 0 && !(item.cmd.startsWith(\"git diff\") && gitError.status === 1)) {\n // 其他错误\n // 对于 ls-files,如果出错,也记录\n console.error(`Error getting ${item.desc}: ${gitError.stderr || gitError.message}`);\n }\n // `git ls-files` 在没有文件时退出码为0,输出为空。\n // `git diff` 在没有差异时退出码为0,输出为空。\n }\n }\n\n // 返回相对于仓库根目录的文件路径\n return [...changedFiles].map((filepath) => new FileEntry(path.resolve(repoPath, filepath), {cwd: repoPath}));\n}\n"]}
@@ -13,7 +13,7 @@ export declare const resolveAiTasks: (cwd: string, config_tasks: JixoConfig["tas
13
13
  } & {
14
14
  name: string;
15
15
  cwd: string;
16
- dir: string;
16
+ dirs: string[];
17
17
  agents: string[];
18
18
  model: string;
19
19
  useMemory: string;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-ai-tasks.d.ts","sourceRoot":"","sources":["../../src/helper/resolve-ai-tasks.ts"],"names":[],"mappings":"AAKA,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,cAAc,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,EAAE,cAAc,UAAU,CAAC,OAAO,CAAC;UAGnE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC;aACjB,MAAM;;UAGT,MAAM;SACP,MAAM;SACN,MAAM;YACH,MAAM,EAAE;WACT,MAAM;eACF,MAAM;YACT,MAAM;SACT,MAAM;eACA,MAAM;IA+FpB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"resolve-ai-tasks.d.ts","sourceRoot":"","sources":["../../src/helper/resolve-ai-tasks.ts"],"names":[],"mappings":"AAKA,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,cAAc,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,EAAE,cAAc,UAAU,CAAC,OAAO,CAAC;UAGnE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC;aACjB,MAAM;;UAGT,MAAM;SACP,MAAM;UACL,MAAM,EAAE;YACN,MAAM,EAAE;WACT,MAAM;eACF,MAAM;YACT,MAAM;SACT,MAAM;eACA,MAAM;IAwGpB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -14,8 +14,16 @@ export const resolveAiTasks = (cwd, config_tasks) => {
14
14
  const config_tasks_arr = Array.isArray(config_tasks) ? config_tasks : [config_tasks];
15
15
  const tasks = [];
16
16
  const addTask = (ai_task, options) => {
17
- const { name: inner_task_name, dir: _task_dir = cwd } = ai_task.data;
18
- const task_dir = normalizeFilePath(path.resolve(cwd, _task_dir));
17
+ const { name: inner_task_name } = ai_task.data;
18
+ const task_dir = match(z.union([z.string(), z.string().array()]).safeParse(ai_task.data.dirs ?? ai_task.data.dir))
19
+ .with({ success: true }, (it) => {
20
+ const dirList = Array.isArray(it.data) ? it.data : [it.data];
21
+ return dirList.map((dir) => normalizeFilePath(path.resolve(cwd, dir)));
22
+ })
23
+ .otherwise(() => []);
24
+ if (task_dir.length === 0) {
25
+ task_dir.push(cwd);
26
+ }
19
27
  const task_name = inner_task_name || options.defaultName;
20
28
  const useMemory = ai_task.data.useMemory || task_name;
21
29
  const useLog = ai_task.data.useLog || task_name;
@@ -30,7 +38,7 @@ export const resolveAiTasks = (cwd, config_tasks) => {
30
38
  ...ai_task,
31
39
  name: task_name,
32
40
  cwd: cwd,
33
- dir: task_dir,
41
+ dirs: task_dir,
34
42
  agents: match(z.union([z.string(), z.string().array()]).safeParse(ai_task.data.agents))
35
43
  .with({ success: true, data: P.select() }, (agents) => {
36
44
  return Array.isArray(agents) ? agents : agents.split(/\s+/);
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-ai-tasks.js","sourceRoot":"","sources":["../../src/helper/resolve-ai-tasks.ts"],"names":[],"mappings":"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","sourcesContent":["import {matter, normalizeFilePath, readMarkdown, walkFiles, writeMarkdown} from \"@gaubee/nodekit\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {match, P} from \"ts-pattern\";\nimport z from \"zod\";\nimport {type JixoConfig} from \"../config.js\";\n\n/**\n * 将 config.tasks 字段转化成具体的 ai-tasks 信息\n * @param cwd\n * @param config_tasks\n * @returns\n */\nexport const resolveAiTasks = (cwd: string, config_tasks: JixoConfig[\"tasks\"]) => {\n const config_tasks_arr = Array.isArray(config_tasks) ? config_tasks : [config_tasks];\n type TaskBase = {\n data: {[key: string]: any};\n content: string;\n };\n type AiTask = TaskBase & {\n name: string;\n cwd: string;\n dir: string;\n agents: string[];\n model: string;\n useMemory: string;\n useLog: string;\n log: string;\n startTime: string;\n };\n const tasks: AiTask[] = [];\n const addTask = (\n ai_task: TaskBase,\n options: {\n defaultName: string;\n },\n ) => {\n const {name: inner_task_name, dir: _task_dir = cwd} = ai_task.data;\n const task_dir = normalizeFilePath(path.resolve(cwd, _task_dir));\n\n const task_name = inner_task_name || options.defaultName;\n const useMemory = ai_task.data.useMemory || task_name;\n const useLog = ai_task.data.useLog || task_name;\n\n const log_filepath = path.join(cwd, `.jixo/${useLog}.log.md`);\n if (!fs.existsSync(log_filepath)) {\n writeMarkdown(log_filepath, ``, {\n createTime: new Date().toISOString(),\n updateTime: new Date().toISOString(),\n });\n }\n\n tasks.push({\n ...ai_task,\n name: task_name,\n cwd: cwd,\n dir: task_dir,\n agents: match(z.union([z.string(), z.string().array()]).safeParse(ai_task.data.agents))\n .with({success: true, data: P.select()}, (agents) => {\n return Array.isArray(agents) ? agents : agents.split(/\\s+/);\n })\n .otherwise(() => []),\n model: match(z.string().safeParse(ai_task.data.model))\n .with({success: true, data: P.select()}, (model) => model)\n .otherwise(() => \"\"),\n useMemory,\n useLog,\n log: fs.readFileSync(log_filepath, \"utf-8\"),\n startTime: new Date().toISOString(),\n });\n };\n\n for (const config_task of config_tasks_arr) {\n match(config_task)\n .with(\n {\n type: \"dir\",\n dirname: P.string.select(),\n },\n (dirname) => {\n for (const entry of walkFiles(path.resolve(cwd, dirname), {\n matchFile(entry) {\n return entry.name.endsWith(\".task.md\");\n },\n })) {\n addTask(readMarkdown(entry.path), {\n defaultName: entry.name.slice(0, -\".task.md\".length),\n });\n }\n },\n )\n .with(\n {\n type: \"file\",\n filename: P.string.select(\"filename\"),\n name: P.string.select(\"name\").optional(),\n },\n (m) => {\n addTask(readMarkdown(m.filename), {\n defaultName: m.name ?? m.filename.slice(0, -\".task.md\".length),\n });\n },\n )\n .with(P.string.select(), (mdContent) => {\n addTask(matter(mdContent), {\n defaultName: `${tasks.length + 1}`,\n });\n })\n .with(\n {\n type: \"prompt\",\n content: P.string.select(\"content\"),\n name: P.string.select(\"name\").optional(),\n },\n (m) => {\n addTask(matter(m.content), {\n defaultName: m.name ?? `${tasks.length + 1}`,\n });\n },\n )\n .exhaustive();\n }\n return tasks;\n};\n\nexport type AiTask = ReturnType<typeof resolveAiTasks>[number];\n"]}
1
+ {"version":3,"file":"resolve-ai-tasks.js","sourceRoot":"","sources":["../../src/helper/resolve-ai-tasks.ts"],"names":[],"mappings":"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","sourcesContent":["import {matter, normalizeFilePath, readMarkdown, walkFiles, writeMarkdown} from \"@gaubee/nodekit\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {match, P} from \"ts-pattern\";\nimport z from \"zod\";\nimport {type JixoConfig} from \"../config.js\";\n\n/**\n * 将 config.tasks 字段转化成具体的 ai-tasks 信息\n * @param cwd\n * @param config_tasks\n * @returns\n */\nexport const resolveAiTasks = (cwd: string, config_tasks: JixoConfig[\"tasks\"]) => {\n const config_tasks_arr = Array.isArray(config_tasks) ? config_tasks : [config_tasks];\n type TaskBase = {\n data: {[key: string]: any};\n content: string;\n };\n type AiTask = TaskBase & {\n name: string;\n cwd: string;\n dirs: string[];\n agents: string[];\n model: string;\n useMemory: string;\n useLog: string;\n log: string;\n startTime: string;\n };\n const tasks: AiTask[] = [];\n const addTask = (\n ai_task: TaskBase,\n options: {\n defaultName: string;\n },\n ) => {\n const {name: inner_task_name} = ai_task.data;\n\n const task_dir = match(z.union([z.string(), z.string().array()]).safeParse(ai_task.data.dirs ?? ai_task.data.dir))\n .with({success: true}, (it) => {\n const dirList = Array.isArray(it.data) ? it.data : [it.data];\n return dirList.map((dir) => normalizeFilePath(path.resolve(cwd, dir)));\n })\n .otherwise(() => []);\n if (task_dir.length === 0) {\n task_dir.push(cwd);\n }\n\n const task_name = inner_task_name || options.defaultName;\n const useMemory = ai_task.data.useMemory || task_name;\n const useLog = ai_task.data.useLog || task_name;\n\n const log_filepath = path.join(cwd, `.jixo/${useLog}.log.md`);\n if (!fs.existsSync(log_filepath)) {\n writeMarkdown(log_filepath, ``, {\n createTime: new Date().toISOString(),\n updateTime: new Date().toISOString(),\n });\n }\n\n tasks.push({\n ...ai_task,\n name: task_name,\n cwd: cwd,\n dirs: task_dir,\n agents: match(z.union([z.string(), z.string().array()]).safeParse(ai_task.data.agents))\n .with({success: true, data: P.select()}, (agents) => {\n return Array.isArray(agents) ? agents : agents.split(/\\s+/);\n })\n .otherwise(() => []),\n model: match(z.string().safeParse(ai_task.data.model))\n .with({success: true, data: P.select()}, (model) => model)\n .otherwise(() => \"\"),\n useMemory,\n useLog,\n log: fs.readFileSync(log_filepath, \"utf-8\"),\n startTime: new Date().toISOString(),\n });\n };\n\n for (const config_task of config_tasks_arr) {\n match(config_task)\n .with(\n {\n type: \"dir\",\n dirname: P.string.select(),\n },\n (dirname) => {\n for (const entry of walkFiles(path.resolve(cwd, dirname), {\n matchFile(entry) {\n return entry.name.endsWith(\".task.md\");\n },\n })) {\n addTask(readMarkdown(entry.path), {\n defaultName: entry.name.slice(0, -\".task.md\".length),\n });\n }\n },\n )\n .with(\n {\n type: \"file\",\n filename: P.string.select(\"filename\"),\n name: P.string.select(\"name\").optional(),\n },\n (m) => {\n addTask(readMarkdown(m.filename), {\n defaultName: m.name ?? m.filename.slice(0, -\".task.md\".length),\n });\n },\n )\n .with(P.string.select(), (mdContent) => {\n addTask(matter(mdContent), {\n defaultName: `${tasks.length + 1}`,\n });\n })\n .with(\n {\n type: \"prompt\",\n content: P.string.select(\"content\"),\n name: P.string.select(\"name\").optional(),\n },\n (m) => {\n addTask(matter(m.content), {\n defaultName: m.name ?? `${tasks.length + 1}`,\n });\n },\n )\n .exhaustive();\n }\n return tasks;\n};\n\nexport type AiTask = ReturnType<typeof resolveAiTasks>[number];\n"]}
package/dist/prompts.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "data": {
19
19
  "parent": []
20
20
  },
21
- "content": "你是一个AI工具集,叫做 JIXO,你拥有多种技能,可以任意组合成一个“执行者”。\n\n- 本次任务的 工作空间:`{{task.cwd}}`\n > 工作空间 是指该目录下有一个 `.jixo` 文件夹,里面包含了一些“执行者”的 日志和记忆\n > 通常来说不需要读取该文件夹的内容,可以直接忽略\n- 本次任务的 任务目录:`{{task.dir}}`\n > 任务目录 是指 “执行者” 执行任务所需的资源文件夹,可能需要在这个目录里读取文件或者写入文件\n- 本次任务的开始时间是:`{{task.startTime}}`\n- 本次任务的执行者是:`{{task.name}}`\n\n**IMPORTANT: 你必须通过调用工具来与文件系统交互。例如,读取文件必须使用 'read_file',写入文件必须使用 'write_file' 或 'edit_file'。任何声称要进行文件操作的意图,都必须紧随一个相应的工具调用。不要仅仅声明意图,然后停止或返回文本。**\n\n**IMPORTANT: 你是一个有独立思考能力的工具,如果没有特别说明,是不需要与用户进行交互的。你的最终目标是使用合理的成本完成指定的任务。如果你觉得任务不合理,那么可以通过对任务做留言的方式,到 `./.jixo/{{task.useLog}}.log.md` 中进行写入,来告知用户。**\n\n### 这是上次执行完任务后的工作日志总结\n\n目前文件 `./.jixo/{{task.useLog}}.log.md` 完整内容如下(你不需要再去读取该文件):\n\n```md\n{{task.log}}\n```\n\n### 这里的当前 任务目录 的文件列表(这里不包含被 .gitignore 忽略的文件)\n\n```yaml\n{{allFiles}}\n```\n\n### 这里的上次任务到现在的变更的文件列表\n\n```yaml\n{{changedFiles}}\n```\n\n### 你的任务如下(静默地完成任务,不要对用户做任何询问,如果有疑虑,可以通过留言的方式告知用户):\n\n{{task.content}}\n\n### 每次执行任务都遵循以下步骤:\n\n1. 用户标识:\n\n- 你应该假设你正在与 用户: `{{env.user}}` 交互\n\n2. 内存检索:\n\n- 总是以“记住(Remembering)……”作为聊天的开始,并从你的知识图谱中检索所有相关信息\n- 永远把你的知识图谱称为你的“记忆(memory)”\n\n3. 记忆\n\n- 在执行用户下发的任务时,注意任何属于以下类别的新信息:\n 1. **Basic Identity** 基本身份(年龄、性别、工作地点、职称、教育程度等)\n 2. **Behaviors** 行为(兴趣、习惯等)\n 3. **Preferences** 偏好(沟通风格、首选语言等)\n 4. **Goals** 目标(目标、目标、抱负等)\n 5. **Relationships** 人际关系(个人和职业关系高达3度的分离)\n\n4. 记忆更新:\n\n- 如果在执行任务的过程中收集了任何新的信息,请按照以下方式更新你的记忆:\n 1. 为反复出现的 组织(organizations)、人员(people) 和 重大事件(significant events) 创建 实体(entities)\n 2. 使用 关系(relations) 将它们连接到 当前实体(current entities)\n 3. 以 观察(observations) 的形式存储有关他们的 事实(facts)\n\n### 任务完成后的步骤:\n\n请你对现有的记忆内容进行补充总结,用于下一次启动任务时的记忆。将这些记忆创建或者追加到 `./.jixo/{{task.useLog}}.log.md` 这个文件里。记忆的内容格式如下:\n\n```md\n- 时间:`本次任务开始时间`,执行者:`@本次任务的执行者`,第N次执行任务:\n - 新增文件`xxxx`: 这里是新增文件的大纲,在300字以内进行概括,主要描述该文件的基本结构块有哪些。比如如果是markdown文件,那么就提供一下文件的目录信息。如果是代码,那么就解释一下新增了什么类什么函数等等。其它类型的文件就做简单的概括。\n - 修改文件`xxxx`: 这里是修改文件的大纲,在200字以内进行概括。\n - 修改文件`xxxx`: 如果200字无法概括修改内容,那么就对概括内容进行拆分,使用多条。\n - 删除文件`xxxx`: 这里是删除文件的大纲,在100字以内进行概括。\n - 遇到问题1:问题的标题\n - 问题的描述1..\n - 问题的描述2..\n - 请用户 `{{env.user}}` 提供回答:\n - <!-- 请用户提供回复,来替换这条注释 -->\n - 遇到问题2:问题的标题\n - 问题的描述1..\n - 问题的描述2..\n - 请用户 `{{env.user}}` 提供回答:\n - <!-- 请用户提供回复,来替换这条注释 -->\n```\n\n1. 请同步修改元数据中的 `updateTime`,更新为本次任务的开始时间。\n"
21
+ "content": "你是一个AI工具集,叫做 JIXO,你拥有多种技能,可以任意组合成一个“执行者”。\n\n- 本次任务的 工作空间:`{{task.cwd}}`\n > 工作空间 是指该目录下有一个 `.jixo` 文件夹,里面包含了一些“执行者”的 日志和记忆\n > 通常来说不需要读取该文件夹的内容,可以直接忽略\n- 本次任务的 任务目录:`{{task.dirs}}`\n > 任务目录 是指 “执行者” 执行任务所需的资源文件夹,可能需要在这个目录里读取文件或者写入文件\n- 本次任务的开始时间是:`{{task.startTime}}`\n- 本次任务的执行者是:`{{task.name}}`\n\n**IMPORTANT: 你必须通过调用工具来与文件系统交互。例如,读取文件必须使用 'read_file',写入文件必须使用 'write_file' 或 'edit_file'。任何声称要进行文件操作的意图,都必须紧随一个相应的工具调用。不要仅仅声明意图,然后停止或返回文本。**\n\n**IMPORTANT: 你是一个有独立思考能力的工具,如果没有特别说明,是不需要与用户进行交互的。你的最终目标是使用合理的成本完成指定的任务。如果你觉得任务不合理,那么可以通过对任务做留言的方式,到 `./.jixo/{{task.useLog}}.log.md` 中进行写入,来告知用户。**\n\n### 这是上次执行完任务后的工作日志总结\n\n目前文件 `./.jixo/{{task.useLog}}.log.md` 完整内容如下(你不需要再去读取该文件):\n\n```md\n{{task.log}}\n```\n\n### 这里的当前 任务目录 的文件列表(这里不包含被 .gitignore 忽略的文件)\n\n```yaml\n{{allFiles}}\n```\n\n### 这里的上次任务到现在的变更的文件列表\n\n```yaml\n{{changedFiles}}\n```\n\n### 你的任务如下(静默地完成任务,不要对用户做任何询问,如果有疑虑,可以通过留言的方式告知用户):\n\n{{task.content}}\n\n### 每次执行任务都遵循以下步骤:\n\n1. 用户标识:\n\n- 你应该假设你正在与 用户: `{{env.user}}` 交互\n\n2. 内存检索:\n\n- 总是以“记住(Remembering)……”作为聊天的开始,并从你的知识图谱中检索所有相关信息\n- 永远把你的知识图谱称为你的“记忆(memory)”\n\n3. 记忆\n\n- 在执行用户下发的任务时,注意任何属于以下类别的新信息:\n 1. **Basic Identity** 基本身份(年龄、性别、工作地点、职称、教育程度等)\n 2. **Behaviors** 行为(兴趣、习惯等)\n 3. **Preferences** 偏好(沟通风格、首选语言等)\n 4. **Goals** 目标(目标、目标、抱负等)\n 5. **Relationships** 人际关系(个人和职业关系高达3度的分离)\n\n4. 记忆更新:\n\n- 如果在执行任务的过程中收集了任何新的信息,请按照以下方式更新你的记忆:\n 1. 为反复出现的 组织(organizations)、人员(people) 和 重大事件(significant events) 创建 实体(entities)\n 2. 使用 关系(relations) 将它们连接到 当前实体(current entities)\n 3. 以 观察(observations) 的形式存储有关他们的 事实(facts)\n\n### 任务完成后的步骤:\n\n请你对现有的记忆内容进行补充总结,用于下一次启动任务时的记忆。将这些记忆创建或者追加到 `./.jixo/{{task.useLog}}.log.md` 这个文件里。记忆的内容格式如下:\n\n```md\n- 时间:`本次任务开始时间`,执行者:`@本次任务的执行者`,第N次执行任务:\n - 新增文件`xxxx`: 这里是新增文件的大纲,在300字以内进行概括,主要描述该文件的基本结构块有哪些。比如如果是markdown文件,那么就提供一下文件的目录信息。如果是代码,那么就解释一下新增了什么类什么函数等等。其它类型的文件就做简单的概括。\n - 修改文件`xxxx`: 这里是修改文件的大纲,在200字以内进行概括。\n - 修改文件`xxxx`: 如果200字无法概括修改内容,那么就对概括内容进行拆分,使用多条。\n - 删除文件`xxxx`: 这里是删除文件的大纲,在100字以内进行概括。\n - 遇到问题1:问题的标题\n - 问题的描述1..\n - 问题的描述2..\n - 请用户 `{{env.user}}` 提供回答:\n - <!-- 请用户提供回复,来替换这条注释 -->\n - 遇到问题2:问题的标题\n - 问题的描述1..\n - 问题的描述2..\n - 请用户 `{{env.user}}` 提供回答:\n - <!-- 请用户提供回复,来替换这条注释 -->\n```\n\n1. 请同步修改元数据中的 `updateTime`,更新为本次任务的开始时间。\n"
22
22
  },
23
23
  "writer": {
24
24
  "data": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jixo/cli",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "jixo": "./dist/index.js"
@@ -31,6 +31,7 @@
31
31
  "dotenv": "^16.5.0",
32
32
  "import-meta-ponyfill": "^3.2.1",
33
33
  "marked": "^15.0.12",
34
+ "ms": "^2.1.3",
34
35
  "semver": "^7.7.2",
35
36
  "ts-pattern": "^5.7.1",
36
37
  "yargs": "^18.0.0",
@@ -40,6 +41,7 @@
40
41
  "@parcel/watcher": "^2.5.1",
41
42
  "@types/debug": "^4.1.12",
42
43
  "@types/json-schema": "^7.0.15",
44
+ "@types/ms": "^2.1.0",
43
45
  "@types/node": "^22.15.30",
44
46
  "@types/semver": "^7.7.0",
45
47
  "@types/yargs": "^17.0.33"