zhitalk 0.0.11 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent.js +31 -5
- package/dist/agent/colors.d.ts +6 -0
- package/dist/agent/colors.js +18 -0
- package/dist/agent/prompt.js +10 -0
- package/dist/agent/todo.d.ts +17 -0
- package/dist/agent/todo.js +86 -0
- package/dist/agent/tools.js +31 -0
- package/dist/install.js +105 -31
- package/package.json +1 -1
package/dist/agent/agent.js
CHANGED
|
@@ -6,7 +6,8 @@ import { DB_PATH } from './db.js';
|
|
|
6
6
|
import { tools, maybePersistedOutput, initTools } from './tools.js';
|
|
7
7
|
import { compressMessages } from './context.js';
|
|
8
8
|
import { systemPrompt } from './prompt.js';
|
|
9
|
-
import { formatToolLog } from './colors.js';
|
|
9
|
+
import { formatToolLog, formatTodoList } from './colors.js';
|
|
10
|
+
import { processTodoCalls, formatTodoListForPrompt } from './todo.js';
|
|
10
11
|
import { checkReadPermission } from './permission/read.js';
|
|
11
12
|
import { checkWritePermission } from './permission/write.js';
|
|
12
13
|
import { checkExecPermission } from './permission/exec.js';
|
|
@@ -33,6 +34,10 @@ const StateAnnotation = Annotation.Root({
|
|
|
33
34
|
reducer: (_prev, next) => next,
|
|
34
35
|
default: () => 0,
|
|
35
36
|
}),
|
|
37
|
+
todoList: Annotation({
|
|
38
|
+
reducer: (_prev, next) => next,
|
|
39
|
+
default: () => null,
|
|
40
|
+
}),
|
|
36
41
|
});
|
|
37
42
|
// ── Graph Nodes ───────────────────────────────────────────
|
|
38
43
|
function shouldContinue(state) {
|
|
@@ -121,7 +126,11 @@ function createAgentGraph(toolList) {
|
|
|
121
126
|
}
|
|
122
127
|
return true;
|
|
123
128
|
});
|
|
124
|
-
const messages = [new SystemMessage(systemPrompt)
|
|
129
|
+
const messages = [new SystemMessage(systemPrompt)];
|
|
130
|
+
if (state.todoList && state.todoList.length > 0) {
|
|
131
|
+
messages.push(new SystemMessage(`当前任务进度:\n${formatTodoListForPrompt(state.todoList)}`));
|
|
132
|
+
}
|
|
133
|
+
messages.push(...modelMessages);
|
|
125
134
|
const response = await modelWithTheseTools.invoke(messages, config);
|
|
126
135
|
return { messages: [response] };
|
|
127
136
|
}
|
|
@@ -240,9 +249,25 @@ function createAgentGraph(toolList) {
|
|
|
240
249
|
}
|
|
241
250
|
}));
|
|
242
251
|
}
|
|
243
|
-
|
|
252
|
+
// 分离 todo 工具调用
|
|
253
|
+
const regularAllowCalls = [];
|
|
254
|
+
const todoAllowCalls = [];
|
|
255
|
+
for (const call of allowCalls) {
|
|
256
|
+
if (call.name === 'create_todo_list' || call.name === 'update_todo_status') {
|
|
257
|
+
todoAllowCalls.push(call);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
regularAllowCalls.push(call);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const regularOutputs = await executeCalls(regularAllowCalls);
|
|
264
|
+
const todoResult = processTodoCalls(todoAllowCalls, state.todoList);
|
|
265
|
+
if (todoResult.todoList && todoResult.todoList.length > 0) {
|
|
266
|
+
console.log(formatTodoList(todoResult.todoList));
|
|
267
|
+
}
|
|
268
|
+
const allowOutputs = [...regularOutputs, ...todoResult.messages];
|
|
244
269
|
if (confirmCalls.length === 0) {
|
|
245
|
-
return { messages: [...allowOutputs, ...blockMessages] };
|
|
270
|
+
return { messages: [...allowOutputs, ...blockMessages], todoList: todoResult.todoList };
|
|
246
271
|
}
|
|
247
272
|
const result = interrupt({ toolCalls: confirmCalls });
|
|
248
273
|
if (result !== 'approved') {
|
|
@@ -253,10 +278,11 @@ function createAgentGraph(toolList) {
|
|
|
253
278
|
}));
|
|
254
279
|
return {
|
|
255
280
|
messages: [...allowOutputs, ...blockMessages, ...deniedMessages],
|
|
281
|
+
todoList: todoResult.todoList,
|
|
256
282
|
};
|
|
257
283
|
}
|
|
258
284
|
const confirmOutputs = await executeCalls(confirmCalls);
|
|
259
|
-
return { messages: [...allowOutputs, ...blockMessages, ...confirmOutputs] };
|
|
285
|
+
return { messages: [...allowOutputs, ...blockMessages, ...confirmOutputs], todoList: todoResult.todoList };
|
|
260
286
|
}
|
|
261
287
|
const workflow = new StateGraph(StateAnnotation)
|
|
262
288
|
.addNode('model_request', modelRequest)
|
package/dist/agent/colors.d.ts
CHANGED
|
@@ -15,5 +15,11 @@ export declare const color: {
|
|
|
15
15
|
warn: (text: string) => string;
|
|
16
16
|
info: (text: string) => string;
|
|
17
17
|
good: (text: string) => string;
|
|
18
|
+
todoTag: () => string;
|
|
18
19
|
};
|
|
20
|
+
export interface TodoDisplayItem {
|
|
21
|
+
content: string;
|
|
22
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
23
|
+
}
|
|
24
|
+
export declare function formatTodoList(items: TodoDisplayItem[]): string;
|
|
19
25
|
export declare function formatToolLog(name: string, detail?: string): string;
|
package/dist/agent/colors.js
CHANGED
|
@@ -33,7 +33,25 @@ export const color = {
|
|
|
33
33
|
warn: (text) => ck().yellow(text),
|
|
34
34
|
info: (text) => ck().blueBright(text),
|
|
35
35
|
good: (text) => ck().greenBright(text),
|
|
36
|
+
todoTag: () => ck().magentaBright('[Todo]'),
|
|
36
37
|
};
|
|
38
|
+
export function formatTodoList(items) {
|
|
39
|
+
const lines = [color.todoTag()];
|
|
40
|
+
for (const item of items) {
|
|
41
|
+
const symbol = item.status === 'completed'
|
|
42
|
+
? color.good('✓')
|
|
43
|
+
: item.status === 'in_progress'
|
|
44
|
+
? color.info('→')
|
|
45
|
+
: item.status === 'failed'
|
|
46
|
+
? color.error('✗')
|
|
47
|
+
: color.gray('○');
|
|
48
|
+
const desc = item.status === 'completed' || item.status === 'failed'
|
|
49
|
+
? color.gray(item.content)
|
|
50
|
+
: item.content;
|
|
51
|
+
lines.push(` ${symbol} ${desc}`);
|
|
52
|
+
}
|
|
53
|
+
return '\n' + lines.join('\n') + '\n';
|
|
54
|
+
}
|
|
37
55
|
export function formatToolLog(name, detail) {
|
|
38
56
|
const parts = [color.toolTag(), color.toolName(name), color.toolAction()];
|
|
39
57
|
if (detail) {
|
package/dist/agent/prompt.js
CHANGED
|
@@ -47,12 +47,22 @@ ${skillsText}`
|
|
|
47
47
|
const skillPrompt = `## Skills
|
|
48
48
|
|
|
49
49
|
${skillList}\n\nNote: If you want to add a new skill, it must be placed in the ${path.join(WORKSPACE_DIR, 'skills')} directory.`;
|
|
50
|
+
const todoPrompt = `## Task Planning
|
|
51
|
+
|
|
52
|
+
When a user's request is a complex, multi-step task (such as data analysis, writing a document, planning a task, or any task clearly requiring more than 3 steps), you MUST:
|
|
53
|
+
1. First call \`create_todo_list\` to create a structured plan with clear, actionable steps
|
|
54
|
+
2. Then execute each step one by one
|
|
55
|
+
3. After completing each step, call \`update_todo_status\` to mark it as completed (or failed if it didn't work)
|
|
56
|
+
4. Only provide the final answer after all steps are done
|
|
57
|
+
|
|
58
|
+
For simple, single-step tasks, do NOT use the todo list tools.`;
|
|
50
59
|
export const systemPrompt = [
|
|
51
60
|
basePrompt,
|
|
52
61
|
profilePrompt,
|
|
53
62
|
memoryPrompt,
|
|
54
63
|
skillPrompt,
|
|
55
64
|
dateTimePrompt,
|
|
65
|
+
todoPrompt,
|
|
56
66
|
]
|
|
57
67
|
.filter(Boolean)
|
|
58
68
|
.join('\n\n');
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ToolMessage } from '@langchain/core/messages';
|
|
2
|
+
export interface TodoItem {
|
|
3
|
+
id: number;
|
|
4
|
+
content: string;
|
|
5
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
6
|
+
}
|
|
7
|
+
interface TodoCall {
|
|
8
|
+
id?: string;
|
|
9
|
+
name: string;
|
|
10
|
+
args: Record<string, any>;
|
|
11
|
+
}
|
|
12
|
+
export declare function processTodoCalls(calls: TodoCall[], currentTodoList: TodoItem[] | null): {
|
|
13
|
+
messages: ToolMessage[];
|
|
14
|
+
todoList: TodoItem[] | null;
|
|
15
|
+
};
|
|
16
|
+
export declare function formatTodoListForPrompt(items: TodoItem[]): string;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ToolMessage } from '@langchain/core/messages';
|
|
2
|
+
export function processTodoCalls(calls, currentTodoList) {
|
|
3
|
+
const messages = [];
|
|
4
|
+
let todoList = currentTodoList;
|
|
5
|
+
for (const call of calls) {
|
|
6
|
+
if (call.name === 'create_todo_list') {
|
|
7
|
+
const items = call.args.items;
|
|
8
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
9
|
+
messages.push(new ToolMessage({
|
|
10
|
+
content: 'Error: items must be a non-empty array.',
|
|
11
|
+
tool_call_id: call.id ?? '',
|
|
12
|
+
name: call.name,
|
|
13
|
+
}));
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
todoList = items.map((content, i) => ({
|
|
17
|
+
id: i,
|
|
18
|
+
content: typeof content === 'string' ? content.trim() : String(content),
|
|
19
|
+
status: 'pending',
|
|
20
|
+
}));
|
|
21
|
+
messages.push(new ToolMessage({
|
|
22
|
+
content: 'Todo list created successfully.',
|
|
23
|
+
tool_call_id: call.id ?? '',
|
|
24
|
+
name: call.name,
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
else if (call.name === 'update_todo_status') {
|
|
28
|
+
const index = call.args.index;
|
|
29
|
+
const status = call.args.status;
|
|
30
|
+
if (!todoList) {
|
|
31
|
+
messages.push(new ToolMessage({
|
|
32
|
+
content: 'Error: no todo list exists.',
|
|
33
|
+
tool_call_id: call.id ?? '',
|
|
34
|
+
name: call.name,
|
|
35
|
+
}));
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (typeof index !== 'number' ||
|
|
39
|
+
!Number.isInteger(index) ||
|
|
40
|
+
index < 0 ||
|
|
41
|
+
index >= todoList.length) {
|
|
42
|
+
messages.push(new ToolMessage({
|
|
43
|
+
content: `Error: index ${index} is out of range.`,
|
|
44
|
+
tool_call_id: call.id ?? '',
|
|
45
|
+
name: call.name,
|
|
46
|
+
}));
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const validStatuses = [
|
|
50
|
+
'pending',
|
|
51
|
+
'in_progress',
|
|
52
|
+
'completed',
|
|
53
|
+
'failed',
|
|
54
|
+
];
|
|
55
|
+
if (!validStatuses.includes(status)) {
|
|
56
|
+
messages.push(new ToolMessage({
|
|
57
|
+
content: `Error: invalid status "${status}".`,
|
|
58
|
+
tool_call_id: call.id ?? '',
|
|
59
|
+
name: call.name,
|
|
60
|
+
}));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
todoList[index].status = status;
|
|
64
|
+
messages.push(new ToolMessage({
|
|
65
|
+
content: `Todo item ${index} updated to ${status}.`,
|
|
66
|
+
tool_call_id: call.id ?? '',
|
|
67
|
+
name: call.name,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return { messages, todoList };
|
|
72
|
+
}
|
|
73
|
+
export function formatTodoListForPrompt(items) {
|
|
74
|
+
return items
|
|
75
|
+
.map((item) => {
|
|
76
|
+
const statusMark = item.status === 'completed'
|
|
77
|
+
? '[x]'
|
|
78
|
+
: item.status === 'in_progress'
|
|
79
|
+
? '[~]'
|
|
80
|
+
: item.status === 'failed'
|
|
81
|
+
? '[!]'
|
|
82
|
+
: '[ ]';
|
|
83
|
+
return `${statusMark} ${item.content}`;
|
|
84
|
+
})
|
|
85
|
+
.join('\n');
|
|
86
|
+
}
|
package/dist/agent/tools.js
CHANGED
|
@@ -145,6 +145,35 @@ const agentTool = createZhitalkTool(agentToolImpl, {
|
|
|
145
145
|
.describe('A clear, self-contained task prompt for the sub-agent. It should include all necessary context because the sub-agent cannot see the current conversation history.'),
|
|
146
146
|
}),
|
|
147
147
|
}, 'exec');
|
|
148
|
+
async function createTodoListDummy() {
|
|
149
|
+
return 'Error: create_todo_list should be handled internally by the agent.';
|
|
150
|
+
}
|
|
151
|
+
async function updateTodoStatusDummy() {
|
|
152
|
+
return 'Error: update_todo_status should be handled internally by the agent.';
|
|
153
|
+
}
|
|
154
|
+
const createTodoListTool = createZhitalkTool(createTodoListDummy, {
|
|
155
|
+
name: 'create_todo_list',
|
|
156
|
+
description: 'Create a structured todo list for a complex, multi-step task. Must be called BEFORE starting execution. Each item should be a clear, actionable step.',
|
|
157
|
+
schema: z.object({
|
|
158
|
+
items: z
|
|
159
|
+
.array(z.string().describe('A single todo item description.'))
|
|
160
|
+
.describe('The list of todo items to create. Each item should be a clear, actionable step.'),
|
|
161
|
+
}),
|
|
162
|
+
}, 'read');
|
|
163
|
+
const updateTodoStatusTool = createZhitalkTool(updateTodoStatusDummy, {
|
|
164
|
+
name: 'update_todo_status',
|
|
165
|
+
description: 'Update the status of a todo item in the current todo list. Call this after completing EACH step.',
|
|
166
|
+
schema: z.object({
|
|
167
|
+
index: z
|
|
168
|
+
.number()
|
|
169
|
+
.int()
|
|
170
|
+
.min(0)
|
|
171
|
+
.describe('The zero-based index of the todo item to update.'),
|
|
172
|
+
status: z
|
|
173
|
+
.enum(['in_progress', 'completed', 'failed'])
|
|
174
|
+
.describe('The new status of the todo item.'),
|
|
175
|
+
}),
|
|
176
|
+
}, 'read');
|
|
148
177
|
export async function maybePersistedOutput(content, toolCallId) {
|
|
149
178
|
const MAX_LENGTH = 50000;
|
|
150
179
|
if (content.length <= MAX_LENGTH) {
|
|
@@ -180,6 +209,8 @@ export const nativeTools = [
|
|
|
180
209
|
memoryDeleteTool,
|
|
181
210
|
profileUpdateTool,
|
|
182
211
|
agentTool,
|
|
212
|
+
createTodoListTool,
|
|
213
|
+
updateTodoStatusTool,
|
|
183
214
|
];
|
|
184
215
|
export let tools = [...nativeTools];
|
|
185
216
|
export async function initTools() {
|
package/dist/install.js
CHANGED
|
@@ -5,34 +5,112 @@ import { execSync } from 'child_process';
|
|
|
5
5
|
import { WORKSPACE_DIR, CONFIG_PATH } from './agent/config.js';
|
|
6
6
|
import { initDb } from './agent/db.js';
|
|
7
7
|
const SKILLS_DIR = path.join(WORKSPACE_DIR, 'skills');
|
|
8
|
+
// 核心 skills
|
|
9
|
+
const CORE_SKILLS = [
|
|
10
|
+
{
|
|
11
|
+
name: 'find-skills',
|
|
12
|
+
repo: 'vercel-labs/skills',
|
|
13
|
+
path: 'skills/find-skills',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'skill-creator',
|
|
17
|
+
repo: 'anthropics/skills',
|
|
18
|
+
path: 'skills/skill-creator',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
// 可选的常用 skills,默认一起安装
|
|
22
|
+
const OPTIONAL_SKILLS = [
|
|
23
|
+
{
|
|
24
|
+
name: 'canvas-design',
|
|
25
|
+
repo: 'anthropics/skills',
|
|
26
|
+
path: 'skills/canvas-design',
|
|
27
|
+
},
|
|
28
|
+
{ name: 'docx', repo: 'anthropics/skills', path: 'skills/docx' },
|
|
29
|
+
{ name: 'pdf', repo: 'anthropics/skills', path: 'skills/pdf' },
|
|
30
|
+
{ name: 'pptx', repo: 'anthropics/skills', path: 'skills/pptx' },
|
|
31
|
+
{ name: 'xlsx', repo: 'anthropics/skills', path: 'skills/xlsx' },
|
|
32
|
+
{
|
|
33
|
+
name: 'frontend-design',
|
|
34
|
+
repo: 'anthropics/skills',
|
|
35
|
+
path: 'skills/frontend-design',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'webapp-testing',
|
|
39
|
+
repo: 'anthropics/skills',
|
|
40
|
+
path: 'skills/webapp-testing',
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
const ALL_SKILLS = [...CORE_SKILLS, ...OPTIONAL_SKILLS];
|
|
8
44
|
function run(command, options) {
|
|
9
45
|
execSync(command, { stdio: 'inherit', ...options });
|
|
10
46
|
}
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
47
|
+
function installSkills(skills, targetBaseDir) {
|
|
48
|
+
const installed = [];
|
|
49
|
+
const skipped = [];
|
|
50
|
+
const failed = [];
|
|
51
|
+
// 按 repo 分组,避免重复下载
|
|
52
|
+
const byRepo = new Map();
|
|
53
|
+
for (const skill of skills) {
|
|
54
|
+
const list = byRepo.get(skill.repo) ?? [];
|
|
55
|
+
list.push(skill);
|
|
56
|
+
byRepo.set(skill.repo, list);
|
|
15
57
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
58
|
+
for (const [repo, repoSkills] of byRepo) {
|
|
59
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zhitalk-'));
|
|
60
|
+
const markFailed = () => {
|
|
61
|
+
const repoFailed = repoSkills.filter((s) => !fs.existsSync(path.join(targetBaseDir, s.name)));
|
|
62
|
+
if (repoFailed.length === 0)
|
|
63
|
+
return;
|
|
64
|
+
for (const skill of repoFailed) {
|
|
65
|
+
console.log(` ❌ ${skill.name} 安装失败,已跳过`);
|
|
66
|
+
failed.push(skill.name);
|
|
67
|
+
}
|
|
68
|
+
console.log(` ⚠️ ${repo} 下载失败,你可以手动安装:`);
|
|
69
|
+
console.log(` 1. 下载 https://github.com/${repo}/archive/refs/heads/main.tar.gz`);
|
|
70
|
+
console.log(` 2. 解压后找到以下目录并拷贝:`);
|
|
71
|
+
for (const skill of repoFailed) {
|
|
72
|
+
console.log(` ${skill.path} → ${path.join(targetBaseDir, skill.name)}`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
console.log(` 📥 正在下载 ${repo}...`);
|
|
76
|
+
try {
|
|
77
|
+
const tarPath = path.join(tempDir, 'repo.tar.gz');
|
|
78
|
+
run(`curl --connect-timeout 10 --max-time 30 -fsSL -o "${tarPath}" "https://github.com/${repo}/archive/refs/heads/main.tar.gz"`, { timeout: 45000 });
|
|
79
|
+
run(`tar -xzf "${tarPath}" -C "${tempDir}"`, { timeout: 30000 });
|
|
80
|
+
const subDir = fs.readdirSync(tempDir).find((d) => d !== 'repo.tar.gz');
|
|
81
|
+
if (!subDir) {
|
|
82
|
+
markFailed();
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const extractDir = path.join(tempDir, subDir);
|
|
86
|
+
for (const skill of repoSkills) {
|
|
87
|
+
const targetDir = path.join(targetBaseDir, skill.name);
|
|
88
|
+
if (fs.existsSync(targetDir)) {
|
|
89
|
+
console.log(` ✅ ${skill.name} 已存在,跳过`);
|
|
90
|
+
skipped.push(skill.name);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
console.log(` 📥 正在安装 ${skill.name}...`);
|
|
94
|
+
fs.cpSync(path.join(extractDir, skill.path), targetDir, {
|
|
95
|
+
recursive: true,
|
|
96
|
+
});
|
|
97
|
+
console.log(` ✅ ${skill.name} 安装完成`);
|
|
98
|
+
installed.push(skill.name);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
markFailed();
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
try {
|
|
106
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// 忽略清理失败
|
|
110
|
+
}
|
|
33
111
|
}
|
|
34
|
-
throw error;
|
|
35
112
|
}
|
|
113
|
+
return { installed, skipped, failed };
|
|
36
114
|
}
|
|
37
115
|
export async function runInstall() {
|
|
38
116
|
console.log('🚀 欢迎使用 Zhitalk!首次使用需要进行初始化配置。\n');
|
|
@@ -41,17 +119,13 @@ export async function runInstall() {
|
|
|
41
119
|
initDb();
|
|
42
120
|
console.log('✅ 数据库初始化完成\n');
|
|
43
121
|
// 2. 安装 skills
|
|
44
|
-
console.log('🔧
|
|
122
|
+
console.log('🔧 正在安装内置 skills...');
|
|
45
123
|
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
installSkill('skill-creator', 'anthropics/skills', 'skills/skill-creator', path.join(SKILLS_DIR, 'skill-creator'), tempDir);
|
|
50
|
-
}
|
|
51
|
-
finally {
|
|
52
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
124
|
+
const { installed, skipped, failed } = installSkills(ALL_SKILLS, SKILLS_DIR);
|
|
125
|
+
if (failed.length > 0) {
|
|
126
|
+
console.log(`\n⚠️ 以下 ${failed.length} 个 skill 安装失败:${failed.join(', ')}`);
|
|
53
127
|
}
|
|
54
|
-
console.log(
|
|
128
|
+
console.log(`\n✅ Skills 安装完成(${installed.length} 个新安装,${skipped.length} 个已存在跳过)\n`);
|
|
55
129
|
// 3. 创建配置文件
|
|
56
130
|
console.log('⚙️ 正在创建配置文件...');
|
|
57
131
|
const configTemplate = {
|
package/package.json
CHANGED