foliko 1.1.88 → 1.1.90

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.
@@ -16,7 +16,7 @@ const { buildSessionContext, EntryTypes } = require('../src/core/session-entry')
16
16
  * Get default session directory for a cwd
17
17
  */
18
18
  function getDefaultSessionDir(cwd) {
19
- const agentDir = path.join(process.cwd(), '.foliko');
19
+ const agentDir = path.join(cwd, '.foliko');
20
20
  const sessionDir = path.join(agentDir, 'sessions');
21
21
  return sessionDir;
22
22
  }
@@ -54,10 +54,18 @@ class SessionPlugin extends Plugin {
54
54
  return this;
55
55
  }
56
56
 
57
+ /**
58
+ * 获取当前工作目录(framework.getCwd() 优先, fallback 到 process.cwd())
59
+ */
60
+ _defaultCwd() {
61
+ return this._framework?.getCwd?.() ?? process.cwd();
62
+ }
63
+
57
64
  /**
58
65
  * Get or create a SessionManager for a session
59
66
  */
60
- _getSessionManager(sessionId, cwd = process.cwd()) {
67
+ _getSessionManager(sessionId, cwd) {
68
+ cwd = cwd ?? this._defaultCwd();
61
69
  if (this._sessionManagers.has(sessionId)) {
62
70
  return this._sessionManagers.get(sessionId);
63
71
  }
@@ -72,7 +80,7 @@ class SessionPlugin extends Plugin {
72
80
  /**
73
81
  * List all sessions for current cwd
74
82
  */
75
- async listSessions(cwd = process.cwd()) {
83
+ async listSessions(cwd = this._defaultCwd()) {
76
84
  const sessionDir = getDefaultSessionDir(cwd);
77
85
  const sessions = [];
78
86
 
@@ -115,7 +123,7 @@ class SessionPlugin extends Plugin {
115
123
  cwd: z.string().optional().describe('工作目录')
116
124
  }),
117
125
  execute: async (args, fw) => {
118
- const cwd = args.cwd || process.cwd();
126
+ const cwd = args.cwd || this._defaultCwd();
119
127
  const sessionDir = getDefaultSessionDir(cwd);
120
128
  const manager = new SessionManager(cwd, sessionDir, undefined, true);
121
129
  const sessionId = manager.getSessionId();
@@ -140,7 +148,7 @@ class SessionPlugin extends Plugin {
140
148
  cwd: z.string().optional().describe('工作目录')
141
149
  }),
142
150
  execute: async (args) => {
143
- const cwd = args.cwd || process.cwd();
151
+ const cwd = args.cwd || this._defaultCwd();
144
152
  const manager = this._getSessionManager(args.sessionId, cwd);
145
153
  const entries = manager.getEntries();
146
154
 
@@ -163,7 +171,7 @@ class SessionPlugin extends Plugin {
163
171
  cwd: z.string().optional().describe('工作目录')
164
172
  }),
165
173
  execute: async (args) => {
166
- const cwd = args.cwd || process.cwd();
174
+ const cwd = args.cwd || this._defaultCwd();
167
175
  const sessions = await this.listSessions(cwd);
168
176
  return {
169
177
  success: true,
@@ -181,7 +189,7 @@ class SessionPlugin extends Plugin {
181
189
  cwd: z.string().optional().describe('工作目录')
182
190
  }),
183
191
  execute: async (args) => {
184
- const cwd = args.cwd || process.cwd();
192
+ const cwd = args.cwd || this._defaultCwd();
185
193
  const manager = this._getSessionManager(args.sessionId, cwd);
186
194
 
187
195
  if (manager.getSessionFile() && require('fs').existsSync(manager.getSessionFile())) {
@@ -203,7 +211,7 @@ class SessionPlugin extends Plugin {
203
211
  limit: z.number().optional().describe('返回消息数量限制')
204
212
  }),
205
213
  execute: async (args) => {
206
- const cwd = args.cwd || process.cwd();
214
+ const cwd = args.cwd || this._defaultCwd();
207
215
  const manager = this._getSessionManager(args.sessionId, cwd);
208
216
  const context = manager.buildSessionContext();
209
217
  let messages = context.messages;
@@ -233,7 +241,7 @@ class SessionPlugin extends Plugin {
233
241
  cwd: z.string().optional().describe('工作目录')
234
242
  }),
235
243
  execute: async (args) => {
236
- const cwd = args.cwd || process.cwd();
244
+ const cwd = args.cwd || this._defaultCwd();
237
245
  const manager = this._getSessionManager(args.sessionId, cwd);
238
246
 
239
247
  try {
@@ -262,7 +270,7 @@ class SessionPlugin extends Plugin {
262
270
  cwd: z.string().optional().describe('工作目录')
263
271
  }),
264
272
  execute: async (args) => {
265
- const cwd = args.cwd || process.cwd();
273
+ const cwd = args.cwd || this._defaultCwd();
266
274
  const manager = this._getSessionManager(args.sessionId, cwd);
267
275
 
268
276
  try {
@@ -307,7 +315,7 @@ class SessionPlugin extends Plugin {
307
315
  /**
308
316
  * Add message to session
309
317
  */
310
- addMessage(sessionId, message, cwd = process.cwd()) {
318
+ addMessage(sessionId, message, cwd = this._defaultCwd()) {
311
319
  const manager = this._getSessionManager(sessionId, cwd);
312
320
  const entryId = manager.appendMessage(message);
313
321
 
@@ -322,7 +330,7 @@ class SessionPlugin extends Plugin {
322
330
  /**
323
331
  * Get session context for LLM
324
332
  */
325
- getSessionContext(sessionId, cwd = process.cwd()) {
333
+ getSessionContext(sessionId, cwd = this._defaultCwd()) {
326
334
  const manager = this._getSessionManager(sessionId, cwd);
327
335
  return manager.buildSessionContext();
328
336
  }
@@ -330,14 +338,14 @@ class SessionPlugin extends Plugin {
330
338
  /**
331
339
  * Get or create session (alias for getSessionContext)
332
340
  */
333
- getOrCreateSession(sessionId, options = {}, cwd = process.cwd()) {
341
+ getOrCreateSession(sessionId, options = {}, cwd = this._defaultCwd()) {
334
342
  return this.getSessionContext(sessionId, cwd);
335
343
  }
336
344
 
337
345
  /**
338
346
  * Get specific entry
339
347
  */
340
- getEntry(sessionId, entryId, cwd = process.cwd()) {
348
+ getEntry(sessionId, entryId, cwd = this._defaultCwd()) {
341
349
  const manager = this._getSessionManager(sessionId, cwd);
342
350
  return manager.getEntry(entryId);
343
351
  }
@@ -345,7 +353,7 @@ class SessionPlugin extends Plugin {
345
353
  /**
346
354
  * Get branch (path from root to leaf)
347
355
  */
348
- getBranch(sessionId, fromId, cwd = process.cwd()) {
356
+ getBranch(sessionId, fromId, cwd = this._defaultCwd()) {
349
357
  const manager = this._getSessionManager(sessionId, cwd);
350
358
  return manager.getBranch(fromId);
351
359
  }
@@ -353,7 +361,7 @@ class SessionPlugin extends Plugin {
353
361
  /**
354
362
  * Append compaction entry
355
363
  */
356
- appendCompaction(sessionId, summary, firstKeptEntryId, tokensBefore, details, cwd = process.cwd()) {
364
+ appendCompaction(sessionId, summary, firstKeptEntryId, tokensBefore, details, cwd = this._defaultCwd()) {
357
365
  const manager = this._getSessionManager(sessionId, cwd);
358
366
  return manager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, false);
359
367
  }
@@ -361,7 +369,7 @@ class SessionPlugin extends Plugin {
361
369
  /**
362
370
  * Append thinking level change
363
371
  */
364
- appendThinkingLevelChange(sessionId, thinkingLevel, cwd = process.cwd()) {
372
+ appendThinkingLevelChange(sessionId, thinkingLevel, cwd = this._defaultCwd()) {
365
373
  const manager = this._getSessionManager(sessionId, cwd);
366
374
  return manager.appendThinkingLevelChange(thinkingLevel);
367
375
  }
@@ -369,7 +377,7 @@ class SessionPlugin extends Plugin {
369
377
  /**
370
378
  * Append model change
371
379
  */
372
- appendModelChange(sessionId, provider, modelId, cwd = process.cwd()) {
380
+ appendModelChange(sessionId, provider, modelId, cwd = this._defaultCwd()) {
373
381
  const manager = this._getSessionManager(sessionId, cwd);
374
382
  return manager.appendModelChange(provider, modelId);
375
383
  }
@@ -377,7 +385,7 @@ class SessionPlugin extends Plugin {
377
385
  /**
378
386
  * Set session label
379
387
  */
380
- setLabel(sessionId, entryId, label, cwd = process.cwd()) {
388
+ setLabel(sessionId, entryId, label, cwd = this._defaultCwd()) {
381
389
  const manager = this._getSessionManager(sessionId, cwd);
382
390
  return manager.appendLabelChange(entryId, label);
383
391
  }
@@ -385,7 +393,7 @@ class SessionPlugin extends Plugin {
385
393
  /**
386
394
  * Get session info (compatible with external callers)
387
395
  */
388
- getSession(sessionId, cwd = process.cwd()) {
396
+ getSession(sessionId, cwd = this._defaultCwd()) {
389
397
  const manager = this._getSessionManager(sessionId, cwd);
390
398
  const entries = manager.getEntries();
391
399
  return {
@@ -414,8 +422,9 @@ class SessionPlugin extends Plugin {
414
422
  async _doCleanup() {
415
423
  try {
416
424
  const fs = require('fs');
417
- const sessionDir = getDefaultSessionDir(process.cwd());
418
-
425
+ const cwd = this._defaultCwd();
426
+ const sessionDir = getDefaultSessionDir(cwd);
427
+
419
428
  if (!fs.existsSync(sessionDir)) {
420
429
  return;
421
430
  }
@@ -426,7 +435,7 @@ class SessionPlugin extends Plugin {
426
435
  for (const file of files) {
427
436
  const filePath = path.join(sessionDir, file);
428
437
  try {
429
- const manager = SessionManager.open(filePath, sessionDir, process.cwd());
438
+ const manager = SessionManager.open(filePath, sessionDir, cwd);
430
439
  const entries = manager.getEntries();
431
440
 
432
441
  // Clean up if exceeds maxHistoryLength
@@ -19,7 +19,7 @@ class ShellExecutorPlugin extends Plugin {
19
19
 
20
20
  this.config = {
21
21
  timeout: config.timeout || 60000,
22
- workingDir: config.workingDir || process.cwd()
22
+ workingDir: config.workingDir
23
23
  }
24
24
 
25
25
  this._framework = null
@@ -27,6 +27,9 @@ class ShellExecutorPlugin extends Plugin {
27
27
 
28
28
  install(framework) {
29
29
  this._framework = framework
30
+ if (!this.config.workingDir) {
31
+ this.config.workingDir = framework?.getCwd?.() ?? process.cwd()
32
+ }
30
33
  return this
31
34
  }
32
35
 
@@ -44,7 +44,7 @@ class StoragePlugin extends Plugin {
44
44
  _initStorage() {
45
45
  if (this._storageManager) return;
46
46
 
47
- const baseDir = path.resolve(process.cwd(), this.config.path);
47
+ const baseDir = path.resolve(this._framework?.getCwd?.() ?? process.cwd(), this.config.path);
48
48
  const filePath = path.join(baseDir, `${this.config.namespace}.jsonl`);
49
49
 
50
50
  // 传递 compaction 配置
@@ -587,7 +587,7 @@ class SubAgentManagerPlugin extends Plugin {
587
587
  */
588
588
  _loadAgentsFromDir() {
589
589
  // 默认使用 .foliko/agents 目录
590
- const agentsDir = this.config.agentsDir || path.join(process.cwd(), '.foliko', 'agents')
590
+ const agentsDir = this.config.agentsDir || path.join(this._framework?.getCwd?.() ?? process.cwd(), '.foliko', 'agents')
591
591
  //log.info(' _loadAgentsFromDir called, agentsDir:', agentsDir)
592
592
  if (!fs.existsSync(agentsDir)) {
593
593
  //log.info(' agentsDir not found or does not exist')
@@ -254,7 +254,7 @@ class TelegramPlugin extends Plugin {
254
254
  const agent = this._framework.createSessionAgent(`telegram_${chatId}`, {
255
255
  systemPrompt: this.systemPrompt,
256
256
  sharedPrompt: `工作目录: {{WORK_DIR}}`,
257
- metadata: { WORK_DIR: process.cwd() }
257
+ metadata: { WORK_DIR: this._framework?.getCwd?.() ?? process.cwd() }
258
258
  })
259
259
  this._sessionAgents.set(chatId, agent)
260
260
 
@@ -477,7 +477,7 @@ class TelegramPlugin extends Plugin {
477
477
  async _downloadFile(fileId, ext, subDir) {
478
478
  const path = require('path')
479
479
  const fs = require('fs')
480
- const saveDir = path.join(process.cwd(), '.foliko', 'data', subDir)
480
+ const saveDir = path.join(this._framework?.getCwd?.() ?? process.cwd(), '.foliko', 'data', subDir)
481
481
  if (!fs.existsSync(saveDir)) fs.mkdirSync(saveDir, { recursive: true })
482
482
 
483
483
  const fileName = `${Date.now()}_${Math.random().toString(36).substring(7)}.${ext}`
@@ -63,17 +63,20 @@ class WeixinPlugin extends Plugin {
63
63
  this._initialized = false
64
64
  // 预创建的 sessionScope 监听器(避免每次消息都创建/销毁)
65
65
  this._sessionScopes = new Map()
66
- const saveDir = path.join(process.cwd(), '.foliko', 'data', this.name)
67
- this.downloader=new FileDownloader({
68
- retries: 3,
69
- baseDir:saveDir
70
- })
66
+ this.downloader = null
71
67
  this.agent=null
72
68
  this.sessionId=null
73
69
  }
74
70
 
75
71
  install(framework) {
76
72
  this._framework = framework
73
+ if (!this.downloader) {
74
+ const saveDir = path.join(this._framework?.getCwd?.() ?? process.cwd(), '.foliko', 'data', this.name)
75
+ this.downloader = new FileDownloader({
76
+ retries: 3,
77
+ baseDir: saveDir
78
+ })
79
+ }
77
80
  // 注册微信发送工具
78
81
  this._registerTools()
79
82
  return this
@@ -473,7 +476,7 @@ class WeixinPlugin extends Plugin {
473
476
  name: `weixin_${userId}`,
474
477
  systemPrompt: this.systemPrompt,
475
478
  sharedPrompt: `工作目录: {{WORK_DIR}}`,
476
- metadata: { WORK_DIR: process.cwd() }
479
+ metadata: { WORK_DIR: this._framework?.getCwd?.() ?? process.cwd() }
477
480
  })
478
481
 
479
482
  this._sessionAgents.set(userId, agent)
@@ -1,133 +1,133 @@
1
- ---
2
- name: find-skills
3
- description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
4
- ---
5
-
6
- # Find Skills
7
-
8
- This skill helps you discover and install skills from the open agent skills ecosystem.
9
-
10
- ## When to Use This Skill
11
-
12
- Use this skill when the user:
13
-
14
- - Asks "how do I do X" where X might be a common task with an existing skill
15
- - Says "find a skill for X" or "is there a skill for X"
16
- - Asks "can you do X" where X is a specialized capability
17
- - Expresses interest in extending agent capabilities
18
- - Wants to search for tools, templates, or workflows
19
- - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.)
20
-
21
- ## What is the Skills CLI?
22
-
23
- The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools.
24
-
25
- **Key commands:**
26
-
27
- - `npx skills find [query]` - Search for skills interactively or by keyword
28
- - `npx skills add <package>` - Install a skill from GitHub or other sources
29
- - `npx skills check` - Check for skill updates
30
- - `npx skills update` - Update all installed skills
31
-
32
- **Browse skills at:** https://skills.sh/
33
-
34
- ## How to Help Users Find Skills
35
-
36
- ### Step 1: Understand What They Need
37
-
38
- When a user asks for help with something, identify:
39
-
40
- 1. The domain (e.g., React, testing, design, deployment)
41
- 2. The specific task (e.g., writing tests, creating animations, reviewing PRs)
42
- 3. Whether this is a common enough task that a skill likely exists
43
-
44
- ### Step 2: Search for Skills
45
-
46
- Run the find command with a relevant query:
47
-
48
- ```bash
49
- npx skills find [query]
50
- ```
51
-
52
- For example:
53
-
54
- - User asks "how do I make my React app faster?" → `npx skills find react performance`
55
- - User asks "can you help me with PR reviews?" → `npx skills find pr review`
56
- - User asks "I need to create a changelog" → `npx skills find changelog`
57
-
58
- The command will return results like:
59
-
60
- ```
61
- Install with npx skills add <owner/repo@skill>
62
-
63
- vercel-labs/agent-skills@vercel-react-best-practices
64
- └ https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices
65
- ```
66
-
67
- ### Step 3: Present Options to the User
68
-
69
- When you find relevant skills, present them to the user with:
70
-
71
- 1. The skill name and what it does
72
- 2. The install command they can run
73
- 3. A link to learn more at skills.sh
74
-
75
- Example response:
76
-
77
- ```
78
- I found a skill that might help! The "vercel-react-best-practices" skill provides
79
- React and Next.js performance optimization guidelines from Vercel Engineering.
80
-
81
- To install it:
82
- npx skills add vercel-labs/agent-skills@vercel-react-best-practices
83
-
84
- Learn more: https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices
85
- ```
86
-
87
- ### Step 4: Offer to Install
88
-
89
- If the user wants to proceed, you can install the skill for them:
90
-
91
- ```bash
92
- npx skills add <owner/repo@skill> -g -y
93
- ```
94
-
95
- The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts.
96
-
97
- ## Common Skill Categories
98
-
99
- When searching, consider these common categories:
100
-
101
- | Category | Example Queries |
102
- | --------------- | ---------------------------------------- |
103
- | Web Development | react, nextjs, typescript, css, tailwind |
104
- | Testing | testing, jest, playwright, e2e |
105
- | DevOps | deploy, docker, kubernetes, ci-cd |
106
- | Documentation | docs, readme, changelog, api-docs |
107
- | Code Quality | review, lint, refactor, best-practices |
108
- | Design | ui, ux, design-system, accessibility |
109
- | Productivity | workflow, automation, git |
110
-
111
- ## Tips for Effective Searches
112
-
113
- 1. **Use specific keywords**: "react testing" is better than just "testing"
114
- 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd"
115
- 3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills`
116
-
117
- ## When No Skills Are Found
118
-
119
- If no relevant skills exist:
120
-
121
- 1. Acknowledge that no existing skill was found
122
- 2. Offer to help with the task directly using your general capabilities
123
- 3. Suggest the user could create their own skill with `npx skills init`
124
-
125
- Example:
126
-
127
- ```
128
- I searched for skills related to "xyz" but didn't find any matches.
129
- I can still help you with this task directly! Would you like me to proceed?
130
-
131
- If this is something you do often, you could create your own skill:
132
- npx skills init my-xyz-skill
133
- ```
1
+ ---
2
+ name: find-skills
3
+ description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
4
+ ---
5
+
6
+ # Find Skills
7
+
8
+ This skill helps you discover and install skills from the open agent skills ecosystem.
9
+
10
+ ## When to Use This Skill
11
+
12
+ Use this skill when the user:
13
+
14
+ - Asks "how do I do X" where X might be a common task with an existing skill
15
+ - Says "find a skill for X" or "is there a skill for X"
16
+ - Asks "can you do X" where X is a specialized capability
17
+ - Expresses interest in extending agent capabilities
18
+ - Wants to search for tools, templates, or workflows
19
+ - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.)
20
+
21
+ ## What is the Skills CLI?
22
+
23
+ The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools.
24
+
25
+ **Key commands:**
26
+
27
+ - `npx skills find [query]` - Search for skills interactively or by keyword
28
+ - `npx skills add <package>` - Install a skill from GitHub or other sources
29
+ - `npx skills check` - Check for skill updates
30
+ - `npx skills update` - Update all installed skills
31
+
32
+ **Browse skills at:** https://skills.sh/
33
+
34
+ ## How to Help Users Find Skills
35
+
36
+ ### Step 1: Understand What They Need
37
+
38
+ When a user asks for help with something, identify:
39
+
40
+ 1. The domain (e.g., React, testing, design, deployment)
41
+ 2. The specific task (e.g., writing tests, creating animations, reviewing PRs)
42
+ 3. Whether this is a common enough task that a skill likely exists
43
+
44
+ ### Step 2: Search for Skills
45
+
46
+ Run the find command with a relevant query:
47
+
48
+ ```bash
49
+ npx skills find [query]
50
+ ```
51
+
52
+ For example:
53
+
54
+ - User asks "how do I make my React app faster?" → `npx skills find react performance`
55
+ - User asks "can you help me with PR reviews?" → `npx skills find pr review`
56
+ - User asks "I need to create a changelog" → `npx skills find changelog`
57
+
58
+ The command will return results like:
59
+
60
+ ```
61
+ Install with npx skills add <owner/repo@skill>
62
+
63
+ vercel-labs/agent-skills@vercel-react-best-practices
64
+ └ https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices
65
+ ```
66
+
67
+ ### Step 3: Present Options to the User
68
+
69
+ When you find relevant skills, present them to the user with:
70
+
71
+ 1. The skill name and what it does
72
+ 2. The install command they can run
73
+ 3. A link to learn more at skills.sh
74
+
75
+ Example response:
76
+
77
+ ```
78
+ I found a skill that might help! The "vercel-react-best-practices" skill provides
79
+ React and Next.js performance optimization guidelines from Vercel Engineering.
80
+
81
+ To install it:
82
+ npx skills add vercel-labs/agent-skills@vercel-react-best-practices
83
+
84
+ Learn more: https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices
85
+ ```
86
+
87
+ ### Step 4: Offer to Install
88
+
89
+ If the user wants to proceed, you can install the skill for them:
90
+
91
+ ```bash
92
+ npx skills add <owner/repo@skill> -g -y
93
+ ```
94
+
95
+ The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts.
96
+
97
+ ## Common Skill Categories
98
+
99
+ When searching, consider these common categories:
100
+
101
+ | Category | Example Queries |
102
+ | --------------- | ---------------------------------------- |
103
+ | Web Development | react, nextjs, typescript, css, tailwind |
104
+ | Testing | testing, jest, playwright, e2e |
105
+ | DevOps | deploy, docker, kubernetes, ci-cd |
106
+ | Documentation | docs, readme, changelog, api-docs |
107
+ | Code Quality | review, lint, refactor, best-practices |
108
+ | Design | ui, ux, design-system, accessibility |
109
+ | Productivity | workflow, automation, git |
110
+
111
+ ## Tips for Effective Searches
112
+
113
+ 1. **Use specific keywords**: "react testing" is better than just "testing"
114
+ 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd"
115
+ 3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills`
116
+
117
+ ## When No Skills Are Found
118
+
119
+ If no relevant skills exist:
120
+
121
+ 1. Acknowledge that no existing skill was found
122
+ 2. Offer to help with the task directly using your general capabilities
123
+ 3. Suggest the user could create their own skill with `npx skills init`
124
+
125
+ Example:
126
+
127
+ ```
128
+ I searched for skills related to "xyz" but didn't find any matches.
129
+ I can still help you with this task directly! Would you like me to proceed?
130
+
131
+ If this is something you do often, you could create your own skill:
132
+ npx skills init my-xyz-skill
133
+ ```
@@ -247,7 +247,7 @@ class Skill {
247
247
  sessionId: framework?._currentSessionId || 'unknown',
248
248
  agent: null,
249
249
  framework: framework,
250
- cwd: process.cwd(), // 工作目录,用于路径解析
250
+ cwd: framework?.getCwd?.() ?? process.cwd(), // 工作目录,用于路径解析
251
251
  };
252
252
  // 支持 argumentParser 先解析参数
253
253
  let parsedArgs = toolArgs.command || '';
@@ -520,8 +520,9 @@ class SkillManagerPlugin extends Plugin {
520
520
  let totalLoaded = 0;
521
521
 
522
522
  // 1. 扫描 skillsDirs
523
+ const baseCwd = this._framework?.getCwd?.() ?? process.cwd();
523
524
  for (const skillsDir of this._skillsDirs) {
524
- const resolvedDir = path.resolve(process.cwd(), skillsDir);
525
+ const resolvedDir = path.resolve(baseCwd, skillsDir);
525
526
 
526
527
  if (!fs.existsSync(resolvedDir)) {
527
528
  continue;
@@ -881,7 +881,8 @@ class WorkflowPlugin extends Plugin {
881
881
  * 加载目录中的工作流定义
882
882
  */
883
883
  _loadWorkflows() {
884
- const dir = path.resolve(process.cwd(), this._workflowsDir);
884
+ const cwd = this._framework?.getCwd?.() ?? process.cwd();
885
+ const dir = path.resolve(cwd, this._workflowsDir);
885
886
  if (!fs.existsSync(dir)) {
886
887
  fs.mkdirSync(dir, { recursive: true });
887
888
  // log.info(` Created workflows directory: ${dir}`);
@@ -475,7 +475,7 @@ class AgentChatHandler extends EventEmitter {
475
475
  if (!this._aiClient) {
476
476
  throw new Error('AI client not configured.');
477
477
  }
478
- this._validateToolCalls(messages);
478
+
479
479
  const systemPrompt = framework.getSystemPrompt();
480
480
  //await fs.promises.writeFile(`.${sessionId}_systemPrompt.md`, systemPrompt); // 调试用:保存系统提示词
481
481
  const tools = this._getAITools(aiTool);
@@ -580,7 +580,7 @@ class AgentChatHandler extends EventEmitter {
580
580
  usage: usageData,
581
581
  });
582
582
  }
583
- this._validateToolCalls(messages);
583
+
584
584
  // yield usage 数据,让 UI 层能直接获取
585
585
  yield {
586
586
  type: 'usage',
@@ -658,7 +658,7 @@ class AgentChatHandler extends EventEmitter {
658
658
  if (this._thinkingMode) {
659
659
  delete apiOptions.temperature;
660
660
  }
661
- this._validateToolCalls(messages);
661
+
662
662
  const agent = new ToolLoopAgent({
663
663
  model: this._aiClient,
664
664
  instructions: systemPrompt,
@@ -699,7 +699,7 @@ class AgentChatHandler extends EventEmitter {
699
699
  messages.push(...result.response.messages);
700
700
  const userMsg = messages[messages.length - result.response.messages.length - 1];
701
701
  this.emit('message', { content: result.text, sessionId: sessionId, userMessage: userMsg });
702
- this._validateToolCalls(messages);
702
+
703
703
  return {
704
704
  success: true,
705
705
  message: cleanResponse(result.text || ''),
package/src/core/agent.js CHANGED
@@ -172,7 +172,7 @@ class Agent extends EventEmitter {
172
172
  switch (key) {
173
173
  case 'WORK_DIR':
174
174
  case 'CWD':
175
- return process.cwd();
175
+ return this.framework?.getCwd?.() ?? process.cwd();
176
176
  case 'HOME_DIR':
177
177
  return os.homedir();
178
178
  case 'HOST_NAME':
@@ -122,6 +122,9 @@ const SYSTEM_PLUGINS = new Set([
122
122
  /** Agent 配置目录名 */
123
123
  const AGENT_DIR = '.foliko';
124
124
 
125
+ /** 用户主目录下 Agent 配置目录名 */
126
+ const HOME_AGENT_DIR_NAME = '.foliko';
127
+
125
128
  // ============================================================================
126
129
  // Session 存储
127
130
  // ============================================================================
@@ -186,6 +189,7 @@ module.exports = {
186
189
  DEFAULT_PLUGIN_PRIORITY,
187
190
  SYSTEM_PLUGINS,
188
191
  AGENT_DIR,
192
+ HOME_AGENT_DIR_NAME,
189
193
 
190
194
  // Storage
191
195
  DEFAULT_SESSION_STORAGE_TYPE,